From: Nico Weber Date: Fri, 30 Jan 2015 16:53:11 +0000 (+0000) Subject: Follow-up to r217302 and r227555: Don't crash on inline ~A::A() if A is an int. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d2a265184cd366af3349b70d1e9d110dc3b7834e;p=clang Follow-up to r217302 and r227555: Don't crash on inline ~A::A() if A is an int. Even with r227555, this still crashed: struct S { int A; ~A::A() {} }; That's because ParseOptionalCXXScopeSpecifier()'s call to ActOnCXXNestedNameSpecifier() doesn't mark the scope spec as invalid if sema thought it's a good idea to fixit-correct "::" to ":". For the diagnostic improvement done in r217302, we never want :: to be interpreted as :, so fix this by setting ColonSacred to false temporarily. Found by SLi's bot. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@227581 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index a753b0ff27..8faec51667 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2509,7 +2509,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // If the user wrote ~T::T, correct it to T::~T. DeclaratorScopeObj DeclScopeObj(*this, SS); - if (!TemplateSpecified && NextToken().is(tok::coloncolon)) { + if (!TemplateSpecified && //!ColonIsSacred && + NextToken().is(tok::coloncolon)) { + // Don't let ParseOptionalCXXScopeSpecifier() "correct" + // `int A; struct { ~A::A(); };` to `int A; struct { ~A:A(); };`, + // it will confuse this recovery logic. + ColonProtectionRAIIObject ColonRAII(*this, false); + if (SS.isSet()) { AnnotateScopeToken(SS, /*NewAnnotation*/true); SS.clear(); diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp index 7c5c4ecf58..077bd6f02c 100644 --- a/test/Parser/cxx-class.cpp +++ b/test/Parser/cxx-class.cpp @@ -159,6 +159,21 @@ namespace DtorErrors { ~D::D() throw(X) {} // expected-error {{'~' in destructor name should be after nested name specifier}} ~Undeclared::Undeclared() {} // expected-error {{use of undeclared identifier 'Undeclared'}} expected-error {{'~' in destructor name should be after nested name specifier}} + + struct S { + // For another struct's destructor, emit the same diagnostic like for + // A::~A() in addition to the "~ in the wrong place" one. + ~A::A() {} // expected-error {{'~' in destructor name should be after nested name specifier}} expected-error {{non-friend class member '~A' cannot have a qualified name}} + A::~A() {} // expected-error {{non-friend class member '~A' cannot have a qualified name}} + + // An inline destructor with a redundant class name should also get the + // same diagnostic as S::~S. + ~S::S() {} // expected-error {{'~' in destructor name should be after nested name specifier}} expected-error {{extra qualification on member '~S'}} + + // This just shouldn't crash. + int I; // expected-note {{declared here}} + ~I::I() {} // expected-error {{'I' is not a class, namespace, or enumeration}} expected-error {{'~' in destructor name should be after nested name specifier}} + }; } namespace BadFriend {