Skip to content

Commit 1e0affb

Browse files
committed
[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
1 parent 86d560f commit 1e0affb

File tree

8 files changed

+110
-57
lines changed

8 files changed

+110
-57
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,7 @@ def ExtVectorType : Attr {
11701170

11711171
def FallThrough : StmtAttr {
11721172
let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">,
1173-
CXX11<"clang", "fallthrough">];
1173+
CXX11<"clang", "fallthrough">, GCC<"fallthrough">];
11741174
// let Subjects = [NullStmt];
11751175
let Documentation = [FallthroughDocs];
11761176
}

clang/include/clang/Parse/Parser.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,12 +2107,13 @@ class Parser : public CodeCompletionHandler {
21072107

21082108
DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context,
21092109
SourceLocation &DeclEnd,
2110-
ParsedAttributesWithRange &attrs);
2111-
DeclGroupPtrTy ParseSimpleDeclaration(DeclaratorContext Context,
2112-
SourceLocation &DeclEnd,
2113-
ParsedAttributesWithRange &attrs,
2114-
bool RequireSemi,
2115-
ForRangeInit *FRI = nullptr);
2110+
ParsedAttributesWithRange &attrs,
2111+
SourceLocation *DeclSpecStart = nullptr);
2112+
DeclGroupPtrTy
2113+
ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
2114+
ParsedAttributesWithRange &attrs, bool RequireSemi,
2115+
ForRangeInit *FRI = nullptr,
2116+
SourceLocation *DeclSpecStart = nullptr);
21162117
bool MightBeDeclarator(DeclaratorContext Context);
21172118
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
21182119
SourceLocation *DeclEnd = nullptr,

clang/lib/Parse/ParseDecl.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,9 +1741,10 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs,
17411741
/// [C++11/C11] static_assert-declaration
17421742
/// others... [FIXME]
17431743
///
1744-
Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
1745-
SourceLocation &DeclEnd,
1746-
ParsedAttributesWithRange &attrs) {
1744+
Parser::DeclGroupPtrTy
1745+
Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
1746+
ParsedAttributesWithRange &attrs,
1747+
SourceLocation *DeclSpecStart) {
17471748
ParenBraceBracketBalancer BalancerRAIIObj(*this);
17481749
// Must temporarily exit the objective-c container scope for
17491750
// parsing c none objective-c decls.
@@ -1763,8 +1764,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
17631764
SourceLocation InlineLoc = ConsumeToken();
17641765
return ParseNamespace(Context, DeclEnd, InlineLoc);
17651766
}
1766-
return ParseSimpleDeclaration(Context, DeclEnd, attrs,
1767-
true);
1767+
return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
1768+
DeclSpecStart);
17681769
case tok::kw_namespace:
17691770
ProhibitAttributes(attrs);
17701771
return ParseNamespace(Context, DeclEnd);
@@ -1777,7 +1778,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
17771778
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
17781779
break;
17791780
default:
1780-
return ParseSimpleDeclaration(Context, DeclEnd, attrs, true);
1781+
return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
1782+
DeclSpecStart);
17811783
}
17821784

17831785
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1802,11 +1804,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
18021804
/// If FRI is non-null, we might be parsing a for-range-declaration instead
18031805
/// of a simple-declaration. If we find that we are, we also parse the
18041806
/// for-range-initializer, and place it here.
1805-
Parser::DeclGroupPtrTy
1806-
Parser::ParseSimpleDeclaration(DeclaratorContext Context,
1807-
SourceLocation &DeclEnd,
1808-
ParsedAttributesWithRange &Attrs,
1809-
bool RequireSemi, ForRangeInit *FRI) {
1807+
///
1808+
/// DeclSpecStart is used when decl-specifiers are parsed before parsing
1809+
/// the Declaration. The SourceLocation for this Decl is set to
1810+
/// DeclSpecStart if DeclSpecStart is non-null.
1811+
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
1812+
DeclaratorContext Context, SourceLocation &DeclEnd,
1813+
ParsedAttributesWithRange &Attrs, bool RequireSemi, ForRangeInit *FRI,
1814+
SourceLocation *DeclSpecStart) {
18101815
// Parse the common declaration-specifiers piece.
18111816
ParsingDeclSpec DS(*this);
18121817

@@ -1836,6 +1841,9 @@ Parser::ParseSimpleDeclaration(DeclaratorContext Context,
18361841
return Actions.ConvertDeclToDeclGroup(TheDecl);
18371842
}
18381843

1844+
if (DeclSpecStart)
1845+
DS.SetRangeStart(*DeclSpecStart);
1846+
18391847
DS.takeAttributesFrom(Attrs);
18401848
return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
18411849
}

