[cxx2a] P0614R1: Support init-statements in range-based for loops.

We don't yet support this for the case where a range-based for loop is
implicitly rewritten to an ObjC for..in statement.

llvm-svn: 343350
diff --git a/clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist b/clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
index 040c66a..9afb805 100644
--- a/clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
+++ b/clang/test/Analysis/Inputs/expected-plists/cxx-for-range.cpp.plist
@@ -1670,6 +1670,287 @@
    </array>
   </dict>
   </dict>
+  <dict>
+   <key>path</key>
+   <array>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>102</integer>
+      <key>col</key><integer>8</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>8</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>15</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Initializing to a null pointer value</string>
+     <key>message</key>
+     <string>Initializing to a null pointer value</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>10</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>102</integer>
+      <key>col</key><integer>58</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>58</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>58</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Entering loop body</string>
+     <key>message</key>
+     <string>Entering loop body</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>58</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>51</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>53</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>102</integer>
+      <key>col</key><integer>51</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>51</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>102</integer>
+         <key>col</key><integer>56</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>&apos;p&apos; initialized to a null pointer value</string>
+     <key>message</key>
+     <string>&apos;p&apos; initialized to a null pointer value</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>51</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>102</integer>
+           <key>col</key><integer>53</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>103</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>103</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>103</integer>
+      <key>col</key><integer>8</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>103</integer>
+         <key>col</key><integer>6</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>103</integer>
+         <key>col</key><integer>6</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+     <key>message</key>
+     <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+    </dict>
+   </array>
+   <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+   <key>category</key><string>Logic error</string>
+   <key>type</key><string>Dereference of null pointer</string>
+   <key>check_name</key><string>core.NullDereference</string>
+   <!-- This hash is experimental and going to change! -->
+   <key>issue_hash_content_of_line_in_context</key><string>ad377f8d4510dfd77d6485c402d57a2d</string>
+  <key>issue_context_kind</key><string>function</string>
+  <key>issue_context</key><string>testForRangeInit</string>
+  <key>issue_hash_function_offset</key><string>2</string>
+  <key>location</key>
+  <dict>
+   <key>line</key><integer>103</integer>
+   <key>col</key><integer>8</integer>
+   <key>file</key><integer>0</integer>
+  </dict>
+  <key>ExecutedLines</key>
+  <dict>
+   <key>0</key>
+   <array>
+    <integer>101</integer>
+    <integer>102</integer>
+    <integer>103</integer>
+   </array>
+  </dict>
+  </dict>
  </array>
  <key>files</key>
  <array>
diff --git a/clang/test/Analysis/cxx-for-range.cpp b/clang/test/Analysis/cxx-for-range.cpp
index d9ea1c1..8bcad89 100644
--- a/clang/test/Analysis/cxx-for-range.cpp
+++ b/clang/test/Analysis/cxx-for-range.cpp
@@ -97,3 +97,8 @@
 
   *(volatile int *)0 = 1; // no-warning
 }
+
+void testForRangeInit() {
+  for (int *arr[3] = {nullptr, nullptr, nullptr}; int *p : arr) // expected-warning {{extension}}
+    *p = 1; // expected-warning {{Dereference of null pointer}}
+}
diff --git a/clang/test/Analysis/scopes-cfg-output.cpp b/clang/test/Analysis/scopes-cfg-output.cpp
index 0f2201a..f8d84b6 100644
--- a/clang/test/Analysis/scopes-cfg-output.cpp
+++ b/clang/test/Analysis/scopes-cfg-output.cpp
@@ -820,10 +820,9 @@
 // CHECK-NEXT:   3: __end1
 // CHECK-NEXT:   4: [B2.3] (ImplicitCastExpr, LValueToRValue, class A *)
 // CHECK-NEXT:   5: [B2.2] != [B2.4]
-// CHECK-NEXT:   T: for (auto &i : [B5.4]) {
+// CHECK-NEXT:   T: for (auto &i : [B5.4])
 // CHECK:         [B4.11];
-// CHECK-NEXT:}
-// CHECK-NEXT:   Preds (2): B3 B5
+// CHECK:        Preds (2): B3 B5
 // CHECK-NEXT:   Succs (2): B4 B1
 // CHECK:      [B3]
 // CHECK-NEXT:   1: __begin1
