diff options
-rw-r--r-- | include/clang/AST/DeclBase.h | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 39 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 36 | ||||
-rw-r--r-- | test/SemaCXX/destructor.cpp | 3 |
5 files changed, 53 insertions, 31 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index c44515eaa4..7670798d13 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -310,6 +310,10 @@ public: } } + bool isCXXRecord() const { + return DeclKind == Decl::CXXRecord; + } + const ScopedDecl *getDeclChain() const { return DeclChain; } ScopedDecl *getDeclChain() { return DeclChain; } void setDeclChain(ScopedDecl *D) { DeclChain = D; } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index b3b6e81f9f..726a6bd9ea 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -691,6 +691,8 @@ DIAG(err_constructor_byvalue_arg, ERROR, "copy constructor must pass its first argument by reference") // C++ destructors +DIAG(err_destructor_not_member, ERROR, + "destructor must be a non-static member function") DIAG(err_destructor_cannot_be, ERROR, "destructor cannot be declared '%0'") DIAG(err_invalid_qualified_destructor, ERROR, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 58cc9e2c6b..2b18be02a3 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1355,6 +1355,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) { /// conversion-function-id [TODO] /// '~' class-name /// template-id [TODO] +/// void Parser::ParseDirectDeclarator(Declarator &D) { // Parse the first direct-declarator seen. if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { @@ -1362,31 +1363,35 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // Determine whether this identifier is a C++ constructor name or // a normal identifier. if (getLang().CPlusPlus && - CurScope->isCXXClassScope() && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope)) D.SetConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope), Tok.getIdentifierInfo(), Tok.getLocation()); else D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); - } else if (getLang().CPlusPlus && Tok.is(tok::tilde) && - CurScope->isCXXClassScope() && D.mayHaveIdentifier()) { + } else if (getLang().CPlusPlus && + Tok.is(tok::tilde) && D.mayHaveIdentifier()) { // This should be a C++ destructor. SourceLocation TildeLoc = ConsumeToken(); - - // Use the next identifier and "~" to form a name for the - // destructor. This is useful both for diagnostics and for - // correctness of the parser, since we use presence/absence of the - // identifier to determine what we parsed. - // FIXME: We could end up with a template-id here, once we parse - // templates, and will have to do something different to form the - // name of the destructor. - assert(Tok.is(tok::identifier) && "Expected identifier"); - IdentifierInfo *II = Tok.getIdentifierInfo(); - II = &PP.getIdentifierTable().get(std::string("~") + II->getName()); - - if (TypeTy *Type = ParseClassName()) - D.SetDestructor(Type, II, TildeLoc); + if (Tok.is(tok::identifier)) { + // Use the next identifier and "~" to form a name for the + // destructor. This is useful both for diagnostics and for + // correctness of the parser, since we use presence/absence of the + // identifier to determine what we parsed. + // FIXME: We could end up with a template-id here, once we parse + // templates, and will have to do something different to form the + // name of the destructor. + IdentifierInfo *II = Tok.getIdentifierInfo(); + II = &PP.getIdentifierTable().get(std::string("~") + II->getName()); + + if (TypeTy *Type = ParseClassName()) + D.SetDestructor(Type, II, TildeLoc); + else + D.SetIdentifier(0, TildeLoc); + } else { + Diag(Tok, diag::err_expected_class_name); + D.SetIdentifier(0, TildeLoc); + } } else if (Tok.is(tok::kw_operator)) { SourceLocation OperatorLoc = Tok.getLocation(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 12a4b08e91..18d77c4a18 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -811,7 +811,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { FunctionDecl *NewFD; if (D.getKind() == Declarator::DK_Constructor) { // This is a C++ constructor declaration. - assert(D.getContext() == Declarator::MemberContext && + assert(CurContext->isCXXRecord() && "Constructors can only be declared in a member context"); bool isInvalidDecl = CheckConstructorDeclarator(D, R, SC); @@ -827,21 +827,29 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { NewFD->setInvalidDecl(); } else if (D.getKind() == Declarator::DK_Destructor) { // This is a C++ destructor declaration. - assert(D.getContext() == Declarator::MemberContext && - "Destructor can only be declared in a member context"); + if (CurContext->isCXXRecord()) { + bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC); - bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC); - - NewFD = CXXDestructorDecl::Create(Context, - cast<CXXRecordDecl>(CurContext), - D.getIdentifierLoc(), II, R, - isInline, - /*isImplicitlyDeclared=*/false); + NewFD = CXXDestructorDecl::Create(Context, + cast<CXXRecordDecl>(CurContext), + D.getIdentifierLoc(), II, R, + isInline, + /*isImplicitlyDeclared=*/false); - if (isInvalidDecl) + if (isInvalidDecl) + NewFD->setInvalidDecl(); + } else { + Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); + // Create a FunctionDecl to satisfy the function definition parsing + // code path. + NewFD = FunctionDecl::Create(Context, CurContext, D.getIdentifierLoc(), + II, R, SC, isInline, LastDeclarator, + // FIXME: Move to DeclGroup... + D.getDeclSpec().getSourceRange().getBegin()); NewFD->setInvalidDecl(); + } } else if (D.getKind() == Declarator::DK_Conversion) { - if (D.getContext() != Declarator::MemberContext) { + if (!CurContext->isCXXRecord()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member); return 0; @@ -856,7 +864,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { if (isInvalidDecl) NewFD->setInvalidDecl(); } - } else if (D.getContext() == Declarator::MemberContext) { + } else if (CurContext->isCXXRecord()) { // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext), D.getIdentifierLoc(), II, R, @@ -1037,7 +1045,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { case DeclSpec::SCS_register: SC = VarDecl::Register; break; case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; } - if (D.getContext() == Declarator::MemberContext) { + if (CurContext->isCXXRecord()) { assert(SC == VarDecl::Static && "Invalid storage class for member!"); // This is a static data member for a C++ class. NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(CurContext), diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp index 1eec0d5f00..cb5bd23a9e 100644 --- a/test/SemaCXX/destructor.cpp +++ b/test/SemaCXX/destructor.cpp @@ -35,3 +35,6 @@ struct F { ~F(); // expected-error{{destructor cannot be redeclared}} }; +~; // expected-error {{expected class name}} +~undef(); // expected-error {{expected class name}} +~F(){} // expected-error {{destructor must be a non-static member function}} |