Enable out-of-line definitions of C++ constructors and destructors

llvm-svn: 60947
This commit is contained in:
Douglas Gregor 2008-12-12 08:25:50 +00:00
parent e4bcb8e2dd
commit 4287b37389
5 changed files with 65 additions and 17 deletions

View File

@ -178,10 +178,12 @@ public:
IdentifierNamespace getIdentifierNamespace() const { IdentifierNamespace getIdentifierNamespace() const {
switch (DeclKind) { 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 ImplicitParam:
case Typedef: case Typedef:
case Function:
case Var: case Var:
case ParmVar: case ParmVar:
case EnumConstant: case EnumConstant:

View File

@ -246,6 +246,24 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
} else if (LookupCtx) { } else if (LookupCtx) {
assert(getLangOptions().CPlusPlus && "No qualified name lookup in C"); 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. // Perform qualified name lookup into the LookupCtx.
// FIXME: Will need to look into base classes and such. // FIXME: Will need to look into base classes and such.
DeclContext::lookup_const_iterator I, E; 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 // after the point of declaration in a namespace that encloses the
// declarations namespace. // 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) { if (PrevDecl == 0) {
// No previous declaration in the qualifying scope. // No previous declaration in the qualifying scope.
Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member) Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)

View File

@ -1104,16 +1104,16 @@ Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) {
// Check default arguments on the constructor // Check default arguments on the constructor
CheckCXXDefaultArguments(ConDecl); CheckCXXDefaultArguments(ConDecl);
CXXRecordDecl *ClassDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); // Set the lexical context of this constructor
if (!ClassDecl) { ConDecl->setLexicalDeclContext(CurContext);
ConDecl->setInvalidDecl();
return ConDecl; CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ConDecl->getDeclContext());
}
// Make sure this constructor is an overload of the existing // Make sure this constructor is an overload of the existing
// constructors. // constructors.
OverloadedFunctionDecl::function_iterator MatchedDecl; 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) Diag(ConDecl->getLocation(), diag::err_constructor_redeclared)
<< SourceRange(ConDecl->getLocation()); << SourceRange(ConDecl->getLocation());
Diag((*MatchedDecl)->getLocation(), diag::note_previous_declaration) Diag((*MatchedDecl)->getLocation(), diag::note_previous_declaration)
@ -1122,7 +1122,6 @@ Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) {
return ConDecl; return ConDecl;
} }
// C++ [class.copy]p3: // C++ [class.copy]p3:
// A declaration of a constructor for a class X is ill-formed if // A declaration of a constructor for a class X is ill-formed if
// its first parameter is of type (optionally cv-qualified) X and // 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) { Sema::DeclTy *Sema::ActOnDestructorDeclarator(CXXDestructorDecl *Destructor) {
assert(Destructor && "Expected to receive a destructor declaration"); 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. // Make sure we aren't redeclaring the destructor.
if (CXXDestructorDecl *PrevDestructor = ClassDecl->getDestructor()) { if (CXXDestructorDecl *PrevDestructor = ClassDecl->getDestructor()) {
Diag(Destructor->getLocation(), diag::err_destructor_redeclared); if (CurContext == PrevDestructor->getLexicalDeclContext()) {
Diag(PrevDestructor->getLocation(), Diag(Destructor->getLocation(), diag::err_destructor_redeclared);
PrevDestructor->isThisDeclarationADefinition() ? Diag(PrevDestructor->getLocation(),
diag::note_previous_definition PrevDestructor->isThisDeclarationADefinition() ?
: diag::note_previous_declaration); diag::note_previous_definition
Destructor->setInvalidDecl(); : diag::note_previous_declaration);
Destructor->setInvalidDecl();
}
// FIXME: Just drop the definition (for now).
return Destructor; return Destructor;
} }
@ -1179,7 +1185,10 @@ Sema::DeclTy *Sema::ActOnDestructorDeclarator(CXXDestructorDecl *Destructor) {
Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { Sema::DeclTy *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
assert(Conversion && "Expected to receive a conversion function declaration"); 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. // Make sure we aren't redeclaring the conversion function.
QualType ConvType = Context.getCanonicalType(Conversion->getConversionType()); QualType ConvType = Context.getCanonicalType(Conversion->getConversionType());

View File

@ -18,3 +18,6 @@ class Foo {
int Foo(int, int); // expected-error{{constructor cannot have a return type}} int Foo(int, int); // expected-error{{constructor cannot have a return type}}
}; };
Foo::Foo(const Foo&) { }

View File

@ -38,3 +38,10 @@ struct F {
~; // expected-error {{expected class name}} ~; // expected-error {{expected class name}}
~undef(); // expected-error {{expected class name}} ~undef(); // expected-error {{expected class name}}
~F(){} // expected-error {{destructor must be a non-static member function}} ~F(){} // expected-error {{destructor must be a non-static member function}}
struct G {
~G();
};
G::~G() { }