From 7d14568fc6ac279db206c3950cb7a460064e8038 Mon Sep 17 00:00:00 2001 From: Richard Smith <richard-llvm@metafoo.co.uk> Date: Sat, 6 Sep 2014 02:06:12 +0000 Subject: [PATCH] Add error, recovery and fixit for "~A::A() {...}". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217302 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 2 ++ lib/Parse/ParseExprCXX.cpp | 23 +++++++++++++++++++-- test/FixIt/fixit.cpp | 7 +++++++ test/Parser/cxx-class.cpp | 14 +++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 0dcfb5642ba..ff3e9a76bb6 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -492,6 +492,8 @@ def err_constructor_bad_name : Error< "missing return type for function %0; did you mean the constructor name %1?">; def err_destructor_tilde_identifier : Error< "expected a class name after '~' to name a destructor">; +def err_destructor_tilde_scope : Error< + "'~' in destructor name should be after nested name specifier">; def err_destructor_template_id : Error< "destructor name %0 does not refer to a template">; def err_default_arg_unparsed : Error< diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 27109aba5b7..cf0e4ce5c0c 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2452,10 +2452,29 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, return true; } + // If the user wrote ~T::T, correct it to T::~T. + if (!TemplateSpecified && NextToken().is(tok::coloncolon)) { + if (SS.isSet()) { + AnnotateScopeToken(SS, /*NewAnnotation*/true); + SS.clear(); + } + if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext)) + return true; + if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon)) { + Diag(TildeLoc, diag::err_destructor_tilde_scope); + return true; + } + + // Recover as if the tilde had been written before the identifier. + Diag(TildeLoc, diag::err_destructor_tilde_scope) + << FixItHint::CreateRemoval(TildeLoc) + << FixItHint::CreateInsertion(Tok.getLocation(), "~"); + } + // Parse the class-name (or template-name in a simple-template-id). IdentifierInfo *ClassName = Tok.getIdentifierInfo(); SourceLocation ClassNameLoc = ConsumeToken(); - + if (TemplateSpecified || Tok.is(tok::less)) { Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc); return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, @@ -2463,7 +2482,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, EnteringContext, ObjectType, Result, TemplateSpecified); } - + // Note that this is a destructor name. ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName, ClassNameLoc, getCurScope(), diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp index f2649385656..6c328c52180 100644 --- a/test/FixIt/fixit.cpp +++ b/test/FixIt/fixit.cpp @@ -308,6 +308,13 @@ namespace dtor_fixit { ~bar() { } // expected-error {{expected the class name after '~' to name a destructor}} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:9}:"foo" }; + + class bar { + ~bar(); + }; + ~bar::bar() {} // expected-error {{'~' in destructor name should be after nested name specifier}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:4}:"" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:9-[[@LINE-2]]:9}:"~" } namespace PR5066 { diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp index 69776f4d422..7e820f17aad 100644 --- a/test/Parser/cxx-class.cpp +++ b/test/Parser/cxx-class.cpp @@ -139,6 +139,20 @@ namespace CtorErrors { }; } +namespace DtorErrors { + struct A { ~A(); } a; + ~A::A() {} // expected-error {{'~' in destructor name should be after nested name specifier}} expected-note {{previous}} + A::~A() {} // expected-error {{redefinition}} + + struct B { ~B(); } *b; + DtorErrors::~B::B() {} // expected-error {{'~' in destructor name should be after nested name specifier}} + + void f() { + a.~A::A(); // expected-error {{'~' in destructor name should be after nested name specifier}} + b->~DtorErrors::~B::B(); // expected-error {{'~' in destructor name should be after nested name specifier}} + } +} + namespace BadFriend { struct A { friend int : 3; // expected-error {{friends can only be classes or functions}} -- GitLab