[c++1z] P0217R3: Allow by-value structured binding of arrays.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Dec 2016 03:22:16 +0000 (03:22 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Dec 2016 03:22:16 +0000 (03:22 +0000)
llvm-svn: 289630

clang/include/clang/Sema/Initialization.h
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaInit.cpp
clang/test/CXX/dcl.decl/dcl.decomp/p2.cpp
clang/www/cxx_status.html

index ab108c8..c2795fc 100644 (file)
@@ -732,8 +732,9 @@ public:
     /// \brief Array initialization by elementwise copy.
     SK_ArrayLoopInit,
     /// \brief Array initialization (from an array rvalue).
-    /// This is a GNU C extension.
     SK_ArrayInit,
+    /// \brief Array initialization (from an array rvalue) as a GNU extension.
+    SK_GNUArrayInit,
     /// \brief Array initialization from a parenthesized initializer list.
     /// This is a GNU C++ extension.
     SK_ParenthesizedArrayInit,
@@ -1123,7 +1124,7 @@ public:
   void AddArrayInitLoopStep(QualType T, QualType EltTy);
 
   /// \brief Add an array initialization step.
-  void AddArrayInitStep(QualType T);
+  void AddArrayInitStep(QualType T, bool IsGNUExtension);
 
   /// \brief Add a parenthesized array initialization step.
   void AddParenthesizedArrayInitStep(QualType T);
index 15c664a..692853f 100644 (file)
@@ -9653,9 +9653,6 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
 
   VarDeclOrName VN{VDecl, Name};
 
-  // FIXME: Deduction for a decomposition declaration does weird things if the
-  // initializer is an array.
-
   ArrayRef<Expr *> DeduceInits = Init;
   if (DirectInit) {
     if (auto *PL = dyn_cast<ParenListExpr>(Init))
@@ -9704,6 +9701,15 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
     DefaultedAnyToId = true;
   }
 
+  // C++ [dcl.decomp]p1:
+  //   If the assignment-expression [...] has array type A and no ref-qualifier
+  //   is present, e has type cv A
+  if (VDecl && isa<DecompositionDecl>(VDecl) &&
+      Context.hasSameUnqualifiedType(Type, Context.getAutoDeductType()) &&
+      DeduceInit->getType()->isConstantArrayType())
+    return Context.getQualifiedType(DeduceInit->getType(),
+                                    Type.getQualifiers());
+
   QualType DeducedType;
   if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
     if (!IsInitCapture)
index 291feea..6ece7c8 100644 (file)
@@ -3068,6 +3068,7 @@ void InitializationSequence::Step::Destroy() {
   case SK_ArrayLoopIndex:
   case SK_ArrayLoopInit:
   case SK_ArrayInit:
+  case SK_GNUArrayInit:
   case SK_ParenthesizedArrayInit:
   case SK_PassByIndirectCopyRestore:
   case SK_PassByIndirectRestore:
@@ -3302,9 +3303,9 @@ void InitializationSequence::AddObjCObjectConversionStep(QualType T) {
   Steps.push_back(S);
 }
 
-void InitializationSequence::AddArrayInitStep(QualType T) {
+void InitializationSequence::AddArrayInitStep(QualType T, bool IsGNUExtension) {
   Step S;
-  S.Kind = SK_ArrayInit;
+  S.Kind = IsGNUExtension ? SK_GNUArrayInit : SK_ArrayInit;
   S.Type = T;
   Steps.push_back(S);
 }
@@ -5217,8 +5218,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
         canPerformArrayCopy(Entity)) {
       // If source is a prvalue, use it directly.
       if (Initializer->getValueKind() == VK_RValue) {
-        // FIXME: This produces a bogus extwarn
-        AddArrayInitStep(DestType);
+        AddArrayInitStep(DestType, /*IsGNUExtension*/false);
         return;
       }
 
@@ -5251,7 +5251,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
       else if (Initializer->HasSideEffects(S.Context))
         SetFailed(FK_NonConstantArrayInit);
       else {
-        AddArrayInitStep(DestType);
+        AddArrayInitStep(DestType, /*IsGNUExtension*/true);
       }
     }
     // Note: as a GNU C++ extension, we allow list-initialization of a
@@ -6520,6 +6520,7 @@ InitializationSequence::Perform(Sema &S,
   case SK_ArrayLoopIndex:
   case SK_ArrayLoopInit:
   case SK_ArrayInit:
+  case SK_GNUArrayInit:
   case SK_ParenthesizedArrayInit:
   case SK_PassByIndirectCopyRestore:
   case SK_PassByIndirectRestore:
@@ -7011,13 +7012,14 @@ InitializationSequence::Perform(Sema &S,
       break;
     }
 
-    case SK_ArrayInit:
+    case SK_GNUArrayInit:
       // Okay: we checked everything before creating this step. Note that
       // this is a GNU extension.
       S.Diag(Kind.getLocation(), diag::ext_array_init_copy)
         << Step->Type << CurInit.get()->getType()
         << CurInit.get()->getSourceRange();
-
+      LLVM_FALLTHROUGH;
+    case SK_ArrayInit:
       // If the destination type is an incomplete array type, update the
       // type accordingly.
       if (ResultType) {
@@ -7976,6 +7978,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
       OS << "array initialization";
       break;
 
+    case SK_GNUArrayInit:
+      OS << "array initialization (GNU extension)";
+      break;
+
     case SK_ParenthesizedArrayInit:
       OS << "parenthesized array initialization";
       break;
index 639aff6..211719a 100644 (file)
@@ -1,9 +1,20 @@
-// RUN: %clang_cc1 -std=c++1z -verify %s
+// RUN: %clang_cc1 -std=c++1z -verify %s -Wpedantic
+
+struct X {
+  X(int);
+  X(const X&) = delete;
+};
 
 int array() {
   static int arr[3] = {};
-  // FIXME: We are supposed to create an array object here and perform elementwise initialization.
-  auto [a, b, c] = arr; // expected-error {{cannot decompose non-class, non-array}}
+  auto [a, b, c] = arr;
+  static_assert(&a != &arr[0]);
+
+  using I3 = int[3];
+  auto [a2, b2, c2] = I3{1, 2, 3};
+
+  using X3 = X[3];
+  auto [a3, b3, c3] = X3{1, 2, 3};
 
   auto &[d, e] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but only 2 names were provided}}
   auto &[f, g, h, i] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but 4 names were provided}}
index 9e6b675..2e11566 100644 (file)
@@ -722,9 +722,7 @@ as the draft C++1z standard evolves.
     <tr>
       <td>Structured bindings</td>
       <td><a href="http://wg21.link/p0217r3">P0217R3</a></td>
-      <td class="partial" align="center">Partial</td>
-      <!-- We don't implement structured bindings of arrays yet, anticipating
-           this being removed from the working draft -->
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td>Separate variable and condition for <tt>if</tt> and <tt>switch</tt></td>