summaryrefslogtreecommitdiffstats
path: root/clang/lib
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
commit4f902c7eccd47cc3e1d0ceebca3025406a2e5fa7 (patch)
treef4f111a17e5cb2aa89e7050bd5c8ef41e30bc2f2 /clang/lib
parent12350a8e133caefd43d1bc1d18baa66ba5202a3d (diff)
downloadbcm5719-llvm-4f902c7eccd47cc3e1d0ceebca3025406a2e5fa7.tar.gz
bcm5719-llvm-4f902c7eccd47cc3e1d0ceebca3025406a2e5fa7.zip
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
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp43
-rw-r--r--clang/lib/Sema/AttributeList.cpp5
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp13
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp20
4 files changed, 61 insertions, 20 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 5f74343fbd9..fcb12f6cebf 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/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/clang/lib/Sema/AttributeList.cpp b/clang/lib/Sema/AttributeList.cpp
index 3c61c95ad8e..cae9393f9f3 100644
--- a/clang/lib/Sema/AttributeList.cpp
+++ b/clang/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/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index ce78ab00926..1fca27f8b95 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/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/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 0279441ee20..c1c7e808dc3 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/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;
}
OpenPOWER on IntegriCloud