r227022 - First steps in implementing DR1467: List-initialization of aggregate from same-type object.

Larisse Voufo lvoufo at google.com
Sat Jan 24 15:09:54 PST 2015


Author: lvoufo
Date: Sat Jan 24 17:09:54 2015
New Revision: 227022

URL: http://llvm.org/viewvc/llvm-project?rev=227022&view=rev
Log:
First steps in implementing DR1467: List-initialization of aggregate from same-type object.
Only the first two items for now, changing Sections 8.5.4 [dcl.init.list] paragraph 3 and 13.3.1.7 [over.match.list] paragraph 1,
so that defining class objects and character arrays using uniform initialization syntax is actually treated as list initialization
and before it is treated aggregate initialization.

Modified:
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/CXX/drs/dr14xx.cpp

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=227022&r1=227021&r2=227022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Sat Jan 24 17:09:54 2015
@@ -3222,9 +3222,16 @@ static void TryConstructorInitialization
   OverloadCandidateSet::iterator Best;
   bool AsInitializerList = false;
 
+  // C++14 DR 1467 [over.match.list]p1:
+  //   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.
@@ -3425,42 +3432,88 @@ static void TryListInitialization(Sema &
     TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence);
     return;
   }
-  if (DestType->isRecordType()) {
-    if (S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) {
-      Sequence.setIncompleteTypeFailure(DestType);
-      return;
-    }
 
-    // C++11 [dcl.init.list]p3:
-    //   - If T is an aggregate, aggregate initialization is performed.
-    if (!DestType->isAggregateType()) {
-      if (S.getLangOpts().CPlusPlus11) {
-        //   - Otherwise, if the initializer list has no elements and T is a
-        //     class type with a default constructor, the object is
-        //     value-initialized.
-        if (InitList->getNumInits() == 0) {
-          CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
-          if (RD->hasDefaultConstructor()) {
-            TryValueInitialization(S, Entity, Kind, Sequence, InitList);
-            return;
-          }
-        }
-
-        //   - Otherwise, if T is a specialization of std::initializer_list<E>,
-        //     an initializer_list object constructed [...]
-        if (TryInitializerListConstruction(S, InitList, DestType, Sequence))
-          return;
+  if (DestType->isRecordType() &&
+      S.RequireCompleteType(InitList->getLocStart(), DestType, 0)) {
+    Sequence.setIncompleteTypeFailure(DestType);
+    return;
+  }
 
-        //   - Otherwise, if T is a class type, constructors are considered.
+  // C++14 DR1467 [dcl.init.list]p3:
+  // - 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
+  //   copy-list-initialization, or by direct-initialization for
+  //   direct-list-initialization).
+  // - Otherwise, if T 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]), initialization is performed as described
+  //   in that section.
+  // - Otherwise, If T is an aggregate, [...] (continue below).
+  if (S.getLangOpts().CPlusPlus14 && InitList->getNumInits() == 1) {
+    if (DestType->isRecordType()) {
+      QualType InitType = InitList->getInit(0)->getType();
+      if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||
+          S.IsDerivedFrom(InitType, DestType)) {
         Expr *InitListAsExpr = InitList;
         TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
                                      Sequence, /*InitListSyntax*/true);
-      } else
-        Sequence.SetFailed(
-            InitializationSequence::FK_InitListBadDestinationType);
-      return;
+        return;
+      }
+    }
+    if (const ArrayType *DestAT = S.Context.getAsArrayType(DestType)) {
+      Expr *SubInit[1] = {InitList->getInit(0)};
+      if (!isa<VariableArrayType>(DestAT) &&
+          IsStringInit(SubInit[0], DestAT, S.Context) == SIF_None) {
+        InitializationKind SubKind =
+            Kind.getKind() == InitializationKind::IK_DirectList
+                ? InitializationKind::CreateDirect(Kind.getLocation(),
+                                                   InitList->getLBraceLoc(),
+                                                   InitList->getRBraceLoc())
+                : Kind;
+        Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
+                                /*TopLevelOfInitList*/ true);
+
+        // TryStringLiteralInitialization() (in InitializeFrom()) will fail if
+        // the element is not an appropriately-typed string literal, in which
+        // case we should proceed as in C++11 (below).
+        if (Sequence) {
+          Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+          return;
+        }
+      }
     }
   }
