]> granicus.if.org Git - clang/commitdiff
Basic overloading support for std::initializer_list.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 17 Jan 2012 22:49:48 +0000 (22:49 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 17 Jan 2012 22:49:48 +0000 (22:49 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148350 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaOverload.cpp
test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp

index d14bf904df04ec3367e03302479c9a975814848a..e39735e256cafb0d4d6b54f8f2cfded40164616e 100644 (file)
@@ -3953,15 +3953,42 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
   Result.setBad(BadConversionSequence::no_conversion, From, ToType);
   Result.setListInitializationSequence();
 
+  // We need a complete type for what follows. Incomplete types can bever be
+  // initialized from init lists.
+  if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag()))
+    return Result;
+
   // 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.
-  // FIXME: Recognize std::initializer_list.
-  // FIXME: Implement arrays.
+  QualType X;
   if (ToType->isArrayType())
+    X = S.Context.getBaseElementType(ToType);
+  else
+    (void)S.isStdInitializerList(ToType, &X);
+  if (!X.isNull()) {
+    for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) {
+      Expr *Init = From->getInit(i);
+      ImplicitConversionSequence ICS =
+          TryCopyInitialization(S, Init, X, SuppressUserConversions,
+                                InOverloadResolution,
+                                AllowObjCWritebackConversion);
+      // If a single element isn't convertible, fail.
+      if (ICS.isBad()) {
+        Result = ICS;
+        break;
+      }
+      // Otherwise, look for the worst conversion.
+      if (Result.isBad() ||
+          CompareImplicitConversionSequences(S, ICS, Result) ==
+              ImplicitConversionSequence::Worse)
+        Result = ICS;
+    }
+    Result.setListInitializationSequence();
     return Result;
+  }
 
   // C++11 [over.ics.list]p3:
   //   Otherwise, if the parameter is a non-aggregate class X and overload
@@ -4078,7 +4105,6 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
     //    - if the initializer list has one element, the implicit conversion
     //      sequence is the one required to convert the element to the
     //      parameter type.
-    // FIXME: Catch narrowing here?
     unsigned NumInits = From->getNumInits();
     if (NumInits == 1)
       Result = TryCopyInitialization(S, From->getInit(0), ToType,
index fc0df68575b194161970320362e85fdfd9de6835..87e7e8462ba59cb8b3fc115b63f7aa1af1a0ff3e 100644 (file)
@@ -58,3 +58,32 @@ void function_call() {
   void g(std::initializer_list<B>);
   g({ {1, 2}, {2, 3}, {} });
 }
+
+struct C {
+  C(int);
+};
+
+struct D {
+  D();
+  operator int();
+  operator C();
+};
+
+void overloaded_call() {
+    one overloaded(std::initializer_list<int>);
+    two overloaded(std::initializer_list<B>);
+
+    static_assert(sizeof(overloaded({1, 2, 3})) == sizeof(one), "bad overload");
+    static_assert(sizeof(overloaded({ {1, 2}, {2, 3}, {} })) == sizeof(two), "bad overload");
+
+    void ambiguous(std::initializer_list<A>); // expected-note {{candidate}}
+    void ambiguous(std::initializer_list<B>); // expected-note {{candidate}}
+    ambiguous({ {1, 2}, {2, 3}, {3, 4} }); // expected-error {{ambiguous}}
+
+    one ov2(std::initializer_list<int>); // expected-note {{candidate}}
+    two ov2(std::initializer_list<C>); // expected-note {{candidate}}
+    // Worst sequence to int is identity, whereas to C it's user-defined.
+    static_assert(sizeof(ov2({1, 2, 3})) == sizeof(one), "bad overload");
+    // But here, user-defined is worst in both cases.
+    ov2({1, 2, D()}); // expected-error {{ambiguous}}
+}