clang/lib/Parse/ParseStmt.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
153153
SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) {
154154
const char *SemiError = nullptr;
155155
StmtResult Res;
156+
SourceLocation GNUAttributeLoc;
156157

157158
// Cases in this switch statement should fall through if the parser expects
158159
// the token to end in a semicolon (in which case SemiError should be set),
@@ -208,10 +209,17 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
208209
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
209210
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
210211
ParsedStmtContext()) &&
211-
isDeclarationStatement()) {
212+
(GNUAttributeLoc.isValid() || isDeclarationStatement())) {
212213
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
213-
DeclGroupPtrTy Decl = ParseDeclaration(DeclaratorContext::BlockContext,
214-
DeclEnd, Attrs);
214+
DeclGroupPtrTy Decl;
215+
if (GNUAttributeLoc.isValid()) {
216+
DeclStart = GNUAttributeLoc;
217+
Decl = ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs,
218+
&GNUAttributeLoc);
219+
} else {
220+
Decl =
221+
ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs);
222+
}
215223
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
216224
}
217225

@@ -223,6 +231,12 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
223231
return ParseExprStatement(StmtCtx);
224232
}
225233

234+
case tok::kw___attribute: {
235+
GNUAttributeLoc = Tok.getLocation();
236+
ParseGNUAttributes(Attrs);
237+
goto Retry;
238+
}
239+
226240
case tok::kw_case: // C99 6.8.1: labeled-statement
227241
return ParseCaseStatement(StmtCtx);
228242
case tok::kw_default: // C99 6.8.1: labeled-statement

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,7 +1215,7 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
12151215
tok::r_square, tok::r_square
12161216
};
12171217

1218-
bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17;
1218+
bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x;
12191219

12201220
StringRef MacroName;
12211221
if (PreferClangAttr)
@@ -1224,24 +1224,19 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
12241224
MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
12251225
if (MacroName.empty() && !PreferClangAttr)
12261226
MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
1227-
if (MacroName.empty())
1228-
MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]";
1227+
if (MacroName.empty()) {
1228+
if (!PreferClangAttr)
1229+
MacroName = "[[fallthrough]]";
1230+
else if (PP.getLangOpts().CPlusPlus)
1231+
MacroName = "[[clang::fallthrough]]";
1232+
else
1233+
MacroName = "__attribute__((fallthrough))";
1234+
}
12291235
return MacroName;
12301236
}
12311237

12321238
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
12331239
bool PerFunction) {
1234-
// Only perform this analysis when using [[]] attributes. There is no good
1235-
// workflow for this warning when not using C++11. There is no good way to
1236-
// silence the warning (no attribute is available) unless we are using
1237-
// [[]] attributes. One could use pragmas to silence the warning, but as a
1238-
// general solution that is gross and not in the spirit of this warning.
1239-
//
1240-
// NOTE: This an intermediate solution. There are on-going discussions on
1241-
// how to properly support this warning outside of C++11 with an annotation.
1242-
if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes)
1243-
return;
1244-
12451240
FallthroughMapper FM(S);
12461241
FM.TraverseStmt(AC.getBody());
12471242

