forked from OSchip/llvm-project
[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:
parent
86d560ff1b
commit
1e0affb6e5
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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; ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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}}
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue