} else if (Tok.is(tok::l_brace) && getLang().CPlusPlus0x) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
- // FIXME: Have to communicate the init-list to ActOnCXXNew.
- ParseBraceInitializer();
+ ExprResult InitList = ParseBraceInitializer();
+ if (InitList.isInvalid())
+ return InitList;
+ ConstructorArgs.push_back(InitList.take());
}
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
}
+static OverloadingResult
+IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
+ CXXRecordDecl *To,
+ UserDefinedConversionSequence &User,
+ OverloadCandidateSet &CandidateSet,
+ bool AllowExplicit) {
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = S.LookupConstructors(To);
+ Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl
+ = dyn_cast<FunctionTemplateDecl>(D);
+ if (ConstructorTmpl)
+ Constructor
+ = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+ else
+ Constructor = cast<CXXConstructorDecl>(D);
+
+ bool Usable = !Constructor->isInvalidDecl() &&
+ S.isInitListConstructor(Constructor) &&
+ (AllowExplicit || !Constructor->isExplicit());
+ if (Usable) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ &From, 1, CandidateSet,
+ /*SuppressUserConversions=*/true);
+ else
+ S.AddOverloadCandidate(Constructor, FoundDecl,
+ &From, 1, CandidateSet,
+ /*SuppressUserConversions=*/true);
+ }
+ }
+
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
+ OverloadCandidateSet::iterator Best;
+ switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best, true)) {
+ case OR_Success: {
+ // Record the standard conversion we used and the conversion function.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
+ S.MarkFunctionReferenced(From->getLocStart(), Constructor);
+
+ QualType ThisType = Constructor->getThisType(S.Context);
+ // Initializer lists don't have conversions as such.
+ User.Before.setAsIdentityConversion();
+ User.HadMultipleCandidates = HadMultipleCandidates;
+ User.ConversionFunction = Constructor;
+ User.FoundConversionFunction = Best->FoundDecl;
+ User.After.setAsIdentityConversion();
+ User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setAllToTypes(ToType);
+ return OR_Success;
+ }
+
+ case OR_No_Viable_Function:
+ return OR_No_Viable_Function;
+ case OR_Deleted:
+ return OR_Deleted;
+ case OR_Ambiguous:
+ return OR_Ambiguous;
+ }
+
+ llvm_unreachable("Invalid OverloadResult!");
+}
+
/// Determines whether there is a user-defined conversion sequence
/// (C++ [over.ics.user]) that converts expression From to the type
/// ToType. If such a conversion exists, User will contain the
/// functions (C++0x [class.conv.fct]p2).
static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
- UserDefinedConversionSequence& User,
- OverloadCandidateSet& CandidateSet,
+ UserDefinedConversionSequence &User,
+ OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
// Whether we will only visit constructors.
bool ConstructorsOnly = false;
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<InitListExpr>(From)) {
+ // But first, see if there is an init-list-contructor that will work.
+ OverloadingResult Result = IsInitializerListConstructorConversion(
+ S, From, ToType, ToRecordDecl, User, CandidateSet, AllowExplicit);
+ if (Result != OR_No_Viable_Function)
+ return Result;
+ // Never mind.
+ CandidateSet.clear();
+
+ // If we're list-initializing, we pass the individual elements as
+ // arguments, not the entire list.
Args = InitList->getInits();
NumArgs = InitList->getNumInits();
ListInitializing = true;
struct one { char c[1]; };
struct two { char c[2]; };
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
namespace objects {
struct X1 { X1(int); };
A(int, double) { static_assert(N == 1, ""); }
};
+ template <int N>
+ struct F {
+ F() { static_assert(N == 0, ""); }
+ F(int, double) { static_assert(N == 1, ""); }
+ F(std::initializer_list<int>) { static_assert(N == 3, ""); }
+ };
+
+ template <int N>
+ struct D {
+ D(std::initializer_list<int>) { static_assert(N == 0, ""); } // expected-note 1 {{candidate}}
+ D(std::initializer_list<double>) { static_assert(N == 1, ""); } // expected-note 1 {{candidate}}
+ };
+
template <int N>
struct E {
E(int, int) { static_assert(N == 0, ""); }
{ A<1> a{1, 1.0}; }
{ A<1> a = {1, 1.0}; }
+ { F<0> f{}; }
+ { F<0> f = {}; }
+ // Narrowing conversions don't affect viability. The next two choose
+ // the initializer_list constructor.
+ // FIXME: Emit narrowing conversion errors.
+ { F<3> f{1, 1.0}; } // xpected-error {{narrowing conversion}}
+ { F<3> f = {1, 1.0}; } // xpected-error {{narrowing conversion}}
+ { F<3> f{1, 2, 3, 4, 5, 6, 7, 8}; }
+ { F<3> f = {1, 2, 3, 4, 5, 6, 7, 8}; }
+ { F<3> f{1, 2, 3, 4, 5, 6, 7, 8}; }
+ { F<3> f{1, 2}; }
+
+ { D<0> d{1, 2, 3}; }
+ { D<1> d{1.0, 2.0, 3.0}; }
+ { D<-1> d{1, 2.0}; } // expected-error {{ambiguous}}
+
{ E<0> e{1, 2}; }
}
void inline_init() {
(void) C{1, 1.0};
(void) new C{1, 1.0};
+ (void) A<1>{1, 1.0};
+ (void) new A<1>{1, 1.0};
}
struct B { // expected-note 2 {{candidate constructor}}
static_assert(sizeof(ov1({{1, 1.0}, 2, {3, 4}})) == sizeof(one), "bad overload");
ov1({1}); // expected-error {{no matching function}}
+
+ one ov2(int);
+ two ov2(F<3>);
+ static_assert(sizeof(ov2({1})) == sizeof(one), "bad overload"); // list -> int ranks as identity
+ static_assert(sizeof(ov2({1, 2, 3})) == sizeof(two), "bad overload"); // list -> F only viable
}
}
}
int InitList() {
- (void)new int {}; // expected-warning {{generalized initializer lists are incompatible with C++98}}
+ (void)new int {}; // expected-warning {{generalized initializer lists are incompatible with C++98}} \
+ // expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
(void)int{}; // expected-warning {{generalized initializer lists are incompatible with C++98}}
int x { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
return { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
};
}
-namespace objects {
-
- struct X1 { X1(int); };
- struct X2 { explicit X2(int); };
-
- template <int N>
- struct A {
- A() { static_assert(N == 0, ""); }
- A(int, double) { static_assert(N == 1, ""); }
- A(std::initializer_list<int>) { static_assert(N == 3, ""); }
- };
-
- template <int N>
- struct D {
- D(std::initializer_list<int>) { static_assert(N == 0, ""); } // expected-note 1 {{candidate}}
- D(std::initializer_list<double>) { static_assert(N == 1, ""); } // expected-note 1 {{candidate}}
- };
-
- template <int N>
- struct E {
- E(int, int) { static_assert(N == 0, ""); }
- E(X1, int) { static_assert(N == 1, ""); }
- };
-
- void overload_resolution() {
- { A<0> a{}; }
- { A<0> a = {}; }
- // Narrowing conversions don't affect viability. The next two choose
- // the initializer_list constructor.
- { A<3> a{1, 1.0}; } // expected-error {{narrowing conversion}}
- { A<3> a = {1, 1.0}; } // expected-error {{narrowing conversion}}
- { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
- { A<3> a = {1, 2, 3, 4, 5, 6, 7, 8}; }
- { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
- { A<3> a{1, 2}; }
-
- { D<0> d{1, 2, 3}; }
- { D<1> d{1.0, 2.0, 3.0}; }
- { D<-1> d{1, 2.0}; } // expected-error {{ambiguous}}
-
- { E<0> e{1, 2}; }
- }
-
- void explicit_implicit() {
- { X1 x{0}; }
- { X1 x = {0}; }
- { X2 x{0}; }
- { X2 x = {0}; } // expected-error {{explicit}}
- }
-
- struct C {
- C();
- C(int, double);
- C(int, int);
- C(std::initializer_list<int>);
-
- int operator[](C);
- };
-
- C function_call() {
- void takes_C(C);
- takes_C({1, 1.0});
-
- C c;
- c[{1, 1.0}];
-
- return {1, 1.0};
- }
-
- void inline_init() {
- (void) A<1>{1, 1.0};
- (void) new A<1>{1, 1.0};
- }
-
- struct B {
- B(C, int, C);
- };
-
- void nested_init() {
- B b{{1, 1.0}, 2, {3, 4, 5, 6, 7}};
- }
-}
-
namespace litb {
// invalid