From: Larisse Voufo Date: Tue, 27 Jan 2015 18:47:05 +0000 (+0000) Subject: Implement the remaining portion of DR1467 from r227022. I may have overlooked a few... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=619b4a3e657b37ca1b1a77eae9f1f6ca3b3ef897;p=clang Implement the remaining portion of DR1467 from r227022. I may have overlooked a few things, but this implementation comes straight from the DR resolution itself. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@227224 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index c9d8e5312a..c6d9a544c4 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3110,7 +3110,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, ArrayRef Ctors, OverloadCandidateSet::iterator &Best, bool CopyInitializing, bool AllowExplicit, - bool OnlyListConstructors, bool InitListSyntax) { + bool OnlyListConstructors) { CandidateSet.clear(); for (ArrayRef::iterator @@ -3129,20 +3129,13 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, Constructor = cast(D); // C++11 [over.best.ics]p4: - // However, when considering the argument of a constructor or - // user-defined conversion function that is a candidate: - // -- by 13.3.1.3 when invoked for the copying/moving of a temporary - // in the second step of a class copy-initialization, - // -- by 13.3.1.7 when passing the initializer list as a single - // argument or when the initializer list has exactly one elementand - // a conversion to some class X or reference to (possibly - // cv-qualified) X is considered for the first parameter of a - // constructor of X, 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 considered. - if ((CopyInitializing || (InitListSyntax && Args.size() == 1)) && - Constructor->isCopyOrMoveConstructor()) + // ... and the constructor or user-defined conversion function is a + // candidate by + // — 13.3.1.3, when the argument is the temporary in the second step + // of a class copy-initialization, or + // — 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases), + // user-defined conversion sequences are not considered. + if (CopyInitializing && Constructor->isCopyOrMoveConstructor()) SuppressUserConversions = true; } @@ -3222,16 +3215,12 @@ static void TryConstructorInitialization(Sema &S, OverloadCandidateSet::iterator Best; bool AsInitializerList = false; - // C++14 DR 1467 [over.match.list]p1: + // C++11 [over.match.list]p1, per DR1467: // When objects of non-aggregate type T are list-initialized, such that // 8.5.4 [dcl.init.list] specifies that overload resolution is performed // according to the rules in this section, overload resolution selects // the constructor in two phases: // - // C++11 [over.match.list]p1: - // When objects of non-aggregate type T are list-initialized, overload - // resolution selects the constructor in two phases: - // // - Initially, the candidate functions are the initializer-list // constructors of the class T and the argument list consists of the // initializer list as a single argument. @@ -3245,8 +3234,7 @@ static void TryConstructorInitialization(Sema &S, Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, - /*OnlyListConstructor=*/true, - InitListSyntax); + /*OnlyListConstructor=*/true); // Time to unwrap the init list. Args = MultiExprArg(ILE->getInits(), ILE->getNumInits()); @@ -3262,8 +3250,7 @@ static void TryConstructorInitialization(Sema &S, Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, - /*OnlyListConstructors=*/false, - InitListSyntax); + /*OnlyListConstructors=*/false); } if (Result) { Sequence.SetOverloadFailure(InitListSyntax ? @@ -3439,7 +3426,7 @@ static void TryListInitialization(Sema &S, return; } - // C++14 DR1467 [dcl.init.list]p3: + // C++11 [dcl.init.list]p3, per DR1467: // - If T is a class type and the initializer list has a single element of // type cv U, where U is T or a class derived from T, the object is // initialized from that element (by copy-initialization for @@ -3449,8 +3436,8 @@ static void TryListInitialization(Sema &S, // single element that is an appropriately-typed string literal // (8.5.2 [dcl.init.string]), initialization is performed as described // in that section. - // - Otherwise, If T is an aggregate, [...] (continue below). - if (S.getLangOpts().CPlusPlus14 && InitList->getNumInits() == 1) { + // - Otherwise, if T is an aggregate, [...] (continue below). + if (S.getLangOpts().CPlusPlus11 && InitList->getNumInits() == 1) { if (DestType->isRecordType()) { QualType InitType = InitList->getInit(0)->getType(); if (S.Context.hasSameUnqualifiedType(InitType, DestType) || @@ -3519,12 +3506,6 @@ static void TryListInitialization(Sema &S, InitList->getInit(0)->getType()->isRecordType()) { // - Otherwise, if the initializer list has a single element of type E // [...references are handled above...], the object or reference is - // initialized from that element; if a narrowing conversion is required - // to convert the element to T, the program is ill-formed. - // - // C++14 DR1467: - // - Otherwise, if the initializer list has a single element of type E - // [...references are handled above...], the object or reference is // initialized from that element (by copy-initialization for // copy-list-initialization, or by direct-initialization for // direct-list-initialization); if a narrowing conversion is required diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 7c34f43d27..28f1231bd5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3336,7 +3336,26 @@ CompareImplicitConversionSequences(Sema &S, // Two implicit conversion sequences of the same form are // indistinguishable conversion sequences unless one of the // following rules apply: (C++ 13.3.3.2p3): + + // List-initialization sequence L1 is a better conversion sequence than + // list-initialization sequence L2 if: + // - L1 converts to std::initializer_list for some X and L2 does not, or, + // if not that, + // - L1 converts to type “array of N1 T”, L2 converts to type “array of N2 T”, + // and N1 is smaller than N2., + // even if one of the other rules in this paragraph would otherwise apply. + if (!ICS1.isBad()) { + if (ICS1.isStdInitializerListElement() && + !ICS2.isStdInitializerListElement()) + return ImplicitConversionSequence::Better; + if (!ICS1.isStdInitializerListElement() && + ICS2.isStdInitializerListElement()) + return ImplicitConversionSequence::Worse; + } + if (ICS1.isStandard()) + // Standard conversion sequence S1 is a better conversion sequence than + // standard conversion sequence S2 if [...] Result = CompareStandardConversionSequences(S, ICS1.Standard, ICS2.Standard); else if (ICS1.isUserDefined()) { @@ -3357,19 +3376,6 @@ CompareImplicitConversionSequences(Sema &S, ICS2.UserDefined.ConversionFunction); } - // List-initialization sequence L1 is a better conversion sequence than - // list-initialization sequence L2 if L1 converts to std::initializer_list - // for some X and L2 does not. - if (Result == ImplicitConversionSequence::Indistinguishable && - !ICS1.isBad()) { - if (ICS1.isStdInitializerListElement() && - !ICS2.isStdInitializerListElement()) - return ImplicitConversionSequence::Better; - if (!ICS1.isStdInitializerListElement() && - ICS2.isStdInitializerListElement()) - return ImplicitConversionSequence::Worse; - } - return Result; } @@ -4453,11 +4459,53 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, if (S.RequireCompleteType(From->getLocStart(), ToType, 0)) return Result; + // Per DR1467: + // If the parameter type is a class X and the initializer list has a single + // element of type cv U, where U is X or a class derived from X, the + // implicit conversion sequence is the one required to convert the element + // to the parameter type. + // + // Otherwise, if the parameter type is a character array [... ] + // and the initializer list has a single element that is an + // appropriately-typed string literal (8.5.2 [dcl.init.string]), the + // implicit conversion sequence is the identity conversion. + if (From->getNumInits() == 1) { + if (ToType->isRecordType()) { + QualType InitType = From->getInit(0)->getType(); + if (S.Context.hasSameUnqualifiedType(InitType, ToType) || + S.IsDerivedFrom(InitType, ToType)) + return TryCopyInitialization(S, From->getInit(0), ToType, + SuppressUserConversions, + InOverloadResolution, + AllowObjCWritebackConversion); + } + if (S.Context.getAsArrayType(ToType)) { + InitializedEntity Entity = + InitializedEntity::InitializeParameter(S.Context, ToType, + /*Consumed=*/false); + if (S.CanPerformCopyInitialization(Entity, From)) { + Result.setStandard(); + Result.Standard.setAsIdentityConversion(); + Result.Standard.setFromType(ToType); + Result.Standard.setAllToTypes(ToType); + return Result; + } + } + } + + // C++14 [over.ics.list]p2: Otherwise, if the parameter type [...] (below). // C++11 [over.ics.list]p2: // If the parameter type is std::initializer_list or "array of X" and // all the elements can be implicitly converted to X, the implicit // conversion sequence is the worst conversion necessary to convert an // element of the list to X. + // + // C++14 [over.ics.list]p3: + // Otherwise, if the parameter type is “array of N X”, if the initializer + // list has exactly N elements or if it has fewer than N elements and X is + // default-constructible, and if all the elements of the initializer list + // can be implicitly converted to X, the implicit conversion sequence is + // the worst conversion necessary to convert an element of the list to X. bool toStdInitializerList = false; QualType X; if (ToType->isArrayType()) @@ -4496,6 +4544,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, return Result; } + // C++14 [over.ics.list]p4: // C++11 [over.ics.list]p3: // Otherwise, if the parameter is a non-aggregate class X and overload // resolution chooses a single best constructor [...] the implicit @@ -4511,6 +4560,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, /*AllowObjCConversionOnExplicit=*/false); } + // C++14 [over.ics.list]p5: // C++11 [over.ics.list]p4: // Otherwise, if the parameter has an aggregate type which can be // initialized from the initializer list [...] the implicit conversion @@ -4537,6 +4587,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, return Result; } + // C++14 [over.ics.list]p6: // C++11 [over.ics.list]p5: // Otherwise, if the parameter is a reference, see 13.3.3.1.4. if (ToType->isReferenceType()) { @@ -4605,14 +4656,15 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, return Result; } + // C++14 [over.ics.list]p7: // C++11 [over.ics.list]p6: // Otherwise, if the parameter type is not a class: if (!ToType->isRecordType()) { - // - if the initializer list has one element, the implicit conversion - // sequence is the one required to convert the element to the - // parameter type. + // - if the initializer list has one element that is not itself an + // initializer list, the implicit conversion sequence is the one + // required to convert the element to the parameter type. unsigned NumInits = From->getNumInits(); - if (NumInits == 1) + if (NumInits == 1 && !dyn_cast(From->getInit(0))) Result = TryCopyInitialization(S, From->getInit(0), ToType, SuppressUserConversions, InOverloadResolution, @@ -4628,6 +4680,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, return Result; } + // C++14 [over.ics.list]p8: // C++11 [over.ics.list]p7: // In all cases other than those enumerated above, no conversion is possible return Result; diff --git a/test/CXX/drs/dr14xx.cpp b/test/CXX/drs/dr14xx.cpp index 556cc9b15b..bdab5eb0af 100644 --- a/test/CXX/drs/dr14xx.cpp +++ b/test/CXX/drs/dr14xx.cpp @@ -227,9 +227,18 @@ namespace std { const _E* begin() const {return __begin_;} const _E* end() const {return __begin_ + __size_;} }; + + template < class _T1, class _T2 > struct pair { _T2 second; }; + + template struct basic_string { + basic_string(const T* x) {} + ~basic_string() {}; + }; + typedef basic_string string; + } // std -namespace dr1467 { +namespace dr1467 { // dr1467: yes c++11 // List-initialization of aggregate from same-type object namespace basic0 { @@ -298,23 +307,138 @@ namespace dr1467 { X x; X x2{x}; -#if __cplusplus == 201103L - // expected-error@-2 {{excess elements in struct initializer}} -#endif + } // dr_example + + namespace nonaggregate { + + struct NonAggregate { + NonAggregate() {} + }; + + struct WantsIt { + WantsIt(NonAggregate); + }; + + void f(NonAggregate); + void f(WantsIt); + + void test1() { + NonAggregate n; + f({n}); + } - // TODO: Only Items 1 and 2 from DR1467 are covered for now. - // Implement remaining items, and expand here as necessary. + void test2() { + NonAggregate x; + NonAggregate y{x}; + NonAggregate z{{x}}; + } - } // dr_example + } // nonaggregate } // dr1467 -namespace dr1490 { +namespace dr1490 { // dr1490: yes c++11 // List-initialization from a string literal - + char s[4]{"abc"}; // Ok std::initializer_list{"abc"}; // expected-error {{expected unqualified-id}}} - + } // dr1490 + +namespace dr1589 { // dr1589: yes c++11 + // Ambiguous ranking of list-initialization sequences + + void f0(long, int=0); // Would makes selection of #0 ambiguous + void f0(long); // #0 + void f0(std::initializer_list); // #00 + void g0() { f0({1L}); } // chooses #00 + + void f1(int, int=0); // Would make selection of #1 ambiguous + void f1(int); // #1 + void f1(std::initializer_list); // #2 + void g1() { f1({42}); } // chooses #2 + + void f2(std::pair, int = 0); // Would makes selection of #3 ambiguous + void f2(std::pair); // #3 + void f2(std::initializer_list); // #4 + void g2() { f2({"foo","bar"}); } // chooses #4 + + namespace with_error { + + void f0(long); // #0 expected-note {{candidate function}} + void f0(std::initializer_list); // #00 expected-note {{candidate function}} + void f0(std::initializer_list, int = 0); // Makes selection of #00 ambiguous \ + // expected-note {{candidate function}} + void g0() { f0({1L}); } // chooses #00 expected-error{{call to 'f0' is ambiguous}} + + void f1(int); // #1 expected-note {{candidate function}} + void f1(std::initializer_list); // #2 expected-note {{candidate function}} + void f1(std::initializer_list, int = 0); // Makes selection of #00 ambiguous \ + // expected-note {{candidate function}} + void g1() { f1({42}); } // chooses #2 expected-error{{call to 'f1' is ambiguous}} + + void f2(std::pair); // #3 TODO: expected- note {{candidate function}} + void f2(std::initializer_list); // #4 expected-note {{candidate function}} + void f2(std::initializer_list, int = 0); // Makes selection of #00 ambiguous \ + // expected-note {{candidate function}} + void g2() { f2({"foo","bar"}); } // chooses #4 expected-error{{call to 'f2' is ambiguous}} + + } + +} // dr1589 + + +namespace dr1631 { // dr1589: yes c++11 + // Incorrect overload resolution for single-element initializer-list + + struct A { int a[1]; }; + struct B { B(int); }; + void f(B, int); + void f(B, int, int = 0); + void f(int, A); + + void test() { + f({0}, {{1}}); + } + + namespace with_error { + void f(B, int); // TODO: expected- note {{candidate function}} + void f(int, A); // expected-note {{candidate function}} + void f(int, A, int = 0); // expected-note {{candidate function}} + + void test() { + f({0}, {{1}}); // expected-error{{call to 'f' is ambiguous}} + } + } + +} // dr1631 + +namespace dr1756 { // dr1490: yes c++11 + // Direct-list-initialization of a non-class object + + int a{0}; + + struct X { operator int(); } x; + int b{x}; +} + +namespace dr1758 { // dr1758: yes c++11 + // Explicit conversion in copy/move list initialization + + struct X { X(); }; + struct Y { explicit operator X(); } y; + X x{y}; + + struct A { + A() {} + A(const A &) {} + }; + struct B { + operator A() { return A(); } + } b; + A a{b}; + +} // dr1758 + #endif diff --git a/test/CXX/special/class.inhctor/p2.cpp b/test/CXX/special/class.inhctor/p2.cpp index e6abd6840e..d1c16ff886 100644 --- a/test/CXX/special/class.inhctor/p2.cpp +++ b/test/CXX/special/class.inhctor/p2.cpp @@ -96,7 +96,7 @@ struct TemplateCtors { template TemplateCtors(int, int = 0, int = 0); // expected-note {{inherited from here}} }; -struct UsingTemplateCtors : TemplateCtors { +struct UsingTemplateCtors : TemplateCtors { // expected-note 2{{candidate is the implicit}} using TemplateCtors::TemplateCtors; // expected-note 4{{here}} expected-note {{candidate}} constexpr UsingTemplateCtors(X<0>, X<0>) {} diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp index 3ea53095d4..b481865d84 100644 --- a/test/SemaCXX/cxx0x-initializer-constructor.cpp +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -214,7 +214,9 @@ namespace PR12092 { namespace PR12117 { struct A { A(int); }; - struct B { B(A); } b{{0}}; + struct B { B(A); } b{{0}}; // expected-error {{call to constructor of 'struct B' is ambiguous}} \ + // expected-note 2{{candidate is the implicit}} \ + // expected-note {{candidate constructor}} struct C { C(int); } c{0}; } diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp index d1a9ed3007..dda68a3ec9 100644 --- a/test/SemaCXX/cxx0x-initializer-references.cpp +++ b/test/SemaCXX/cxx0x-initializer-references.cpp @@ -105,12 +105,13 @@ namespace inner_init { B b2 { { 0 } }; B b3 { { { 0 } } }; // expected-warning {{braces around scalar init}} - struct C { C(int); }; + struct C { C(int); }; // expected-note 2{{candidate constructor (the implicit}} \ + // expected-note {{candidate constructor not viable: cannot convert initializer list argument to 'int'}} struct D { C &&r; }; D d1 { 0 }; // ok, 0 implicitly converts to C D d2 { { 0 } }; // ok, { 0 } calls C(0) D d3 { { { 0 } } }; // ok, { { 0 } } calls C({ 0 }) - D d4 { { { { 0 } } } }; // expected-warning {{braces around scalar init}} + D d4 { { { { 0 } } } }; // expected-error {{no matching constructor for initialization of 'inner_init::C &&'}} struct E { explicit E(int); }; // expected-note 2{{here}} struct F { E &&r; }; diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp index 155141c058..a3902e5d10 100644 --- a/test/SemaCXX/explicit.cpp +++ b/test/SemaCXX/explicit.cpp @@ -56,7 +56,7 @@ namespace Conversion { void testExplicit() { // Taken from 12.3.2p2 - class X { X(); }; // expected-note+ {{candidate constructor}} + class X { X(); }; class Y { }; // expected-note+ {{candidate constructor (the implicit}} struct Z { @@ -89,14 +89,10 @@ namespace Conversion { const Y& y11{z}; // expected-error {{excess elements}} expected-note {{in initialization of temporary of type 'const Y'}} const int& y12{z}; - // X is not an aggregate, so constructors are considered. - // However, by 13.3.3.1/4, only standard conversion sequences and - // ellipsis conversion sequences are considered here, so this is not - // allowed. - // FIXME: It's not really clear that this is a sensible restriction for this - // case. g++ allows this, EDG does not. - const X x1{z}; // expected-error {{no matching constructor}} - const X& x2{z}; // expected-error {{no matching constructor}} + // X is not an aggregate, so constructors are considered, + // per 13.3.3.1/4 & DR1467. + const X x1{z}; + const X& x2{z}; } void testBool() {