diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-03-08 00:32:55 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-03-08 00:32:55 +0000 |
| commit | 4f902c7eccd47cc3e1d0ceebca3025406a2e5fa7 (patch) | |
| tree | f4f111a17e5cb2aa89e7050bd5c8ef41e30bc2f2 /clang/lib | |
| parent | 12350a8e133caefd43d1bc1d18baa66ba5202a3d (diff) | |
| download | bcm5719-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.cpp | 43 | ||||
| -rw-r--r-- | clang/lib/Sema/AttributeList.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmtAttr.cpp | 20 |
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; } |

