From: Douglas Gregor Date: Mon, 15 Dec 2008 21:24:18 +0000 (+0000) Subject: Place constructors and destructors into the DeclContext of the class, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9e7d9de3ef538c1473248238b76a6d7b16f5f684;p=clang 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 --- 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(const_cast(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(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(*Lookup.first)) { + for (OverloadedFunctionDecl::function_const_iterator Con + = Constructors->function_begin(); + Con != Constructors->function_end(); ++Con) { if (cast(*Con)->isCopyConstructor(Context, TypeQuals) && (TypeQuals & QualType::Const != 0)) return true; + } + } else if (CXXConstructorDecl *Constructor + = dyn_cast(*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(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(LookupCtx)) - return const_cast(Record)->getConstructors(); - else - return 0; - - case DeclarationName::CXXDestructorName: - if (const CXXRecordDecl *Record = dyn_cast(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(OldMethod)) + NewDiag = diag::err_constructor_redeclared; + else if (isa(NewMethod)) + NewDiag = diag::err_destructor_redeclared; + else if (isa(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(NewFD)) - return ActOnConstructorDeclarator(Constructor); - else if (CXXDestructorDecl *Destructor = dyn_cast(NewFD)) - return ActOnDestructorDeclarator(Destructor); - - // Extra checking for conversion functions, including recording - // the conversion function in its class. - if (CXXConversionDecl *Conversion = dyn_cast(NewFD)) + if (CXXConstructorDecl *Constructor = dyn_cast(NewFD)) { + CXXRecordDecl *ClassDecl = cast(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(NewFD)) + cast(NewFD->getParent())->setUserDeclaredDestructor(true); + else if (CXXConversionDecl *Conversion = dyn_cast(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(*Lookup.first) && + !isa(*Lookup.first))) + ClassDecl->addDecl(Context, CopyConstructor); + else { + OverloadedFunctionDecl *Ovl + = dyn_cast(*Lookup.first); + if (!Ovl) { + Ovl = OverloadedFunctionDecl::Create(Context, ClassDecl, Name); + Ovl->addOverload(cast(*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(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(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(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(ClassDecl->getConstructors()); - for (OverloadedFunctionDecl::function_iterator Con - = Constructors->function_begin(); - Con != Constructors->function_end(); ++Con) { - CXXConstructorDecl *Constructor = cast(*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(*Lookup.first)) { + for (OverloadedFunctionDecl::function_iterator Con + = Constructors->function_begin(); + Con != Constructors->function_end(); ++Con) { + CXXConstructorDecl *Constructor = cast(*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(*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(*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(*Lookup.first)) { + for (OverloadedFunctionDecl::function_const_iterator func + = Constructors->function_begin(); + func != Constructors->function_end(); ++func) { + CXXConstructorDecl *Constructor = cast(*func); + if (Constructor->isConvertingConstructor()) + AddOverloadCandidate(Constructor, &From, 1, CandidateSet, + /*SuppressUserConversions=*/true); + } + } else if (CXXConstructorDecl *Constructor + = dyn_cast(*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}}