@@ -1281,25 +1276,24 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
12811276
SourceLocation L = Label->getBeginLoc();
12821277
if (L.isMacroID())
12831278
continue;
1284-
if (S.getLangOpts().CPlusPlus11) {
1285-
const Stmt *Term = B->getTerminatorStmt();
1286-
// Skip empty cases.
1287-
while (B->empty() && !Term && B->succ_size() == 1) {
1288-
B = *B->succ_begin();
1289-
Term = B->getTerminatorStmt();
1290-
}
1291-
if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
1292-
Preprocessor &PP = S.getPreprocessor();
1293-
StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
1294-
SmallString<64> TextToInsert(AnnotationSpelling);
1295-
TextToInsert += "; ";
1296-
S.Diag(L, diag::note_insert_fallthrough_fixit) <<
1297-
AnnotationSpelling <<
1298-
FixItHint::CreateInsertion(L, TextToInsert);
1299-
}
1279+
1280+
const Stmt *Term = B->getTerminatorStmt();
1281+
// Skip empty cases.
1282+
while (B->empty() && !Term && B->succ_size() == 1) {
1283+
B = *B->succ_begin();
1284+
Term = B->getTerminatorStmt();
1285+
}
1286+
if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
1287+
Preprocessor &PP = S.getPreprocessor();
1288+
StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
1289+
SmallString<64> TextToInsert(AnnotationSpelling);
1290+
TextToInsert += "; ";
1291+
S.Diag(L, diag::note_insert_fallthrough_fixit)
1292+
<< AnnotationSpelling
1293+
<< FixItHint::CreateInsertion(L, TextToInsert);
13001294
}
1301-
S.Diag(L, diag::note_insert_break_fixit) <<
1302-
FixItHint::CreateInsertion(L, "break; ");
1295+
S.Diag(L, diag::note_insert_break_fixit)
1296+
<< FixItHint::CreateInsertion(L, "break; ");
13031297
}
13041298
}
13051299

clang/test/Sema/fallthrough-attr.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_cc1 -fsyntax-only -std=gnu89 -verify -Wimplicit-fallthrough %s
2+
// RUN: %clang_cc1 -fsyntax-only -std=gnu99 -verify -Wimplicit-fallthrough %s
3+
// RUN: %clang_cc1 -fsyntax-only -std=c99 -verify -Wimplicit-fallthrough %s
4+
// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify -Wimplicit-fallthrough %s
5+
// RUN: %clang_cc1 -fsyntax-only -std=c2x -DC2X -verify -Wimplicit-fallthrough %s
6+
7+
int fallthrough_attribute_spelling(int n) {
8+
switch (n) {
9+
case 0:
10+
n++;
11+
case 1:
12+
#if defined(C2X)
13+
// 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}}
14+
#else
15+
// 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}}
16+
#endif
17+
n++;
18+
__attribute__((fallthrough));
19+
case 2:
20+
n++;
21+
break;
22+
}
23+
return n;
24+
}

clang/test/SemaCXX/switch-implicit-fallthrough.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,3 +329,15 @@ int fallthrough_alt_spelling(int n) {
329329
}
330330
return n;
331331
}
332+
333+
int fallthrough_attribute_spelling(int n) {
334+
switch (n) {
335+
case 0:
336+
n++;
337+
__attribute__((fallthrough));
338+
case 1:
339+
n++;
340+
break;
341+
}
342+
return n;
343+
}

clang/test/SemaCXX/warn-unused-label-error.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ namespace PR8455 {
1818
}
1919

2020
void h() {
21-
D: // expected-warning {{unused label 'D'}}
22-
#pragma weak unused_local_static
23-
__attribute__((unused)) // expected-warning {{declaration does not declare anything}}
24-
;
21+
D:
22+
#pragma weak unused_local_static
23+
__attribute__((unused)) // expected-error {{'unused' attribute cannot be applied to a statement}}
24+
;
2525
}
2626
}

0 commit comments

Comments
 (0)