[cfe-commits] r150316 - in /cfe/trunk: lib/Parse/ParseExprCXX.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/cxx0x-initializer-constructor.cpp test/SemaCXX/cxx98-compat.cpp test/SemaCXX/generalized-initializers.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sat Feb 11 15:51:08 PST 2012


Author: cornedbee
Date: Sat Feb 11 17:51:08 2012
New Revision: 150316

URL: http://llvm.org/viewvc/llvm-project?rev=150316&view=rev
Log:
Fix parsing new expressions using init lists. Probably still do the wrong thing in cases involving array new.
Show that many cases using initializer list constructors work, in that they parse and pass semantic analysis.

Modified:
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
    cfe/trunk/test/SemaCXX/cxx98-compat.cpp
    cfe/trunk/test/SemaCXX/generalized-initializers.cpp

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=150316&r1=150315&r2=150316&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Sat Feb 11 17:51:08 2012
@@ -2182,8 +2182,10 @@
   } 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,

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=150316&r1=150315&r2=150316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Feb 11 17:51:08 2012
@@ -2750,6 +2750,76 @@
   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
@@ -2762,8 +2832,8 @@
 /// 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;
@@ -2796,9 +2866,17 @@
       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;

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=150316&r1=150315&r2=150316&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp Sat Feb 11 17:51:08 2012
@@ -3,6 +3,38 @@
 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); };
@@ -15,6 +47,19 @@
   };
 
   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, ""); }
     E(X1, int) { static_assert(N == 1, ""); }
@@ -26,6 +71,22 @@
     { 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}; }
   }
 
@@ -57,6 +118,8 @@
   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}}
@@ -77,5 +140,10 @@
     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
   }
 }

Modified: cfe/trunk/test/SemaCXX/cxx98-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx98-compat.cpp?rev=150316&r1=150315&r2=150316&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx98-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx98-compat.cpp Sat Feb 11 17:51:08 2012
@@ -39,7 +39,8 @@
 }
 
 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}}

Modified: cfe/trunk/test/SemaCXX/generalized-initializers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/generalized-initializers.cpp?rev=150316&r1=150315&r2=150316&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/generalized-initializers.cpp (original)
+++ cfe/trunk/test/SemaCXX/generalized-initializers.cpp Sat Feb 11 17:51:08 2012
@@ -38,89 +38,6 @@
   };
 }
 
-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





More information about the cfe-commits mailing list