[Attr] Support _attribute__ ((fallthrough))

Summary: Fixed extraneous matches of non-NullStmt

Reviewers: aaron.ballman, rsmith, efriedma, xbolva00

Reviewed By: aaron.ballman, rsmith, xbolva00

Subscribers: riccibruno, arphaman, ziangwan, ojeda, xbolva00, nickdesaulniers, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D64838

llvm-svn: 369414
This commit is contained in:
Nathan Huckleberry 2019-08-20 17:16:49 +00:00
parent 86d560ff1b
commit 1e0affb6e5
8 changed files with 110 additions and 57 deletions

View File

@ -1170,7 +1170,7 @@ def ExtVectorType : Attr {
def FallThrough : StmtAttr { def FallThrough : StmtAttr {
let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">, let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">,
CXX11<"clang", "fallthrough">]; CXX11<"clang", "fallthrough">, GCC<"fallthrough">];
// let Subjects = [NullStmt]; // let Subjects = [NullStmt];
let Documentation = [FallthroughDocs]; let Documentation = [FallthroughDocs];
} }

View File

@ -2107,12 +2107,13 @@ private:
DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context, DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs); ParsedAttributesWithRange &attrs,
DeclGroupPtrTy ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation *DeclSpecStart = nullptr);
SourceLocation &DeclEnd, DeclGroupPtrTy
ParsedAttributesWithRange &attrs, ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
bool RequireSemi, ParsedAttributesWithRange &attrs, bool RequireSemi,
ForRangeInit *FRI = nullptr); ForRangeInit *FRI = nullptr,
SourceLocation *DeclSpecStart = nullptr);
bool MightBeDeclarator(DeclaratorContext Context); bool MightBeDeclarator(DeclaratorContext Context);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
SourceLocation *DeclEnd = nullptr, SourceLocation *DeclEnd = nullptr,

View File

@ -1741,9 +1741,10 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs,
/// [C++11/C11] static_assert-declaration /// [C++11/C11] static_assert-declaration
/// others... [FIXME] /// others... [FIXME]
/// ///
Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, Parser::DeclGroupPtrTy
SourceLocation &DeclEnd, Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs) { ParsedAttributesWithRange &attrs,
SourceLocation *DeclSpecStart) {
ParenBraceBracketBalancer BalancerRAIIObj(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this);
// Must temporarily exit the objective-c container scope for // Must temporarily exit the objective-c container scope for
// parsing c none objective-c decls. // parsing c none objective-c decls.
@ -1763,8 +1764,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
SourceLocation InlineLoc = ConsumeToken(); SourceLocation InlineLoc = ConsumeToken();
return ParseNamespace(Context, DeclEnd, InlineLoc); return ParseNamespace(Context, DeclEnd, InlineLoc);
} }
return ParseSimpleDeclaration(Context, DeclEnd, attrs, return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
true); DeclSpecStart);
case tok::kw_namespace: case tok::kw_namespace:
ProhibitAttributes(attrs); ProhibitAttributes(attrs);
return ParseNamespace(Context, DeclEnd); return ParseNamespace(Context, DeclEnd);
@ -1777,7 +1778,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
SingleDecl = ParseStaticAssertDeclaration(DeclEnd); SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break; break;
default: default:
return ParseSimpleDeclaration(Context, DeclEnd, attrs, true); return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
DeclSpecStart);
} }
// This routine returns a DeclGroup, if the thing we parsed only contains a // This routine returns a DeclGroup, if the thing we parsed only contains a
@ -1802,11 +1804,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
/// If FRI is non-null, we might be parsing a for-range-declaration instead /// If FRI is non-null, we might be parsing a for-range-declaration instead
/// of a simple-declaration. If we find that we are, we also parse the /// of a simple-declaration. If we find that we are, we also parse the
/// for-range-initializer, and place it here. /// for-range-initializer, and place it here.
Parser::DeclGroupPtrTy ///
Parser::ParseSimpleDeclaration(DeclaratorContext Context, /// DeclSpecStart is used when decl-specifiers are parsed before parsing
SourceLocation &DeclEnd, /// the Declaration. The SourceLocation for this Decl is set to
ParsedAttributesWithRange &Attrs, /// DeclSpecStart if DeclSpecStart is non-null.
bool RequireSemi, ForRangeInit *FRI) { Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
DeclaratorContext Context, SourceLocation &DeclEnd,
ParsedAttributesWithRange &Attrs, bool RequireSemi, ForRangeInit *FRI,
SourceLocation *DeclSpecStart) {
// Parse the common declaration-specifiers piece. // Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this); ParsingDeclSpec DS(*this);
@ -1836,6 +1841,9 @@ Parser::ParseSimpleDeclaration(DeclaratorContext Context,
return Actions.ConvertDeclToDeclGroup(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl);
} }
if (DeclSpecStart)
DS.SetRangeStart(*DeclSpecStart);
DS.takeAttributesFrom(Attrs); DS.takeAttributesFrom(Attrs);
return ParseDeclGroup(DS, Context, &DeclEnd, FRI); return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
} }

