aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-12-15 21:24:18 +0000
committerDouglas Gregor <dgregor@apple.com>2008-12-15 21:24:18 +0000
commit9e7d9de3ef538c1473248238b76a6d7b16f5f684 (patch)
tree272828d09e3dd9dfbcbd05538158ee64fa7312fe
parent9fed5169477cfca54e97069bca035f6453b1ab84 (diff)
Place constructors and destructors into the DeclContext of the class,
just like all other members, and remove the special variables in CXXRecordDecl to store them. This eliminates a lot of special-case code for constructors and destructors, including ActOnConstructor/ActOnDeclarator and special lookup rules in LookupDecl. The result is far more uniform and manageable. Diagnose the redeclaration of member functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61048 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclCXX.h45
-rw-r--r--include/clang/Basic/DiagnosticKinds.def1
-rw-r--r--lib/AST/DeclCXX.cpp46
-rw-r--r--lib/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaDecl.cpp121
-rw-r--r--lib/Sema/SemaDeclCXX.cpp152
-rw-r--r--lib/Sema/SemaOverload.cpp24
-rw-r--r--test/SemaCXX/constructor.cpp6
-rw-r--r--test/SemaCXX/overload-decl.cpp6
9 files changed, 190 insertions, 213 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 9e7e0790b7..d840c68de5 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -260,9 +260,13 @@ class CXXRecordDecl : public RecordDecl {
bool UserDeclaredConstructor : 1;
/// UserDeclaredCopyConstructor - True when this class has a
- /// user-defined copy constructor.
+ /// user-declared copy constructor.
bool UserDeclaredCopyConstructor : 1;
+ /// UserDeclaredDestructor - True when this class has a
+ /// user-declared destructor.
+ bool UserDeclaredDestructor : 1;
+
/// Aggregate - True when this class is an aggregate.
bool Aggregate : 1;
@@ -277,14 +281,6 @@ class CXXRecordDecl : public RecordDecl {
/// NumBases - The number of base class specifiers in Bases.
unsigned NumBases;
- /// Constructors - Overload set containing the constructors of this
- /// C++ class. Each of the entries in this overload set is a
- /// CXXConstructorDecl.
- OverloadedFunctionDecl Constructors;
-
- // Destructor - The destructor of this C++ class.
- CXXDestructorDecl *Destructor;
-
/// Conversions - Overload set containing the conversion functions
/// of this C++ class (but not its inherited conversion
/// functions). Each of the entries in this overload set is a
@@ -321,20 +317,14 @@ public:
base_class_iterator bases_end() { return Bases + NumBases; }
base_class_const_iterator bases_end() const { return Bases + NumBases; }
- /// getConstructors - Retrieve the overload set containing all of
- /// the constructors of this class.
- OverloadedFunctionDecl *getConstructors() { return &Constructors; }
-
- /// getConstructors - Retrieve the overload set containing all of
- /// the constructors of this class.
- const OverloadedFunctionDecl *getConstructors() const { return &Constructors; }
-
/// hasConstCopyConstructor - Determines whether this class has a
/// copy constructor that accepts a const-qualified argument.
bool hasConstCopyConstructor(ASTContext &Context) const;
- /// addConstructor - Add another constructor to the list of constructors.
- void addConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
+ /// addedConstructor - Notify the class that another constructor has
+ /// been added. This routine helps maintain information about the
+ /// class based on which constructors have been added.
+ void addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
/// hasUserDeclaredConstructor - Whether this class has any
/// user-declared constructors. When true, a default constructor
@@ -348,13 +338,16 @@ public:
return UserDeclaredCopyConstructor;
}
- /// getDestructor - Retrieve the destructor for this class.
- CXXDestructorDecl *getDestructor() const { return Destructor; }
+ /// hasUserDeclaredDestructor - Whether this class has a
+ /// user-declared destructor. When false, a destructor will be
+ /// implicitly declared.
+ bool hasUserDeclaredDestructor() const { return UserDeclaredDestructor; }
- /// setDestructor - Set the destructor for this class.
- void setDestructor(CXXDestructorDecl *Destructor) {
- assert(!this->Destructor && "Already have a destructor!");
- this->Destructor = Destructor;
+ /// setUserDeclaredDestructor - Set whether this class has a
+ /// user-declared destructor. If not set by the time the class is
+ /// fully defined, a destructor will be implicitly declared.
+ void setUserDeclaredDestructor(bool UCD = true) {
+ UserDeclaredDestructor = UCD;
}
/// getConversions - Retrieve the overload set containing all of the
@@ -402,8 +395,6 @@ public:
return static_cast<CXXRecordDecl *>(const_cast<DeclContext*>(DC));
}
- virtual void Destroy(ASTContext& C);
-
protected:
/// EmitImpl - Serialize this CXXRecordDecl. Called by Decl::Emit.
// FIXME: Implement this.
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index a70f70eb03..fba04101cf 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -1169,6 +1169,7 @@ DIAG(err_typecheck_incomplete_tag, ERROR,
"incomplete definition of type %0")
DIAG(err_typecheck_no_member, ERROR,
"no member named %0")
+DIAG(err_member_redeclared, ERROR, "class member cannot be redeclared")
DIAG(err_typecheck_ivar_variable_size, ERROR,
"instance variables must have a constant size")
// FIXME: Improve with %select
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 3eaf301d7a..12d715e068 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -40,9 +40,8 @@ CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id)
: RecordDecl(CXXRecord, TK, DC, L, Id),
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
- Aggregate(true), Polymorphic(false), Bases(0), NumBases(0),
- Constructors(DC, DeclarationName()),
- Destructor(0),
+ UserDeclaredDestructor(false), Aggregate(true), Polymorphic(false),
+ Bases(0), NumBases(0),
Conversions(DC, DeclarationName()) { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
@@ -58,18 +57,6 @@ CXXRecordDecl::~CXXRecordDecl() {
delete [] Bases;
}
-void CXXRecordDecl::Destroy(ASTContext &C) {
- for (OverloadedFunctionDecl::function_iterator func
- = Constructors.function_begin();
- func != Constructors.function_end(); ++func)
- (*func)->Destroy(C);
-
- if (isDefinition())
- Destructor->Destroy(C);
-
- RecordDecl::Destroy(C);
-}
-
void
CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
unsigned NumBases) {
@@ -88,20 +75,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
}
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
- for (OverloadedFunctionDecl::function_const_iterator Con
- = Constructors.function_begin();
- Con != Constructors.function_end(); ++Con) {
- unsigned TypeQuals;
+ QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType));
+ unsigned TypeQuals;
+ DeclContext::lookup_const_result Lookup
+ = this->lookup(Context, ConstructorName);
+ if (Lookup.first == Lookup.second)
+ return false;
+ else if (OverloadedFunctionDecl *Constructors
+ = dyn_cast<OverloadedFunctionDecl>(*Lookup.first)) {
+ for (OverloadedFunctionDecl::function_const_iterator Con
+ = Constructors->function_begin();
+ Con != Constructors->function_end(); ++Con) {
if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) &&
(TypeQuals & QualType::Const != 0))
return true;
+ }
+ } else if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(*Lookup.first)) {
+ return Constructor->isCopyConstructor(Context, TypeQuals) &&
+ (TypeQuals & QualType::Const != 0);
}
return false;
}
void
-CXXRecordDecl::addConstructor(ASTContext &Context,
- CXXConstructorDecl *ConDecl) {
+CXXRecordDecl::addedConstructor(ASTContext &Context,
+ CXXConstructorDecl *ConDecl) {
if (!ConDecl->isImplicitlyDeclared()) {
// Note that we have a user-declared constructor.
UserDeclaredConstructor = true;
@@ -116,8 +118,6 @@ CXXRecordDecl::addConstructor(ASTContext &Context,
if (ConDecl->isCopyConstructor(Context))
UserDeclaredCopyConstructor = true;
}
-
- Constructors.addOverload(ConDecl);
}
void CXXRecordDecl::addConversionFunction(ASTContext &Context,
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 0f1c99f702..528611b3a9 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -963,8 +963,6 @@ public:
FunctionDecl::StorageClass& SC);
bool CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
- DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *Constructor);
- DeclTy *ActOnDestructorDeclarator(CXXDestructorDecl *Destructor);
DeclTy *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index fbf89ae311..577cc7a97e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -138,20 +138,20 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
FD->getDeclName());
Ovl->addOverload(cast<FunctionDecl>(Prev));
- // If there is an ame binding for the existing FunctionDecl,
- // remove it.
- for (IdentifierResolver::iterator I
- = IdResolver.begin(FD->getDeclName(), FD->getDeclContext(),
- false/*LookInParentCtx*/),
- E = IdResolver.end(); I != E; ++I) {
- if (*I == Prev) {
- IdResolver.RemoveDecl(*I);
- S->RemoveDecl(*I);
- break;
- }
- }
+ // If there is a name binding for the existing FunctionDecl,
+ // remove it.
+ for (IdentifierResolver::iterator I
+ = IdResolver.begin(FD->getDeclName(), FD->getDeclContext(),
+ false/*LookInParentCtx*/),
+ E = IdResolver.end(); I != E; ++I) {
+ if (*I == Prev) {
+ IdResolver.RemoveDecl(*I);
+ S->RemoveDecl(*I);
+ break;
+ }
+ }
- // Add the name binding for the OverloadedFunctionDecl.
+ // Add the name binding for the OverloadedFunctionDecl.
IdResolver.AddDecl(Ovl);
// Update the context with the newly-created overloaded
@@ -246,24 +246,6 @@ 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;
@@ -565,6 +547,26 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
Diag(Old->getLocation(), PrevDiag);
return New;
}
+
+ // C++ [class.mem]p1:
+ // [...] A member shall not be declared twice in the
+ // member-specification, except that a nested class or member
+ // class template can be declared and then later defined.
+ if (OldMethod->getLexicalDeclContext() ==
+ NewMethod->getLexicalDeclContext()) {
+ unsigned NewDiag;
+ if (isa<CXXConstructorDecl>(OldMethod))
+ NewDiag = diag::err_constructor_redeclared;
+ else if (isa<CXXDestructorDecl>(NewMethod))
+ NewDiag = diag::err_destructor_redeclared;
+ else if (isa<CXXConversionDecl>(NewMethod))
+ NewDiag = diag::err_conv_function_redeclared;
+ else
+ NewDiag = diag::err_member_redeclared;
+
+ Diag(New->getLocation(), NewDiag);
+ Diag(Old->getLocation(), PrevDiag);
+ }
}
// (C++98 8.3.5p3):
@@ -1117,6 +1119,11 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
// Handle attributes.
ProcessDeclAttributes(NewFD, D);
+ // Set the lexical context. If the declarator has a C++
+ // scope specifier, the lexical context will be different
+ // from the semantic context.
+ NewFD->setLexicalDeclContext(CurContext);
+
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
@@ -1189,18 +1196,33 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
}
}
- // C++ constructors and destructors are handled by separate
- // routines, since they don't require any declaration merging (C++
- // [class.mfct]p2) and they aren't ever pushed into scope, because
- // they can't be found by name lookup anyway (C++ [class.ctor]p2).
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
- return ActOnConstructorDeclarator(Constructor);
- else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
- return ActOnDestructorDeclarator(Destructor);
-
- // Extra checking for conversion functions, including recording
- // the conversion function in its class.
- if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DC);
+
+ // 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
+ // either there are no other parameters or else all other
+ // parameters have default arguments.
+ if ((Constructor->getNumParams() == 1) ||
+ (Constructor->getNumParams() > 1 &&
+ Constructor->getParamDecl(1)->getDefaultArg() != 0)) {
+ QualType ParamType = Constructor->getParamDecl(0)->getType();
+ QualType ClassTy = Context.getTagDeclType(ClassDecl);
+ if (Context.getCanonicalType(ParamType).getUnqualifiedType()
+ == ClassTy) {
+ Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)
+ << SourceRange(Constructor->getParamDecl(0)->getLocation());
+ Constructor->setInvalidDecl();
+ }
+ }
+
+ // Notify the class that we've added a constructor.
+ ClassDecl->addedConstructor(Context, Constructor);
+ }
+ else if (isa<CXXDestructorDecl>(NewFD))
+ cast<CXXRecordDecl>(NewFD->getParent())->setUserDeclaredDestructor(true);
+ else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
ActOnConversionDeclarator(Conversion);
// Extra checking for C++ overloaded operators (C++ [over.oper]).
@@ -1268,11 +1290,6 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
CheckCXXDefaultArguments(NewFD);
}
- // Set the lexical context. If the declarator has a C++
- // scope specifier, the lexical context will be different
- // from the semantic context.
- NewFD->setLexicalDeclContext(CurContext);
-
return NewFD;
}
}
@@ -1965,7 +1982,9 @@ void Sema::ActOnUninitializedDecl(DeclTy *dcl) {
// function return type, in the declaration of a class member
// within its class declaration (9.2), and where the extern
// specifier is explicitly used.
- if (Type->isReferenceType() && Var->getStorageClass() != VarDecl::Extern) {
+ if (Type->isReferenceType() &&
+ Var->getStorageClass() != VarDecl::Extern &&
+ Var->getStorageClass() != VarDecl::PrivateExtern) {
Diag(Var->getLocation(), diag::err_reference_var_requires_init)
<< Var->getDeclName()
<< SourceRange(Var->getLocation(), Var->getLocation());
@@ -1984,7 +2003,9 @@ void Sema::ActOnUninitializedDecl(DeclTy *dcl) {
QualType InitType = Type;
if (const ArrayType *Array = Context.getAsArrayType(Type))
InitType = Array->getElementType();
- if (InitType->isRecordType()) {
+ if (Var->getStorageClass() != VarDecl::Extern &&
+ Var->getStorageClass() != VarDecl::PrivateExtern &&
+ InitType->isRecordType()) {
const CXXConstructorDecl *Constructor
= PerformInitializationByConstructor(InitType, 0, 0,
Var->getLocation(),
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 1efb17408a..6f1683ee7f 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -744,7 +744,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
DefaultCon->setAccess(AS_public);
- ClassDecl->addConstructor(Context, DefaultCon);
+ ClassDecl->addDecl(Context, DefaultCon);
+
+ // Notify the class that we've added a constructor.
+ ClassDecl->addedConstructor(Context, DefaultCon);
}
if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
@@ -820,10 +823,27 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ArgType, VarDecl::None, 0, 0);
CopyConstructor->setParams(&FromParam, 1);
- ClassDecl->addConstructor(Context, CopyConstructor);
+ ClassDecl->addedConstructor(Context, CopyConstructor);
+ DeclContext::lookup_result Lookup = ClassDecl->lookup(Context, Name);
+ if (Lookup.first == Lookup.second
+ || (!isa<CXXConstructorDecl>(*Lookup.first) &&
+ !isa<OverloadedFunctionDecl>(*Lookup.first)))
+ ClassDecl->addDecl(Context, CopyConstructor);
+ else {
+ OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(*Lookup.first);
+ if (!Ovl) {
+ Ovl = OverloadedFunctionDecl::Create(Context, ClassDecl, Name);
+ Ovl->addOverload(cast<CXXConstructorDecl>(*Lookup.first));
+ ClassDecl->insert(Context, Ovl);
+ }
+
+ Ovl->addOverload(CopyConstructor);
+ ClassDecl->addDecl(Context, CopyConstructor, false);
+ }
}
- if (!ClassDecl->getDestructor()) {
+ if (!ClassDecl->hasUserDeclaredDestructor()) {
// C++ [class.dtor]p2:
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
@@ -838,7 +858,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
- ClassDecl->setDestructor(Destructor);
+ ClassDecl->addDecl(Context, Destructor);
}
// FIXME: Implicit copy assignment operator
@@ -1087,101 +1107,6 @@ bool Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
return isInvalid;
}
-/// ActOnConstructorDeclarator - Called by ActOnDeclarator to complete
-/// the declaration of the given C++ constructor ConDecl that was
-/// built from declarator D. This routine is responsible for checking
-/// that the newly-created constructor declaration is well-formed and
-/// for recording it in the C++ class. Example:
-///
-/// @code
-/// class X {
-/// X(); // X::X() will be the ConDecl.
-/// };
-/// @endcode
-Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) {
- assert(ConDecl && "Expected to receive a constructor declaration");
-
- // Check default arguments on the constructor
- CheckCXXDefaultArguments(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 (CurContext == (*MatchedDecl)->getLexicalDeclContext()) {
- Diag(ConDecl->getLocation(), diag::err_constructor_redeclared)
- << SourceRange(ConDecl->getLocation());
- Diag((*MatchedDecl)->getLocation(), diag::note_previous_declaration)
- << SourceRange((*MatchedDecl)->getLocation());
- ConDecl->setInvalidDecl();
- return 0;
- }
-
- // FIXME: Just drop the definition (for now).
- 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
- // either there are no other parameters or else all other
- // parameters have default arguments.
- if ((ConDecl->getNumParams() == 1) ||
- (ConDecl->getNumParams() > 1 &&
- ConDecl->getParamDecl(1)->getDefaultArg() != 0)) {
- QualType ParamType = ConDecl->getParamDecl(0)->getType();
- QualType ClassTy = Context.getTagDeclType(
- const_cast<CXXRecordDecl*>(ConDecl->getParent()));
- if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
- Diag(ConDecl->getLocation(), diag::err_constructor_byvalue_arg)
- << SourceRange(ConDecl->getParamDecl(0)->getLocation());
- ConDecl->setInvalidDecl();
- return ConDecl;
- }
- }
-
- // Add this constructor to the set of constructors of the current
- // class.
- ClassDecl->addConstructor(Context, ConDecl);
- return (DeclTy *)ConDecl;
-}
-
-/// ActOnDestructorDeclarator - Called by ActOnDeclarator to complete
-/// the declaration of the given C++ @p Destructor. This routine is
-/// responsible for recording the destructor in the C++ class, if
-/// possible.
-Sema::DeclTy *Sema::ActOnDestructorDeclarator(CXXDestructorDecl *Destructor) {
- assert(Destructor && "Expected to receive a destructor declaration");
-
- 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()) {
- 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;
- }
-
- ClassDecl->setDestructor(Destructor);
- return (DeclTy *)Destructor;
-}
-
/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
/// the declaration of the given C++ conversion function. This routine
/// is responsible for recording the conversion function in the C++
@@ -1437,18 +1362,35 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
OverloadCandidateSet CandidateSet;
// Add constructors to the overload set.
- OverloadedFunctionDecl *Constructors
- = const_cast<OverloadedFunctionDecl *>(ClassDecl->getConstructors());
- for (OverloadedFunctionDecl::function_iterator Con
- = Constructors->function_begin();
- Con != Constructors->function_end(); ++Con) {
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType.getUnqualifiedType()));
+ DeclContext::lookup_const_result Lookup
+ = ClassDecl->lookup(Context, ConstructorName);
+ if (Lookup.first == Lookup.second)
+ /* No constructors */;
+ else if (OverloadedFunctionDecl *Constructors
+ = dyn_cast<OverloadedFunctionDecl>(*Lookup.first)) {
+ for (OverloadedFunctionDecl::function_iterator Con
+ = Constructors->function_begin();
+ Con != Constructors->function_end(); ++Con) {
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ if ((Kind == IK_Direct) ||
+ (Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
+ (Kind == IK_Default && Constructor->isDefaultConstructor()))
+ AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ }
+ } else if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(*Lookup.first)) {
if ((Kind == IK_Direct) ||
(Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
(Kind == IK_Default && Constructor->isDefaultConstructor()))
AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
}
+ // FIXME: When we decide not to synthesize the implicitly-declared
+ // constructors, we'll need to make them appear here.
+
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Best)) {
case OR_Success:
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 4bfe0c4dab..5e3ec3f4bb 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -953,11 +953,25 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// that class. The argument list is the expression-list within
// the parentheses of the initializer.
CXXRecordDecl *ToRecordDecl = ToRecordType->getDecl();
- const OverloadedFunctionDecl *Constructors = ToRecordDecl->getConstructors();
- for (OverloadedFunctionDecl::function_const_iterator func
- = Constructors->function_begin();
- func != Constructors->function_end(); ++func) {
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*func);
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ToType));
+ DeclContext::lookup_result Lookup
+ = ToRecordDecl->lookup(Context, ConstructorName);
+ if (Lookup.first == Lookup.second)
+ /* No constructors. FIXME: Implicit copy constructor? */;
+ else if (OverloadedFunctionDecl *Constructors
+ = dyn_cast<OverloadedFunctionDecl>(*Lookup.first)) {
+ for (OverloadedFunctionDecl::function_const_iterator func
+ = Constructors->function_begin();
+ func != Constructors->function_end(); ++func) {
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*func);
+ if (Constructor->isConvertingConstructor())
+ AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
+ /*SuppressUserConversions=*/true);
+ }
+ } else if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(*Lookup.first)) {
if (Constructor->isConvertingConstructor())
AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
/*SuppressUserConversions=*/true);
diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp
index 4c4d67fa87..786d1451e6 100644
--- a/test/SemaCXX/constructor.cpp
+++ b/test/SemaCXX/constructor.cpp
@@ -21,3 +21,9 @@ class Foo {
Foo::Foo(const Foo&) { }
+typedef struct {
+ int version;
+} Anon;
+extern const Anon anon;
+extern "C" const Anon anon2;
+
diff --git a/test/SemaCXX/overload-decl.cpp b/test/SemaCXX/overload-decl.cpp
index 9814725085..96378bafb3 100644
--- a/test/SemaCXX/overload-decl.cpp
+++ b/test/SemaCXX/overload-decl.cpp
@@ -13,11 +13,15 @@ int f(int, Float); // expected-error {{functions that differ only in their retur
void g(void); // expected-note {{previous declaration is here}}
int g(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+typedef int INT;
+
class X {
void f();
- void f(int);
+ void f(int); // expected-note {{previous declaration is here}}
void f() const;
+ void f(INT); // expected-error{{cannot be redeclared}}
+
void g(int); // expected-note {{previous declaration is here}}
void g(int, float); // expected-note {{previous declaration is here}}
int g(int, Float); // expected-error {{functions that differ only in their return type cannot be overloaded}}