summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-03-08 00:32:55 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-03-08 00:32:55 +0000
commit14b538d62de9e8d256c8457c7580d6d9e0ba16f7 (patch)
tree10f30ff3c9c9e65510a8ca0d90ac328001efd845
parent3827f56644bb23fb687e722860b61e59641adedb (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@262881 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Attr.h13
-rw-r--r--include/clang/Basic/Attr.td8
-rw-r--r--include/clang/Basic/AttrDocs.td9
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td21
-rw-r--r--include/clang/Sema/AttributeList.h1
-rw-r--r--include/clang/Sema/ScopeInfo.h8
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp43
-rw-r--r--lib/Sema/AttributeList.cpp5
-rw-r--r--lib/Sema/SemaDeclAttr.cpp13
-rw-r--r--lib/Sema/SemaStmtAttr.cpp20
-rw-r--r--test/Analysis/cxx11-crashes.cpp3
-rw-r--r--test/PCH/Inputs/cxx11-statement-attributes.h3
-rw-r--r--test/PCH/cxx11-statement-attributes.cpp7
-rw-r--r--test/Parser/cxx0x-attributes.cpp14
-rw-r--r--test/SemaCXX/for-range-examples.cpp2
-rw-r--r--test/SemaCXX/generalized-deprecated.cpp2
-rw-r--r--test/SemaCXX/nodiscard.cpp4
-rw-r--r--test/SemaCXX/switch-implicit-fallthrough-macro.cpp30
-rw-r--r--test/SemaCXX/switch-implicit-fallthrough-per-method.cpp5
-rw-r--r--test/SemaCXX/switch-implicit-fallthrough.cpp22
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp2
-rw-r--r--www/cxx_status.html2
22 files changed, 178 insertions, 59 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 4d864edf6a..1ff6abfbbb 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -118,6 +118,19 @@ public:
bool duplicatesAllowed() const { return DuplicatesAllowed; }
};
+class StmtAttr : public Attr {
+protected:
+ StmtAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
+ bool IsLateParsed, bool DuplicatesAllowed)
+ : Attr(AK, R, SpellingListIndex, IsLateParsed, DuplicatesAllowed) {}
+
+public:
+ static bool classof(const Attr *A) {
+ return A->getKind() >= attr::FirstStmtAttr &&
+ A->getKind() <= attr::LastStmtAttr;
+ }
+};
+
class InheritableAttr : public Attr {
protected:
InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 4ab7c0294b..391d042681 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -311,6 +311,9 @@ class TypeAttr : Attr {
let ASTNode = 0;
}
+/// A stmt attribute is not processed on a declaration or a type.
+class StmtAttr : Attr;
+
/// An inheritable attribute is inherited by later redeclarations.
class InheritableAttr : Attr;
@@ -738,8 +741,9 @@ def ExtVectorType : Attr {
let Documentation = [Undocumented];
}
-def FallThrough : Attr {
- let Spellings = [CXX11<"clang", "fallthrough">];
+def FallThrough : StmtAttr {
+ let Spellings = [CXX11<"", "fallthrough", 201503>,
+ CXX11<"clang", "fallthrough">];
// let Subjects = [NullStmt];
let Documentation = [FallthroughDocs];
}
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index 5de6b19271..97cb9b2c20 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -756,9 +756,10 @@ potentially-evaluated discarded-value expression that is not explicitly cast to
def FallthroughDocs : Documentation {
let Category = DocCatStmt;
+ let Heading = "fallthrough, clang::fallthrough";
let Content = [{
-The ``clang::fallthrough`` attribute is used along with the
-``-Wimplicit-fallthrough`` argument to annotate intentional fall-through
+The ``fallthrough`` (or ``clang::fallthrough``) attribute is used
+to annotate intentional fall-through
between switch labels. It can only be applied to a null statement placed at a
point of execution between any statement and the next switch label. It is
common to mark these places with a specific comment, but this attribute is
@@ -769,6 +770,10 @@ control-flow statements like ``break;``, so it can be placed in most places
where ``break;`` can, but only if there are no statements on the execution path
between it and the next switch label.
+By default, Clang does not warn on unannotated fallthrough from one ``switch``
+case to another. Diagnostics on fallthrough without a corresponding annotation
+can be enabled with the ``-Wimplicit-fallthrough`` argument.
+
Here is an example:
.. code-block:: c++
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index e76be07ff5..9c3ebcadbc 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2358,8 +2358,10 @@ def warn_cxx11_gnu_attribute_on_type : Warning<
def warn_unhandled_ms_attribute_ignored : Warning<
"__declspec attribute %0 is not supported">,
InGroup<IgnoredAttributes>;
-def err_attribute_invalid_on_stmt : Error<
+def err_decl_attribute_invalid_on_stmt : Error<
"%0 attribute cannot be applied to a statement">;
+def err_stmt_attribute_invalid_on_decl : Error<
+ "%0 attribute cannot be applied to a declaration">;
def warn_declspec_attribute_ignored : Warning<
"attribute %0 is ignored, place it after "
"\"%select{class|struct|interface|union|enum}1\" to apply attribute to "
@@ -6592,8 +6594,11 @@ def warn_unused_result : Warning<
def warn_unused_volatile : Warning<
"expression result unused; assign into a variable to force a volatile load">,
InGroup<DiagGroup<"unused-volatile-lvalue">>;
-def ext_nodiscard_attr_is_a_cxx1z_extension : ExtWarn<
- "use of the 'nodiscard' attribute is a C++1z extension">, InGroup<CXX1z>;
+
+def ext_cxx14_attr : Extension<
+ "use of the %0 attribute is a C++14 extension">, InGroup<CXX14>;
+def ext_cxx1z_attr : Extension<
+ "use of the %0 attribute is a C++1z extension">, InGroup<CXX1z>;
def warn_unused_comparison : Warning<
"%select{%select{|in}1equality|relational}0 comparison result unused">,
@@ -7306,13 +7311,12 @@ def note_insert_fallthrough_fixit : Note<
def note_insert_break_fixit : Note<
"insert 'break;' to avoid fall-through">;
def err_fallthrough_attr_wrong_target : Error<
- "clang::fallthrough attribute is only allowed on empty statements">;
+ "%0 attribute is only allowed on empty statements">;
def note_fallthrough_insert_semi_fixit : Note<"did you forget ';'?">;
def err_fallthrough_attr_outside_switch : Error<
"fallthrough annotation is outside switch statement">;
-def warn_fallthrough_attr_invalid_placement : Warning<
- "fallthrough annotation does not directly precede switch label">,
- InGroup<ImplicitFallthrough>;
+def err_fallthrough_attr_invalid_placement : Error<
+ "fallthrough annotation does not directly precede switch label">;
def warn_fallthrough_attr_unreachable : Warning<
"fallthrough annotation in unreachable code">,
InGroup<ImplicitFallthrough>;
@@ -7678,9 +7682,6 @@ def err_asm_naked_this_ref : Error<
def err_asm_naked_parm_ref : Error<
"parameter references not allowed in naked functions">;
-def ext_deprecated_attr_is_a_cxx14_extension : ExtWarn<
- "use of the 'deprecated' attribute is a C++14 extension">, InGroup<CXX14>;
-
// OpenCL warnings and errors.
def err_invalid_astype_of_different_size : Error<
"invalid reinterpretation: sizes of %0 and %1 must match">;
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index cfa3c0d170..8a0fbf23fe 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -491,6 +491,7 @@ public:
bool isTargetSpecificAttr() const;
bool isTypeAttr() const;
+ bool isStmtAttr() const;
bool hasCustomParsing() const;
unsigned getMinArgs() const;
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 881091f1a5..30047cddf2 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -107,6 +107,9 @@ public:
/// \brief True if current scope is for OpenMP declare reduction combiner.
bool HasOMPDeclareReductionCombiner;
+ /// \brief Whether there is a fallthrough statement in this function.
+ bool HasFallthroughStmt : 1;
+
/// A flag that is set when parsing a method that must call super's
/// implementation, such as \c -dealloc, \c -finalize, or any method marked
/// with \c __attribute__((objc_requires_super)).
@@ -348,6 +351,10 @@ public:
HasOMPDeclareReductionCombiner = true;
}
+ void setHasFallthroughStmt() {
+ HasFallthroughStmt = true;
+ }
+
void setHasCXXTry(SourceLocation TryLoc) {
setHasBranchProtectedScope();
FirstCXXTryLoc = TryLoc;
@@ -371,6 +378,7 @@ public:
HasIndirectGoto(false),
HasDroppedStmt(false),
HasOMPDeclareReductionCombiner(false),
+ HasFallthroughStmt(false),
ObjCShouldCallSuper(false),
ObjCIsDesignatedInit(false),
ObjCWarnForNoDesignatedInitChain(false),
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 5f74343fbd..fcb12f6ceb 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1071,6 +1071,34 @@ namespace {
};
} // anonymous namespace
+static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
+ SourceLocation Loc) {
+ TokenValue FallthroughTokens[] = {
+ tok::l_square, tok::l_square,
+ PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+
+ TokenValue ClangFallthroughTokens[] = {
+ tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
+ tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+
+ bool PreferClangAttr = !PP.getLangOpts().CPlusPlus1z;
+
+ StringRef MacroName;
+ if (PreferClangAttr)
+ MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
+ if (MacroName.empty())
+ MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
+ if (MacroName.empty() && !PreferClangAttr)
+ MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
+ if (MacroName.empty())
+ MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]";
+ return MacroName;
+}
+
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
// Only perform this analysis when using C++11. There is no good workflow
@@ -1129,15 +1157,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
Preprocessor &PP = S.getPreprocessor();
- TokenValue Tokens[] = {
- tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
- tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
- tok::r_square, tok::r_square
- };
- StringRef AnnotationSpelling = "[[clang::fallthrough]]";
- StringRef MacroName = PP.getLastMacroWithSpelling(L, Tokens);
- if (!MacroName.empty())
- AnnotationSpelling = MacroName;
+ StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
SmallString<64> TextToInsert(AnnotationSpelling);
TextToInsert += "; ";
S.Diag(L, diag::note_insert_fallthrough_fixit) <<
@@ -1151,7 +1171,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
for (const auto *F : FM.getFallthroughStmts())
- S.Diag(F->getLocStart(), diag::warn_fallthrough_attr_invalid_placement);
+ S.Diag(F->getLocStart(), diag::err_fallthrough_attr_invalid_placement);
}
static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
@@ -2038,7 +2058,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
!Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getLocStart());
bool FallThroughDiagPerFunction = !Diags.isIgnored(
diag::warn_unannotated_fallthrough_per_function, D->getLocStart());
- if (FallThroughDiagFull || FallThroughDiagPerFunction) {
+ if (FallThroughDiagFull || FallThroughDiagPerFunction ||
+ fscope->HasFallthroughStmt) {
DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
}
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 3c61c95ad8..cae9393f9f 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -159,6 +159,7 @@ struct ParsedAttrInfo {
unsigned HasCustomParsing : 1;
unsigned IsTargetSpecific : 1;
unsigned IsType : 1;
+ unsigned IsStmt : 1;
unsigned IsKnownToGCC : 1;
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
@@ -204,6 +205,10 @@ bool AttributeList::isTypeAttr() const {
return getInfo(*this).IsType;
}
+bool AttributeList::isStmtAttr() const {
+ return getInfo(*this).IsStmt;
+}
+
bool AttributeList::existsInTarget(const TargetInfo &Target) const {
return getInfo(*this).ExistsInTarget(Target);
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index ce78ab0092..1fca27f8b9 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2467,7 +2467,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
// about using it as an extension.
if (!S.getLangOpts().CPlusPlus1z && Attr.isCXX11Attribute() &&
!Attr.getScopeName())
- S.Diag(Attr.getLoc(), diag::ext_nodiscard_attr_is_a_cxx1z_extension);
+ S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
D->addAttr(::new (S.Context)
WarnUnusedResultAttr(Attr.getRange(), S.Context,
@@ -5072,7 +5072,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!S.getLangOpts().CPlusPlus14)
if (Attr.isCXX11Attribute() &&
!(Attr.hasScope() && Attr.getScopeName()->isStr("gnu")))
- S.Diag(Attr.getLoc(), diag::ext_deprecated_attr_is_a_cxx14_extension);
+ S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName();
handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
}
@@ -5234,8 +5234,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
switch (Attr.getKind()) {
default:
- // Type attributes are handled elsewhere; silently move on.
- assert(Attr.isTypeAttr() && "Non-type attribute not handled");
+ if (!Attr.isStmtAttr()) {
+ // Type attributes are handled elsewhere; silently move on.
+ assert(Attr.isTypeAttr() && "Non-type attribute not handled");
+ break;
+ }
+ S.Diag(Attr.getLoc(), diag::err_stmt_attribute_invalid_on_decl)
+ << Attr.getName() << D->getLocation();
break;
case AttributeList::AT_Interrupt:
handleInterruptAttr(S, D, Attr);
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 0279441ee2..c1c7e808dc 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -25,9 +25,11 @@ using namespace sema;
static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {
+ FallThroughAttr Attr(A.getRange(), S.Context,
+ A.getAttributeSpellingListIndex());
if (!isa<NullStmt>(St)) {
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
- << St->getLocStart();
+ << Attr.getSpelling() << St->getLocStart();
if (isa<SwitchCase>(St)) {
SourceLocation L = S.getLocForEndOfToken(Range.getEnd());
S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
@@ -35,12 +37,20 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
}
return nullptr;
}
- if (S.getCurFunction()->SwitchStack.empty()) {
+ auto *FnScope = S.getCurFunction();
+ if (FnScope->SwitchStack.empty()) {
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
return nullptr;
}
- return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context,
- A.getAttributeSpellingListIndex());
+
+ // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
+ // about using it as an extension.
+ if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() &&
+ !A.getScopeName())
+ S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName();
+
+ FnScope->setHasFallthroughStmt();
+ return ::new (S.Context) auto(Attr);
}
static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
@@ -266,7 +276,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
default:
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
- S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
+ S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
<< A.getName() << St->getLocStart();
return nullptr;
}
diff --git a/test/Analysis/cxx11-crashes.cpp b/test/Analysis/cxx11-crashes.cpp
index 3c33de3355..c6034e6480 100644
--- a/test/Analysis/cxx11-crashes.cpp
+++ b/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 test() {
void fallthrough() {
switch (1) {
case 1:
- [[clang::fallthrough]];
+ [[clang::fallthrough]]; // expected-error {{does not directly precede}}
}
}
diff --git a/test/PCH/Inputs/cxx11-statement-attributes.h b/test/PCH/Inputs/cxx11-statement-attributes.h
index f4d0619a3f..3f85e1fa2b 100644
--- a/test/PCH/Inputs/cxx11-statement-attributes.h
+++ b/test/PCH/Inputs/cxx11-statement-attributes.h
@@ -7,7 +7,8 @@ int f(int n) {
[[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/test/PCH/cxx11-statement-attributes.cpp b/test/PCH/cxx11-statement-attributes.cpp
index 722ca6e9ff..b5dfc6cd4c 100644
--- a/test/PCH/cxx11-statement-attributes.cpp
+++ b/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/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 7eec5761ea..c032e4723b 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/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 @@ deprecated
]] 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/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index 9359ae63a6..83023e3110 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -226,7 +226,7 @@ namespace test7 {
// 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/test/SemaCXX/generalized-deprecated.cpp b/test/SemaCXX/generalized-deprecated.cpp
index 8fa20d0a0f..43efea1ea4 100644
--- a/test/SemaCXX/generalized-deprecated.cpp
+++ b/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/test/SemaCXX/nodiscard.cpp b/test/SemaCXX/nodiscard.cpp
index 5fa4177095..e53cf9bb06 100644
--- a/test/SemaCXX/nodiscard.cpp
+++ b/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/test/SemaCXX/switch-implicit-fallthrough-macro.cpp b/test/SemaCXX/switch-implicit-fallthrough-macro.cpp
index add212fcf5..11df2cbfb5 100644
--- a/test/SemaCXX/switch-implicit-fallthrough-macro.cpp
+++ b/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 @@ int fallthrough_compatibility_macro_from_command_line(int n) {
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 @@ int fallthrough_compatibility_macro_from_source(int n) {
}
// 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 @@ int fallthrough_compatibility_macro_in_macro(int n) {
#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 @@ int fallthrough_compatibility_macro_history(int n) {
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/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp b/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
index 009c8180b1..6880bdd5f4 100644
--- a/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
+++ b/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
@@ -41,9 +41,8 @@ int fallthrough2(int n) {
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/test/SemaCXX/switch-implicit-fallthrough.cpp b/test/SemaCXX/switch-implicit-fallthrough.cpp
index 0bc43cdbd4..9540b1ff28 100644
--- a/test/SemaCXX/switch-implicit-fallthrough.cpp
+++ b/test/SemaCXX/switch-implicit-fallthrough.cpp
@@ -179,18 +179,15 @@ void fallthrough_cfgblock_with_null_successor(int x) {
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 @@ namespace PR18983 {
}
}
+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}}
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 20147d2595..57c7cb3ea8 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -1761,6 +1761,7 @@ namespace {
static const AttrClassDescriptor AttrClassDescriptors[] = {
{ "ATTR", "Attr" },
+ { "STMT_ATTR", "StmtAttr" },
{ "INHERITABLE_ATTR", "InheritableAttr" },
{ "INHERITABLE_PARAM_ATTR", "InheritableParamAttr" },
{ "PARAMETER_ABI_ATTR", "ParameterABIAttr" }
@@ -2806,6 +2807,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
SS << ", " << I->second->getValueAsBit("HasCustomParsing");
SS << ", " << I->second->isSubClassOf("TargetSpecificAttr");
SS << ", " << I->second->isSubClassOf("TypeAttr");
+ SS << ", " << I->second->isSubClassOf("StmtAttr");
SS << ", " << IsKnownToGCC(*I->second);
SS << ", " << GenerateAppertainsTo(*I->second, OS);
SS << ", " << GenerateLangOptRequirements(*I->second, OS);
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 5027ae8174..5674bff89a 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -629,7 +629,7 @@ as the draft C++1z standard evolves.</p>
<tr>
<td><tt>[[fallthrough]]</tt> attribute</td>
<td><a href="http://wg21.link/p0188r1">P0188R1</a></td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">SVN</td>
</tr>
<tr>
<td><tt>[[nodiscard]]</tt> attribute</td>