View File

@ -153,6 +153,7 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) {
const char *SemiError = nullptr; const char *SemiError = nullptr;
StmtResult Res; StmtResult Res;
SourceLocation GNUAttributeLoc;
// Cases in this switch statement should fall through if the parser expects // Cases in this switch statement should fall through if the parser expects
// the token to end in a semicolon (in which case SemiError should be set), // the token to end in a semicolon (in which case SemiError should be set),
@ -208,10 +209,17 @@ Retry:
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
ParsedStmtContext()) && ParsedStmtContext()) &&
isDeclarationStatement()) { (GNUAttributeLoc.isValid() || isDeclarationStatement())) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd; SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl = ParseDeclaration(DeclaratorContext::BlockContext, DeclGroupPtrTy Decl;
DeclEnd, Attrs); if (GNUAttributeLoc.isValid()) {
DeclStart = GNUAttributeLoc;
Decl = ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs,
&GNUAttributeLoc);
} else {
Decl =
ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs);
}
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
} }
@ -223,6 +231,12 @@ Retry:
return ParseExprStatement(StmtCtx); return ParseExprStatement(StmtCtx);
} }
case tok::kw___attribute: {
GNUAttributeLoc = Tok.getLocation();
ParseGNUAttributes(Attrs);
goto Retry;
}
case tok::kw_case: // C99 6.8.1: labeled-statement case tok::kw_case: // C99 6.8.1: labeled-statement
return ParseCaseStatement(StmtCtx); return ParseCaseStatement(StmtCtx);
case tok::kw_default: // C99 6.8.1: labeled-statement case tok::kw_default: // C99 6.8.1: labeled-statement

View File

