[cfe-commits] r147156 - in /cfe/trunk: include/clang/Sema/Initialization.h lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/cxx0x-initializer-constructor.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Thu Dec 22 10:58:38 PST 2011


Author: cornedbee
Date: Thu Dec 22 12:58:38 2011
New Revision: 147156

URL: http://llvm.org/viewvc/llvm-project?rev=147156&view=rev
Log:
Overloading for initializer list construction.

Modified:
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Thu Dec 22 12:58:38 2011
@@ -643,8 +643,10 @@
     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.

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Dec 22 12:58:38 2011
@@ -2436,6 +2436,7 @@
   case FK_ReferenceInitOverloadFailed:
   case FK_UserConversionOverloadFailed:
   case FK_ConstructorOverloadFailed:
+  case FK_ListConstructorOverloadFailed:
     return FailedOverloadResult == OR_Ambiguous;
   }
 
@@ -2849,8 +2850,8 @@
                                  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 @@
   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 @@
       << (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<InitListExpr>(Args[0]);
+      Args = InitList->getInits();
+      NumArgs = InitList->getNumInits();
+    }
+
     // FIXME: Using "DestType" for the entity we're printing is probably
     // bad.
     switch (FailedOverloadResult) {

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Dec 22 12:58:38 2011
@@ -824,6 +824,86 @@
   return FD->isUnavailable() && !cast<Decl>(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<CXXConstructorDecl>(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 @@
     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<CXXConstructorDecl>(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 @@
       // We're not going to find any constructors.
     } else if (CXXRecordDecl *ToRecordDecl
                  = dyn_cast<CXXRecordDecl>(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<InitListExpr>(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 @@
         else
           Constructor = cast<CXXConstructorDecl>(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<InitListExpr>(From)) {
   } else if (S.RequireCompleteType(From->getLocStart(), From->getType(),
                                    S.PDiag(0) << From->getSourceRange())) {
     // No conversion functions from incomplete types.
@@ -2705,11 +2740,16 @@
       //   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<InitListExpr>(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 @@
   //   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 @@
   //   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

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=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp Thu Dec 22 12:58:38 2011
@@ -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 @@
     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 @@
     (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}}
   }
 }





More information about the cfe-commits mailing list