+
+  // C++11 [dcl.init.list]p3:
+  //   - If T is an aggregate, aggregate initialization is performed.
+  if (DestType->isRecordType() && !DestType->isAggregateType()) {
+    if (S.getLangOpts().CPlusPlus11) {
+      //   - Otherwise, if the initializer list has no elements and T is a
+      //     class type with a default constructor, the object is
+      //     value-initialized.
+      if (InitList->getNumInits() == 0) {
+        CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
+        if (RD->hasDefaultConstructor()) {
+          TryValueInitialization(S, Entity, Kind, Sequence, InitList);
+          return;
+        }
+      }
+
+      //   - Otherwise, if T is a specialization of std::initializer_list<E>,
+      //     an initializer_list object constructed [...]
+      if (TryInitializerListConstruction(S, InitList, DestType, Sequence))
+        return;
+
+      //   - Otherwise, if T is a class type, constructors are considered.
+      Expr *InitListAsExpr = InitList;
+      TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
+                                   Sequence, /*InitListSyntax*/ true);
+    } else
+      Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
+    return;
+  }
+
   if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&
       InitList->getNumInits() == 1 &&
       InitList->getInit(0)->getType()->isRecordType()) {
@@ -3469,6 +3522,14 @@ static void TryListInitialization(Sema &
     //     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
+    //     to convert the element to T, the program is ill-formed.
+    //
     // Per core-24034, this is direct-initialization if we were performing
     // direct-list-initialization and copy-initialization otherwise.
     // We can't use InitListChecker for this, because it always performs
@@ -4408,8 +4469,7 @@ static void checkIndirectCopyRestoreSour
 
 /// \brief Determine whether we have compatible array types for the
 /// purposes of GNU by-copy array initialization.
-static bool hasCompatibleArrayTypes(ASTContext &Context,
-                                    const ArrayType *Dest, 
+static bool hasCompatibleArrayTypes(ASTContext &Context, const ArrayType *Dest,
                                     const ArrayType *Source) {
   // If the source and destination array types are equivalent, we're
   // done.
@@ -4668,7 +4728,7 @@ void InitializationSequence::InitializeF
     return;
   }
 
-  // Determine whether we should consider writeback conversions for 
+  // Determine whether we should consider writeback conversions for
   // Objective-C ARC.
   bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount &&
          Entity.isParameterKind();

Modified: cfe/trunk/test/CXX/drs/dr14xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr14xx.cpp?rev=227022&r1=227021&r2=227022&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr14xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr14xx.cpp Sat Jan 24 17:09:54 2015
@@ -195,3 +195,126 @@ namespace dr1460 { // dr1460: 3.5
   }
 #endif
 }
+
+#if __cplusplus >= 201103L
+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_;}
+  };
+} // std
+
+namespace dr1467 {
+  // List-initialization of aggregate from same-type object
+  
+  namespace basic0 {
+    
+    struct S {
+      int i = 42;
+    };
+    
+    S a;
+    S b(a);
+    S c{a};
+    
+    struct SS : public S { } x;
+    S y(x);
+    S z{x};
+    
+  } // basic0
+  
+  namespace basic1 {
+    
+    struct S {
+      int i{42};
+    };
+    
+    S a;
+    S b(a);
+    S c{a};
+    
+    struct SS : public S { } x;
+    S y(x);
+    S z{x};
+    
+  } // basic1
+  
+  namespace basic2 {
+    
+    struct S {
+      int i = {42};
+    };
+    
+    S a;
+    S b(a);
+    S c{a};
+    
+    struct SS : public S { } x;
+    S y(x);
+    S z{x};
+    
+  } // basic2
+  
+  namespace dr_example {
+    struct OK {
+      OK() = default;
+      OK(const OK&) = default;
+      OK(int) { }
+    };
+    
+    OK ok;
+    OK ok2{ok};
+    
+    
+    struct X {
+      X() = default;
+      X(const X&) = default;
+    };
+    
+    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
+
+} // dr1467
+
+
+namespace dr1490 {
+  // List-initialization from a string literal
+  
+  char s[4]{"abc"};                   // Ok
+  std::initializer_list<char>{"abc"}; // expected-error {{expected unqualified-id}}}
+  
+} // dr1490
+#endif





More information about the cfe-commits mailing list