r227224 - 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.
Larisse Voufo
lvoufo at google.com
Tue Jan 27 10:47:05 PST 2015
Author: lvoufo
Date: Tue Jan 27 12:47:05 2015
New Revision: 227224
URL: http://llvm.org/viewvc/llvm-project?rev=227224&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/CXX/drs/dr14xx.cpp
cfe/trunk/test/CXX/special/class.inhctor/p2.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
cfe/trunk/test/SemaCXX/explicit.cpp
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=227224&r1=227223&r2=227224&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jan 27 12:47:05 2015
@@ -3110,7 +3110,7 @@ ResolveConstructorOverload(Sema &S, Sour
ArrayRef<NamedDecl *> Ctors,
OverloadCandidateSet::iterator &Best,
bool CopyInitializing, bool AllowExplicit,
- bool OnlyListConstructors, bool InitListSyntax) {
+ bool OnlyListConstructors) {
CandidateSet.clear();
for (ArrayRef<NamedDecl *>::iterator
@@ -3129,20 +3129,13 @@ ResolveConstructorOverload(Sema &S, Sour
Constructor = cast<CXXConstructorDecl>(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
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
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
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 &
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 &
// 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 &
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
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=227224&r1=227223&r2=227224&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jan 27 12:47:05 2015
@@ -3336,7 +3336,26 @@ CompareImplicitConversionSequences(Sema
// 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<X> 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
ICS2.UserDefined.ConversionFunction);
}
- // List-initialization sequence L1 is a better conversion sequence than
- // list-initialization sequence L2 if L1 converts to std::initializer_list<X>
- // 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
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<X> 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
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
/*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
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
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<InitListExpr>(From->getInit(0)))
Result = TryCopyInitialization(S, From->getInit(0), ToType,
SuppressUserConversions,
InOverloadResolution,
@@ -4628,6 +4680,7 @@ TryListConversion(Sema &S, InitListExpr
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;
Modified: cfe/trunk/test/CXX/drs/dr14xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr14xx.cpp?rev=227224&r1=227223&r2=227224&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr14xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr14xx.cpp Tue Jan 27 12:47:05 2015
@@ -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<typename T> struct basic_string {
+ basic_string(const T* x) {}
+ ~basic_string() {};
+ };
+ typedef basic_string<char> 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 at -2 {{excess elements in struct initializer}}
-#endif
-
- // TODO: Only Items 1 and 2 from DR1467 are covered for now.
- // Implement remaining items, and expand here as necessary.
-
} // dr_example
+
+ namespace nonaggregate {
+
+ struct NonAggregate {
+ NonAggregate() {}
+ };
+
+ struct WantsIt {
+ WantsIt(NonAggregate);
+ };
+
+ void f(NonAggregate);
+ void f(WantsIt);
+
+ void test1() {
+ NonAggregate n;
+ f({n});
+ }
+
+ void test2() {
+ NonAggregate x;
+ NonAggregate y{x};
+ NonAggregate z{{x}};
+ }
+
+ } // nonaggregate
} // dr1467
-namespace dr1490 {
+namespace dr1490 { // dr1490: yes c++11
// List-initialization from a string literal
-
+
char s[4]{"abc"}; // Ok
std::initializer_list<char>{"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<int>); // #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<long>); // #2
+ void g1() { f1({42}); } // chooses #2
+
+ void f2(std::pair<const char*, const char*>, int = 0); // Would makes selection of #3 ambiguous
+ void f2(std::pair<const char*, const char*>); // #3
+ void f2(std::initializer_list<std::string>); // #4
+ void g2() { f2({"foo","bar"}); } // chooses #4
+
+ namespace with_error {
+
+ void f0(long); // #0 expected-note {{candidate function}}
+ void f0(std::initializer_list<int>); // #00 expected-note {{candidate function}}
+ void f0(std::initializer_list<int>, 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<long>); // #2 expected-note {{candidate function}}
+ void f1(std::initializer_list<long>, 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<const char*, const char*>); // #3 TODO: expected- note {{candidate function}}
+ void f2(std::initializer_list<std::string>); // #4 expected-note {{candidate function}}
+ void f2(std::initializer_list<std::string>, 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
Modified: cfe/trunk/test/CXX/special/class.inhctor/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p2.cpp?rev=227224&r1=227223&r2=227224&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.inhctor/p2.cpp (original)
+++ cfe/trunk/test/CXX/special/class.inhctor/p2.cpp Tue Jan 27 12:47:05 2015
@@ -96,7 +96,7 @@ struct TemplateCtors {
template<typename T = int> 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>) {}
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp?rev=227224&r1=227223&r2=227224&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp Tue Jan 27 12:47:05 2015
@@ -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};
}
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=227224&r1=227223&r2=227224&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Tue Jan 27 12:47:05 2015
@@ -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; };
Modified: cfe/trunk/test/SemaCXX/explicit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/explicit.cpp?rev=227224&r1=227223&r2=227224&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/explicit.cpp (original)
+++ cfe/trunk/test/SemaCXX/explicit.cpp Tue Jan 27 12:47:05 2015
@@ -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() {
More information about the cfe-commits
mailing list