diff --git a/clang/test/CodeGenCXX/cxx2a-init-statement.cpp b/clang/test/CodeGenCXX/cxx2a-init-statement.cpp
new file mode 100644
index 0000000..eb48d4a
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2a-init-statement.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++2a -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
+
+// CHECK: @_ZZ1fvE3arr = private unnamed_addr constant [3 x i32] [i32 1, i32 2, i32 3], align 4
+
+void f() {
+  // CHECK: %[[ARR:.*]] = alloca [3 x i32], align 4
+  // CHECK: call void @llvm.memcpy{{.*}}({{.*}} @_ZZ1fvE3arr
+  for (int arr[3] = {1, 2, 3}; int a : arr)
+    ;
+}
diff --git a/clang/test/Import/cxx-for-range/Inputs/F.cpp b/clang/test/Import/cxx-for-range/Inputs/F.cpp
index 700feb0..26a3a4e 100644
--- a/clang/test/Import/cxx-for-range/Inputs/F.cpp
+++ b/clang/test/Import/cxx-for-range/Inputs/F.cpp
@@ -4,8 +4,7 @@
 };
 
 void f() {
-  Container c;
-  for (int varname : c) {
+  for (Container c; int varname : c) {
     return;
   }
 }
diff --git a/clang/test/Import/cxx-for-range/test.cpp b/clang/test/Import/cxx-for-range/test.cpp
index 1c9d40c..019fc20 100644
--- a/clang/test/Import/cxx-for-range/test.cpp
+++ b/clang/test/Import/cxx-for-range/test.cpp
@@ -4,6 +4,11 @@
 
 // CHECK-NEXT: DeclStmt
 // CHECK-NEXT: VarDecl
+// CHECK-SAME: c 'Container'
+// CHECK-NEXT: CXXConstructExpr
+
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl
 // CHECK-NEXT: DeclRefExpr
 // CHECK-SAME: 'c'
 // CHECK-SAME: Container
diff --git a/clang/test/PCH/cxx2a-for-init-statement.cpp b/clang/test/PCH/cxx2a-for-init-statement.cpp
new file mode 100644
index 0000000..2147c0f
--- /dev/null
+++ b/clang/test/PCH/cxx2a-for-init-statement.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-pch -std=c++2a -o %t %s
+// RUN: %clang_cc1 -std=c++2a -x ast -ast-print %t | FileCheck %s
+
+void f() {
+  // CHECK:      for (int arr[3]; int n : arr) {
+  // CHECK-NEXT: }
+  for (int arr[3]; int n : arr) {}
+}
diff --git a/clang/test/Parser/cxx2a-init-statement.cpp b/clang/test/Parser/cxx2a-init-statement.cpp
new file mode 100644
index 0000000..3b1862f
--- /dev/null
+++ b/clang/test/Parser/cxx2a-init-statement.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+template<int N> struct A {};
+
+using F = bool(*)(int);
+extern F *p;
+extern int m;
+
+struct Convertible { template<typename T> operator T(); };
+
+void f() {
+  int arr1[3];
+  for (int n = 5; int x : arr1) {}
+
+  int A<0>::*arr2[3];
+  for (int n = 5; int A<true ? 0 : 1>::*x : arr2) {}
+
+  F (*arr3[3])(int);
+  for (int n = 5; F (*p)(int n) : arr3) {}
+  for (int n = 5; F (*p)(int (n)) : arr3) {}
+
+  // Here, we have a declaration rather than an expression.
+  for (int n = 5; F (*p)(int (n)); ++n) {}
+
+  // We detect whether we have a for-range-declaration before parsing so that
+  // we can give different diagnostics for for-range-declarations versus
+  // conditions (even though the rules are currently identical).
+  Convertible arr4[3];
+  for (int n = 0; struct { operator bool(); } x = {}; ++n) {} // expected-error {{cannot be defined in a condition}}
+  for (int n = 0; struct { operator bool(); } x : arr4) {} // expected-error {{may not be defined in a for range declaration}}
+
+  for (int n = 0; static int m = 0; ++n) {} // expected-error {{type name does not allow storage class}}
+  for (int n = 0; static int m : arr1) {} // expected-error {{loop variable 'm' may not be declared 'static'}}
+}
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 18c4a72..bb2a4a0 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -204,3 +204,10 @@
                            std::strong_equality::nonequal));
 // TODO: defaulted operator <=>
 } // namespace ThreeWayComparison
+
+constexpr bool for_range_init() {
+  int k = 0;
+  for (int arr[3] = {1, 2, 3}; int n : arr) k += n;
+  return k == 6;
+}
+static_assert(for_range_init());
diff --git a/clang/test/SemaCXX/cxx17-compat.cpp b/clang/test/SemaCXX/cxx17-compat.cpp
index 93e052f..eee9c23 100644
--- a/clang/test/SemaCXX/cxx17-compat.cpp
+++ b/clang/test/SemaCXX/cxx17-compat.cpp
@@ -54,3 +54,12 @@
     // expected-warning@-4 {{explicitly defaulting this copy constructor with a type different from the implicit type is incompatible with C++ standards before C++2a}}
 #endif
 };
+
+void ForRangeInit() {
+  for (int arr[3] = {1, 2, 3}; int n : arr) {}
+#if __cplusplus <= 201703L
+    // expected-warning@-2 {{range-based for loop initialization statements are a C++2a extension}}
+#else
+    // expected-warning@-4 {{range-based for loop initialization statements are incompatible with C++ standards before C++2a}}
+#endif
+}
diff --git a/clang/test/SemaObjCXX/foreach.mm b/clang/test/SemaObjCXX/foreach.mm
index 99f5d0c..e39815d 100644
--- a/clang/test/SemaObjCXX/foreach.mm
+++ b/clang/test/SemaObjCXX/foreach.mm
@@ -14,6 +14,14 @@
   for (auto thisKey : keys) { } // expected-warning{{'auto' deduced as 'id' in declaration of 'thisKey'}}
 }
 
+void for_init_stmt() {
+  for (id keys; id key : keys) {} // expected-warning{{extension}} expected-error{{not supported}}
+}
+template<typename T> void for_init_stmt_tmpl() {
+  for (T keys; id key : keys) {} // expected-warning{{extension}} expected-error{{not supported}}
+}
+template void for_init_stmt_tmpl<id>(); // expected-note {{in instantiation of}}
+
 template<typename Collection>
 void ft(Collection col) {
   for (id x : col) { }