@ -1215,7 +1215,7 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
tok::r_square, tok::r_square tok::r_square, tok::r_square
}; };
bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17; bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x;
StringRef MacroName; StringRef MacroName;
if (PreferClangAttr) if (PreferClangAttr)
@ -1224,24 +1224,19 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
if (MacroName.empty() && !PreferClangAttr) if (MacroName.empty() && !PreferClangAttr)
MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
if (MacroName.empty()) if (MacroName.empty()) {
MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]"; if (!PreferClangAttr)
MacroName = "[[fallthrough]]";
else if (PP.getLangOpts().CPlusPlus)
MacroName = "[[clang::fallthrough]]";
else
MacroName = "__attribute__((fallthrough))";
}
return MacroName; return MacroName;
} }
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) { bool PerFunction) {
// Only perform this analysis when using [[]] attributes. There is no good
// workflow for this warning when not using C++11. There is no good way to
// silence the warning (no attribute is available) unless we are using
// [[]] attributes. One could use pragmas to silence the warning, but as a
// general solution that is gross and not in the spirit of this warning.
//
// NOTE: This an intermediate solution. There are on-going discussions on
// how to properly support this warning outside of C++11 with an annotation.
if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes)
return;
FallthroughMapper FM(S); FallthroughMapper FM(S);
FM.TraverseStmt(AC.getBody()); FM.TraverseStmt(AC.getBody());
@ -1281,25 +1276,24 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
SourceLocation L = Label->getBeginLoc(); SourceLocation L = Label->getBeginLoc();
if (L.isMacroID()) if (L.isMacroID())
continue; continue;
if (S.getLangOpts().CPlusPlus11) {
const Stmt *Term = B->getTerminatorStmt(); const Stmt *Term = B->getTerminatorStmt();
// Skip empty cases. // Skip empty cases.
while (B->empty() && !Term && B->succ_size() == 1) { while (B->empty() && !Term && B->succ_size() == 1) {
B = *B->succ_begin(); B = *B->succ_begin();
Term = B->getTerminatorStmt(); Term = B->getTerminatorStmt();
}
if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
Preprocessor &PP = S.getPreprocessor();
StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
SmallString<64> TextToInsert(AnnotationSpelling);
TextToInsert += "; ";
S.Diag(L, diag::note_insert_fallthrough_fixit) <<
AnnotationSpelling <<
FixItHint::CreateInsertion(L, TextToInsert);
}
} }
S.Diag(L, diag::note_insert_break_fixit) << if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
FixItHint::CreateInsertion(L, "break; "); Preprocessor &PP = S.getPreprocessor();
StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
SmallString<64> TextToInsert(AnnotationSpelling);
TextToInsert += "; ";
S.Diag(L, diag::note_insert_fallthrough_fixit)
<< AnnotationSpelling
<< FixItHint::CreateInsertion(L, TextToInsert);
}
S.Diag(L, diag::note_insert_break_fixit)
<< FixItHint::CreateInsertion(L, "break; ");
} }
} }

View File

@ -0,0 +1,24 @@
// RUN: %clang_cc1 -fsyntax-only -std=gnu89 -verify -Wimplicit-fallthrough %s
// RUN: %clang_cc1 -fsyntax-only -std=gnu99 -verify -Wimplicit-fallthrough %s
// RUN: %clang_cc1 -fsyntax-only -std=c99 -verify -Wimplicit-fallthrough %s
// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify -Wimplicit-fallthrough %s
// RUN: %clang_cc1 -fsyntax-only -std=c2x -DC2X -verify -Wimplicit-fallthrough %s
int fallthrough_attribute_spelling(int n) {
switch (n) {
case 0:
n++;
case 1:
#if defined(C2X)
// expected-warning@-2{{unannotated fall-through between switch labels}} expected-note@-2{{insert '[[fallthrough]];' to silence this warning}} expected-note@-2{{insert 'break;' to avoid fall-through}}
#else
// expected-warning@-4{{unannotated fall-through between switch labels}} expected-note@-4{{insert '__attribute__((fallthrough));' to silence this warning}} expected-note@-4{{insert 'break;' to avoid fall-through}}
#endif
n++;
__attribute__((fallthrough));
case 2:
n++;
break;
}
return n;
}

View File

@ -329,3 +329,15 @@ int fallthrough_alt_spelling(int n) {
} }
return n; return n;
} }
int fallthrough_attribute_spelling(int n) {
switch (n) {
case 0:
n++;
__attribute__((fallthrough));
case 1:
n++;
break;
}
return n;
}

View File

@ -18,9 +18,9 @@ namespace PR8455 {
} }
void h() { void h() {
D: // expected-warning {{unused label 'D'}} D:
#pragma weak unused_local_static #pragma weak unused_local_static
__attribute__((unused)) // expected-warning {{declaration does not declare anything}} __attribute__((unused)) // expected-error {{'unused' attribute cannot be applied to a statement}}
; ;
} }
} }