P0188R1: add support for standard [[fallthrough]] attribute. This is almost
exactly the same as clang's existing [[clang::fallthrough]] attribute, which
has been updated to have the same semantics. The one significant difference
is that [[fallthrough]] is ill-formed if it's not used immediately before a
switch label (even when -Wimplicit-fallthrough is disabled). To support that,
we now build a CFG of any function that uses a '[[fallthrough]];' statement
to check.
In passing, fix some bugs with our support for statement attributes -- in
particular, diagnose their use on declarations, rather than asserting.
llvm-svn: 262881
diff --git a/clang/test/Analysis/cxx11-crashes.cpp b/clang/test/Analysis/cxx11-crashes.cpp
index 3c33de3..c6034e6 100644
--- a/clang/test/Analysis/cxx11-crashes.cpp
+++ b/clang/test/Analysis/cxx11-crashes.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -std=c++11 -verify %s
-// expected-no-diagnostics
// radar://11485149, PR12871
class PlotPoint {
@@ -91,6 +90,6 @@
void fallthrough() {
switch (1) {
case 1:
- [[clang::fallthrough]];
+ [[clang::fallthrough]]; // expected-error {{does not directly precede}}
}
}
diff --git a/clang/test/PCH/Inputs/cxx11-statement-attributes.h b/clang/test/PCH/Inputs/cxx11-statement-attributes.h
index f4d0619..3f85e1f 100644
--- a/clang/test/PCH/Inputs/cxx11-statement-attributes.h
+++ b/clang/test/PCH/Inputs/cxx11-statement-attributes.h
@@ -7,7 +7,8 @@
[[clang::fallthrough]]; // This shouldn't generate a warning.
case 1:
n += 20;
- [[clang::fallthrough]]; // This should generate a warning: "fallthrough annotation does not directly precede switch label".
+ case 2: // This should generate a warning: "unannotated fallthrough"
+ n += 35;
break;
}
return n;
diff --git a/clang/test/PCH/cxx11-statement-attributes.cpp b/clang/test/PCH/cxx11-statement-attributes.cpp
index 722ca6e..b5dfc6c 100644
--- a/clang/test/PCH/cxx11-statement-attributes.cpp
+++ b/clang/test/PCH/cxx11-statement-attributes.cpp
@@ -1,10 +1,15 @@
// Sanity check.
// RUN: %clang_cc1 -include %S/Inputs/cxx11-statement-attributes.h -std=c++11 -Wimplicit-fallthrough -fsyntax-only %s -o - -verify
+// RUN: %clang_cc1 -include %S/Inputs/cxx11-statement-attributes.h -std=c++1z -Wimplicit-fallthrough -fsyntax-only %s -o - -verify
// Run the same tests, this time with the attributes loaded from the PCH file.
// RUN: %clang_cc1 -x c++-header -emit-pch -std=c++11 -o %t %S/Inputs/cxx11-statement-attributes.h
// RUN: %clang_cc1 -include-pch %t -std=c++11 -Wimplicit-fallthrough -fsyntax-only %s -o - -verify
+// RUN: %clang_cc1 -x c++-header -emit-pch -std=c++1z -o %t %S/Inputs/cxx11-statement-attributes.h
+// RUN: %clang_cc1 -include-pch %t -std=c++1z -Wimplicit-fallthrough -fsyntax-only %s -o - -verify
-// expected-warning@Inputs/cxx11-statement-attributes.h:10 {{fallthrough annotation does not directly precede switch label}}
+// expected-warning@Inputs/cxx11-statement-attributes.h:10 {{unannotated fall-through}}
+// expected-note-re@Inputs/cxx11-statement-attributes.h:10 {{insert '[[{{(clang::)?}}fallthrough]];'}}
+// expected-note@Inputs/cxx11-statement-attributes.h:10 {{insert 'break;'}}
void g(int n) {
f<1>(n); // expected-note {{in instantiation of function template specialization 'f<1>' requested here}}
diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp
index 7eec5761..c032e47 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++1z-extensions %s
// Need std::initializer_list
namespace std {
@@ -347,6 +347,18 @@
]] void bad();
}
+int fallthru(int n) {
+ switch (n) {
+ case 0:
+ n += 5;
+ [[fallthrough]]; // expected-warning {{use of the 'fallthrough' attribute is a C++1z extension}}
+ case 1:
+ n *= 2;
+ break;
+ }
+ return n;
+}
+
#define attr_name bitand
#define attr_name_2(x) x
#define attr_name_3(x, y) x##y
diff --git a/clang/test/SemaCXX/for-range-examples.cpp b/clang/test/SemaCXX/for-range-examples.cpp
index 9359ae6..83023e3 100644
--- a/clang/test/SemaCXX/for-range-examples.cpp
+++ b/clang/test/SemaCXX/for-range-examples.cpp
@@ -226,7 +226,7 @@
// we check the alignment attribute before we perform the auto
// deduction.
for (d alignas(1) : arr) {} // expected-error {{requires type for loop variable}}
- for (e [[deprecated]] : arr) { e = 0; } // expected-warning{{use of the 'deprecated' attribute is a C++14 extension}} expected-warning {{deprecated}} expected-note {{here}} expected-error {{requires type for loop variable}}
+ for (e [[deprecated]] : arr) { e = 0; } // expected-warning {{deprecated}} expected-note {{here}} expected-error {{requires type for loop variable}}
}
}
diff --git a/clang/test/SemaCXX/generalized-deprecated.cpp b/clang/test/SemaCXX/generalized-deprecated.cpp
index 8fa20d0..43efea1 100644
--- a/clang/test/SemaCXX/generalized-deprecated.cpp
+++ b/clang/test/SemaCXX/generalized-deprecated.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -fms-extensions -Wno-deprecated %s
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -fms-extensions -Wno-deprecated -Wc++14-extensions %s
// NOTE: use -Wno-deprecated to avoid cluttering the output with deprecated
// warnings
diff --git a/clang/test/SemaCXX/nodiscard.cpp b/clang/test/SemaCXX/nodiscard.cpp
index 5fa4177..e53cf9b 100644
--- a/clang/test/SemaCXX/nodiscard.cpp
+++ b/clang/test/SemaCXX/nodiscard.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify -Wc++1z-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT -Wc++1z-extensions %s
#if !defined(EXT)
static_assert(__has_cpp_attribute(nodiscard) == 201603);
diff --git a/clang/test/SemaCXX/switch-implicit-fallthrough-macro.cpp b/clang/test/SemaCXX/switch-implicit-fallthrough-macro.cpp
index add212f..11df2cb 100644
--- a/clang/test/SemaCXX/switch-implicit-fallthrough-macro.cpp
+++ b/clang/test/SemaCXX/switch-implicit-fallthrough-macro.cpp
@@ -1,4 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wimplicit-fallthrough -DCOMMAND_LINE_FALLTHROUGH=[[clang::fallthrough]] %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wimplicit-fallthrough -DCLANG_PREFIX -DCOMMAND_LINE_FALLTHROUGH=[[clang::fallthrough]] -DUNCHOSEN=[[fallthrough]] %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wimplicit-fallthrough -DCOMMAND_LINE_FALLTHROUGH=[[fallthrough]] %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z -Wimplicit-fallthrough -DCLANG_PREFIX -DCOMMAND_LINE_FALLTHROUGH=[[clang::fallthrough]] %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z -Wimplicit-fallthrough -DCOMMAND_LINE_FALLTHROUGH=[[clang::fallthrough]] %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z -Wimplicit-fallthrough -DCOMMAND_LINE_FALLTHROUGH=[[fallthrough]] -DUNCHOSEN=[[clang::fallthrough]] %s
int fallthrough_compatibility_macro_from_command_line(int n) {
switch (n) {
@@ -10,15 +14,12 @@
return n;
}
-#ifdef __clang__
-#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#ifdef CLANG_PREFIX
#define COMPATIBILITY_FALLTHROUGH [ [ /* test */ clang /* test */ \
:: fallthrough ] ] // testing whitespace and comments in macro definition
-#endif
-#endif
-
-#ifndef COMPATIBILITY_FALLTHROUGH
-#define COMPATIBILITY_FALLTHROUGH do { } while (0)
+#else
+#define COMPATIBILITY_FALLTHROUGH [ [ /* test */ /* test */ \
+ fallthrough ] ] // testing whitespace and comments in macro definition
#endif
int fallthrough_compatibility_macro_from_source(int n) {
@@ -32,7 +33,11 @@
}
// Deeper macro substitution
+#ifdef CLANG_PREFIX
#define M1 [[clang::fallthrough]]
+#else
+#define M1 [[fallthrough]]
+#endif
#ifdef __clang__
#define M2 M1
#else
@@ -59,12 +64,17 @@
#undef M2
#undef COMPATIBILITY_FALLTHROUGH
#undef COMMAND_LINE_FALLTHROUGH
+#undef UNCHOSEN
int fallthrough_compatibility_macro_undefined(int n) {
switch (n) {
case 0:
n = n * 20;
+#if __cplusplus <= 201402L
case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+#else
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+#endif
;
}
#define TOO_LATE [[clang::fallthrough]]
@@ -83,7 +93,11 @@
case 0:
n = n * 20;
#undef MACRO_WITH_HISTORY
+#if __cplusplus <= 201402L
case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+#else
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+#endif
;
#define MACRO_WITH_HISTORY [[clang::fallthrough]]
}
diff --git a/clang/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp b/clang/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
index 009c818..6880bdd 100644
--- a/clang/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
+++ b/clang/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
@@ -41,9 +41,8 @@
void unscoped(int n) {
switch (n % 2) {
case 0:
- // FIXME: This should be typo-corrected, probably.
- [[fallthrough]]; // expected-warning{{unknown attribute 'fallthrough' ignored}}
- case 2: // expected-warning{{unannotated fall-through}} expected-note{{clang::fallthrough}} expected-note{{break;}}
+ [[fallthrough]];
+ case 2:
[[clang::fallthrough]];
case 1:
break;
diff --git a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp
index 0bc43cd..9540b1f 100644
--- a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp
+++ b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp
@@ -179,18 +179,15 @@
int fallthrough_position(int n) {
switch (n) {
- [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
n += 300;
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
case 221:
- [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
return 1;
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
case 222:
- [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
n += 400;
case 223: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
- [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
+ ;
}
long p = static_cast<long>(n) * n;
@@ -282,6 +279,23 @@
}
}
+int fallthrough_placement_error(int n) {
+ switch (n) {
+ [[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
+ n += 300;
+ case 221:
+ [[clang::fallthrough]]; // expected-error{{fallthrough annotation does not directly precede switch label}}
+ return 1;
+ case 222:
+ [[clang::fallthrough]]; // expected-error{{fallthrough annotation does not directly precede switch label}}
+ n += 400;
+ [[clang::fallthrough]];
+ case 223:
+ [[clang::fallthrough]]; // expected-error{{fallthrough annotation does not directly precede switch label}}
+ }
+ return n;
+}
+
int fallthrough_targets(int n) {
[[clang::fallthrough]]; // expected-error{{fallthrough annotation is outside switch statement}}