[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>'p' initialized to a null pointer value</string>
+ <key>message</key>
+ <string>'p' 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 'p')</string>
+ <key>message</key>
+ <string>Dereference of null pointer (loaded from variable 'p')</string>
+ </dict>
+ </array>
+ <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</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) { }