From: Sebastian Redl Date: Thu, 22 Dec 2011 18:58:38 +0000 (+0000) Subject: Overloading for initializer list construction. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cf15cef8447e8b3ae08e81ad25ae9eb443038acf;p=clang Overloading for initializer list construction. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147156 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index ba161c4f11..6d21bc406f 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -643,8 +643,10 @@ public: FK_InitListBadDestinationType, /// \brief Overloading for a user-defined conversion failed. FK_UserConversionOverloadFailed, - /// \brief Overloaded for initialization by constructor failed. + /// \brief Overloading for initialization by constructor failed. FK_ConstructorOverloadFailed, + /// \brief Overloading for list-initialization by constructor failed. + FK_ListConstructorOverloadFailed, /// \brief Default-initialization of a 'const' object. FK_DefaultInitOfConst, /// \brief Initialization of an incomplete type. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index ad29bce8ac..abaeb18fbd 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2436,6 +2436,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: case FK_ConstructorOverloadFailed: + case FK_ListConstructorOverloadFailed: return FailedOverloadResult == OR_Ambiguous; } @@ -2849,8 +2850,8 @@ static bool TryListConstructionSpecialCases(Sema &S, Args, NumArgs, CandidateSet, /*SuppressUserConversions*/ false); Sequence.SetOverloadFailure( - InitializationSequence::FK_ConstructorOverloadFailed, - OR_Deleted); + InitializationSequence::FK_ListConstructorOverloadFailed, + OR_Deleted); } else Sequence.AddConstructorInitializationStep(DefaultConstructor, DefaultConstructor->getAccess(), @@ -2961,8 +2962,9 @@ static void TryConstructorInitialization(Sema &S, OverloadCandidateSet::iterator Best; if (OverloadingResult Result = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { - Sequence.SetOverloadFailure( - InitializationSequence::FK_ConstructorOverloadFailed, + Sequence.SetOverloadFailure(FromInitList ? + InitializationSequence::FK_ListConstructorOverloadFailed : + InitializationSequence::FK_ConstructorOverloadFailed, Result); return; } @@ -5428,12 +5430,20 @@ bool InitializationSequence::Diagnose(Sema &S, << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange(); break; + case FK_ListConstructorOverloadFailed: case FK_ConstructorOverloadFailed: { SourceRange ArgsRange; if (NumArgs) ArgsRange = SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + if (Failure == FK_ListConstructorOverloadFailed) { + assert(NumArgs == 1 && "List construction from other than 1 argument."); + InitListExpr *InitList = cast(Args[0]); + Args = InitList->getInits(); + NumArgs = InitList->getNumInits(); + } + // FIXME: Using "DestType" for the entity we're printing is probably // bad. switch (FailedOverloadResult) { diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index cf8df57eb3..ee846c3fc3 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -824,6 +824,86 @@ bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) { return FD->isUnavailable() && !cast(CurContext)->isUnavailable(); } +/// \brief Tries a user-defined conversion from From to ToType. +/// +/// Produces an implicit conversion sequence for when a standard conversion +/// is not an option. See TryImplicitConversion for more information. +static ImplicitConversionSequence +TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, + bool InOverloadResolution, + bool CStyle, + bool AllowObjCWritebackConversion) { + ImplicitConversionSequence ICS; + + if (SuppressUserConversions) { + // We're not in the case above, so there is no conversion that + // we can perform. + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); + return ICS; + } + + // Attempt user-defined conversion. + OverloadCandidateSet Conversions(From->getExprLoc()); + OverloadingResult UserDefResult + = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions, + AllowExplicit); + + if (UserDefResult == OR_Success) { + ICS.setUserDefined(); + // C++ [over.ics.user]p4: + // A conversion of an expression of class type to the same class + // type is given Exact Match rank, and a conversion of an + // expression of class type to a base class of that type is + // given Conversion rank, in spite of the fact that a copy + // constructor (i.e., a user-defined conversion function) is + // called for those cases. + if (CXXConstructorDecl *Constructor + = dyn_cast(ICS.UserDefined.ConversionFunction)) { + QualType FromCanon + = S.Context.getCanonicalType(From->getType().getUnqualifiedType()); + QualType ToCanon + = S.Context.getCanonicalType(ToType).getUnqualifiedType(); + if (Constructor->isCopyConstructor() && + (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) { + // Turn this into a "standard" conversion sequence, so that it + // gets ranked with standard conversion sequences. + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.setFromType(From->getType()); + ICS.Standard.setAllToTypes(ToType); + ICS.Standard.CopyConstructor = Constructor; + if (ToCanon != FromCanon) + ICS.Standard.Second = ICK_Derived_To_Base; + } + } + + // C++ [over.best.ics]p4: + // However, when considering the argument of a user-defined + // conversion function that is a candidate by 13.3.1.3 when + // invoked for the copying of the temporary in the second step + // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or + // 13.3.1.6 in all cases, only standard conversion sequences and + // ellipsis conversion sequences are allowed. + if (SuppressUserConversions && ICS.isUserDefined()) { + ICS.setBad(BadConversionSequence::suppressed_user, From, ToType); + } + } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) { + ICS.setAmbiguous(); + ICS.Ambiguous.setFromType(From->getType()); + ICS.Ambiguous.setToType(ToType); + for (OverloadCandidateSet::iterator Cand = Conversions.begin(); + Cand != Conversions.end(); ++Cand) + if (Cand->Viable) + ICS.Ambiguous.addConversion(Cand->Function); + } else { + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); + } + + return ICS; +} + /// TryImplicitConversion - Attempt to perform an implicit conversion /// from the given expression (Expr) to the given type (ToType). This /// function returns an implicit conversion sequence that can be used @@ -899,71 +979,9 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType, return ICS; } - if (SuppressUserConversions) { - // We're not in the case above, so there is no conversion that - // we can perform. - ICS.setBad(BadConversionSequence::no_conversion, From, ToType); - return ICS; - } - - // Attempt user-defined conversion. - OverloadCandidateSet Conversions(From->getExprLoc()); - OverloadingResult UserDefResult - = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions, - AllowExplicit); - - if (UserDefResult == OR_Success) { - ICS.setUserDefined(); - // C++ [over.ics.user]p4: - // A conversion of an expression of class type to the same class - // type is given Exact Match rank, and a conversion of an - // expression of class type to a base class of that type is - // given Conversion rank, in spite of the fact that a copy - // constructor (i.e., a user-defined conversion function) is - // called for those cases. - if (CXXConstructorDecl *Constructor - = dyn_cast(ICS.UserDefined.ConversionFunction)) { - QualType FromCanon - = S.Context.getCanonicalType(From->getType().getUnqualifiedType()); - QualType ToCanon - = S.Context.getCanonicalType(ToType).getUnqualifiedType(); - if (Constructor->isCopyConstructor() && - (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) { - // Turn this into a "standard" conversion sequence, so that it - // gets ranked with standard conversion sequences. - ICS.setStandard(); - ICS.Standard.setAsIdentityConversion(); - ICS.Standard.setFromType(From->getType()); - ICS.Standard.setAllToTypes(ToType); - ICS.Standard.CopyConstructor = Constructor; - if (ToCanon != FromCanon) - ICS.Standard.Second = ICK_Derived_To_Base; - } - } - - // C++ [over.best.ics]p4: - // However, when considering the argument of a user-defined - // conversion function that is a candidate by 13.3.1.3 when - // invoked for the copying of the temporary in the second step - // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or - // 13.3.1.6 in all cases, only standard conversion sequences and - // ellipsis conversion sequences are allowed. - if (SuppressUserConversions && ICS.isUserDefined()) { - ICS.setBad(BadConversionSequence::suppressed_user, From, ToType); - } - } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) { - ICS.setAmbiguous(); - ICS.Ambiguous.setFromType(From->getType()); - ICS.Ambiguous.setToType(ToType); - for (OverloadCandidateSet::iterator Cand = Conversions.begin(); - Cand != Conversions.end(); ++Cand) - if (Cand->Viable) - ICS.Ambiguous.addConversion(Cand->Function); - } else { - ICS.setBad(BadConversionSequence::no_conversion, From, ToType); - } - - return ICS; + return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions, + AllowExplicit, InOverloadResolution, CStyle, + AllowObjCWritebackConversion); } ImplicitConversionSequence @@ -2612,6 +2630,18 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // We're not going to find any constructors. } else if (CXXRecordDecl *ToRecordDecl = dyn_cast(ToRecordType->getDecl())) { + + Expr **Args = &From; + unsigned NumArgs = 1; + bool ListInitializing = false; + // If we're list-initializing, we pass the individual elements as + // arguments, not the entire list. + if (InitListExpr *InitList = dyn_cast(From)) { + Args = InitList->getInits(); + NumArgs = InitList->getNumInits(); + ListInitializing = true; + } + DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl); Con != ConEnd; ++Con) { @@ -2628,28 +2658,33 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, else Constructor = cast(D); - if (!Constructor->isInvalidDecl() && - Constructor->isConvertingConstructor(AllowExplicit)) { + bool Usable = !Constructor->isInvalidDecl(); + if (ListInitializing) + Usable = Usable && (AllowExplicit || !Constructor->isExplicit()); + else + Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit); + if (Usable) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, - &From, 1, CandidateSet, + Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ - !ConstructorsOnly); + !ConstructorsOnly && + !ListInitializing); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). S.AddOverloadCandidate(Constructor, FoundDecl, - &From, 1, CandidateSet, + Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ - !ConstructorsOnly); + !ConstructorsOnly && !ListInitializing); } } } } // Enumerate conversion functions, if we're allowed to. - if (ConstructorsOnly) { + if (ConstructorsOnly || isa(From)) { } else if (S.RequireCompleteType(From->getLocStart(), From->getType(), S.PDiag(0) << From->getSourceRange())) { // No conversion functions from incomplete types. @@ -2705,11 +2740,16 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // the argument of the constructor. // QualType ThisType = Constructor->getThisType(S.Context); - if (Best->Conversions[0].isEllipsis()) - User.EllipsisConversion = true; - else { - User.Before = Best->Conversions[0].Standard; - User.EllipsisConversion = false; + if (isa(From)) { + // Initializer lists don't have conversions as such. + User.Before.setAsIdentityConversion(); + } else { + if (Best->Conversions[0].isEllipsis()) + User.EllipsisConversion = true; + else { + User.Before = Best->Conversions[0].Standard; + User.EllipsisConversion = false; + } } User.HadMultipleCandidates = HadMultipleCandidates; User.ConversionFunction = Constructor; @@ -3916,7 +3956,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // conversion sequence is the worst conversion necessary to convert an // element of the list to X. // FIXME: Recognize std::initializer_list. - // FIXME: Arrays don't make sense until we can deal with references. + // FIXME: Implement arrays. if (ToType->isArrayType()) return Result; @@ -3926,9 +3966,15 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // conversion sequence is a user-defined conversion sequence. If multiple // constructors are viable but none is better than the others, the // implicit conversion sequence is a user-defined conversion sequence. - // FIXME: Implement this. - if (ToType->isRecordType() && !ToType->isAggregateType()) + if (ToType->isRecordType() && !ToType->isAggregateType()) { + // This function can deal with initializer lists. + Result = TryUserDefinedConversion(S, From, ToType, SuppressUserConversions, + /*AllowExplicit=*/false, + InOverloadResolution, /*CStyle=*/false, + AllowObjCWritebackConversion); + Result.setListInitializationSequence(); return Result; + } // C++11 [over.ics.list]p4: // Otherwise, if the parameter has an aggregate type which can be diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp index c0e5010051..c083366865 100644 --- a/test/SemaCXX/cxx0x-initializer-constructor.cpp +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s +struct one { char c[1]; }; +struct two { char c[2]; }; + namespace objects { struct X1 { X1(int); }; @@ -45,8 +48,8 @@ namespace objects { void takes_C(C); takes_C({1, 1.0}); - //C c; - //c[{1, 1.0}]; needs overloading + C c; + c[{1, 1.0}]; return {1, 1.0}; } @@ -56,11 +59,23 @@ namespace objects { (void) new C{1, 1.0}; } - struct B { - B(C, int, C); + struct B { // expected-note 2 {{candidate constructor}} + B(C, int, C); // expected-note {{candidate constructor not viable: cannot convert initializer list argument to 'objects::C'}} }; void nested_init() { - //B b{{1, 1.0}, 2, {3, 4}}; needs overloading + B b1{{1, 1.0}, 2, {3, 4}}; + B b2{{1, 1.0, 4}, 2, {3, 4}}; // expected-error {{no matching constructor for initialization of 'objects::B'}} + } + + void overloaded_call() { + one ov1(B); // expected-note {{not viable: cannot convert initializer list}} + two ov1(C); // expected-note {{not viable: cannot convert initializer list}} + + static_assert(sizeof(ov1({})) == sizeof(two), "bad overload"); + static_assert(sizeof(ov1({1, 2})) == sizeof(two), "bad overload"); + static_assert(sizeof(ov1({{1, 1.0}, 2, {3, 4}})) == sizeof(one), "bad overload"); + + ov1({1}); // expected-error {{no matching function}} } }