diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-12-12 08:25:50 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-12-12 08:25:50 +0000 |
commit | 9d35097bc0fefb2f77638be513cac72d1c09d840 (patch) | |
tree | ad5b69bcbb3f896a7e7a52ded70a4e36ffae405f | |
parent | 5d46315ca3cbbfe0d0f5f65520b618fb05dd4446 (diff) |
Enable out-of-line definitions of C++ constructors and destructors
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60947 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclBase.h | 6 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 39 | ||||
-rw-r--r-- | test/SemaCXX/constructor.cpp | 3 | ||||
-rw-r--r-- | test/SemaCXX/destructor.cpp | 7 |
5 files changed, 65 insertions, 17 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index badf6345ec..04d0ce530c 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -178,10 +178,12 @@ public: IdentifierNamespace getIdentifierNamespace() const { switch (DeclKind) { - default: assert(0 && "Unknown decl kind!"); + default: + if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast) + return IDNS_Ordinary; + assert(0 && "Unknown decl kind!"); case ImplicitParam: case Typedef: - case Function: case Var: case ParmVar: case EnumConstant: diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 29d636fabd..2c5e46afa0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -246,6 +246,24 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S, } else if (LookupCtx) { assert(getLangOptions().CPlusPlus && "No qualified name lookup in C"); + switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(LookupCtx)) + return const_cast<CXXRecordDecl *>(Record)->getConstructors(); + else + return 0; + + case DeclarationName::CXXDestructorName: + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(LookupCtx)) + return Record->getDestructor(); + else + return 0; + + default: + // Normal name lookup. + break; + } + // Perform qualified name lookup into the LookupCtx. // FIXME: Will need to look into base classes and such. DeclContext::lookup_const_iterator I, E; @@ -932,6 +950,15 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // after the point of declaration in a namespace that encloses the // declarations namespace. // + // FIXME: We need to perform this check later, once we know that + // we've actually found a redeclaration. Otherwise, just the fact + // that there is some entity with the same name will suppress this + // diagnostic, e.g., we fail to diagnose: + // class X { + // void f(); + // }; + // + // void X::f(int) { } // ill-formed, but we don't complain. if (PrevDecl == 0) { // No previous declaration in the qualifying scope. Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1b189f87fc..40fcecfb1c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1104,16 +1104,16 @@ Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) { // Check default arguments on the constructor CheckCXXDefaultArguments(ConDecl); - CXXRecordDecl *ClassDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); - if (!ClassDecl) { - ConDecl->setInvalidDecl(); - return ConDecl; - } + // Set the lexical context of this constructor + ConDecl->setLexicalDeclContext(CurContext); + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ConDecl->getDeclContext()); // Make sure this constructor is an overload of the existing // constructors. OverloadedFunctionDecl::function_iterator MatchedDecl; - if (!IsOverload(ConDecl, ClassDecl->getConstructors(), MatchedDecl)) { + if (!IsOverload(ConDecl, ClassDecl->getConstructors(), MatchedDecl) && + CurContext == (*MatchedDecl)->getLexicalDeclContext()) { Diag(ConDecl->getLocation(), diag::err_constructor_redeclared) << SourceRange(ConDecl->getLocation()); Diag((*MatchedDecl)->getLocation(), diag::note_previous_declaration) @@ -1122,7 +1122,6 @@ Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) { return ConDecl; } - // C++ [class.copy]p3: // A declaration of a constructor for a class X is ill-formed if // its first parameter is of type (optionally cv-qualified) X and @@ -1155,16 +1154,23 @@ Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) { Sema::DeclTy *Sema::ActOnDestructorDeclarator(CXXDestructorDecl *Destructor) { assert(Destructor && "Expected to receive a destructor declaration"); - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CurContext); + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext()); + + // Set the lexical context of this destructor + Destructor->setLexicalDeclContext(CurContext); // Make sure we aren't redeclaring the destructor. if (CXXDestructorDecl *PrevDestructor = ClassDecl->getDestructor()) { - Diag(Destructor->getLocation(), diag::err_destructor_redeclared); - Diag(PrevDestructor->getLocation(), - PrevDestructor->isThisDeclarationADefinition() ? - diag::note_previous_definition - : diag::note_previous_declaration); - Destructor->setInvalidDecl(); + if (CurContext == PrevDestructor->getLexicalDeclContext()) { + Diag(Destructor->getLocation(), diag::err_destructor_redeclared); + Diag(PrevDestructor->getLocation(), + PrevDestructor->isThisDeclarationADefinition() ? + diag::note_previous_definition + : diag::note_previous_declaration); + Destructor->setInvalidDecl(); + } + + // FIXME: Just drop the definition (for now). return Destructor; } @@ -1179,7 +1185,10 @@ Sema::DeclTy *Sema::ActOnDestructorDeclarator(CXXDestructorDecl *Destructor) { Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { assert(Conversion && "Expected to receive a conversion function declaration"); - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CurContext); + // Set the lexical context of this conversion function + Conversion->setLexicalDeclContext(CurContext); + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext()); // Make sure we aren't redeclaring the conversion function. QualType ConvType = Context.getCanonicalType(Conversion->getConversionType()); diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp index fc398e28ba..4c4d67fa87 100644 --- a/test/SemaCXX/constructor.cpp +++ b/test/SemaCXX/constructor.cpp @@ -18,3 +18,6 @@ class Foo { int Foo(int, int); // expected-error{{constructor cannot have a return type}} }; + +Foo::Foo(const Foo&) { } + diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp index 7f791daf5e..2134f4ec5c 100644 --- a/test/SemaCXX/destructor.cpp +++ b/test/SemaCXX/destructor.cpp @@ -38,3 +38,10 @@ struct F { ~; // expected-error {{expected class name}} ~undef(); // expected-error {{expected class name}} ~F(){} // expected-error {{destructor must be a non-static member function}} + +struct G { + ~G(); +}; + +G::~G() { } + |