Index: cfe/trunk/include/clang/Basic/Attr.td =================================================================== --- cfe/trunk/include/clang/Basic/Attr.td +++ cfe/trunk/include/clang/Basic/Attr.td @@ -1170,7 +1170,7 @@ def FallThrough : StmtAttr { let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">, - CXX11<"clang", "fallthrough">]; + CXX11<"clang", "fallthrough">, GCC<"fallthrough">]; // let Subjects = [NullStmt]; let Documentation = [FallthroughDocs]; } Index: cfe/trunk/include/clang/Parse/Parser.h =================================================================== --- cfe/trunk/include/clang/Parse/Parser.h +++ cfe/trunk/include/clang/Parse/Parser.h @@ -2107,12 +2107,13 @@ DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, - ParsedAttributesWithRange &attrs); - DeclGroupPtrTy ParseSimpleDeclaration(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributesWithRange &attrs, - bool RequireSemi, - ForRangeInit *FRI = nullptr); + ParsedAttributesWithRange &attrs, + SourceLocation *DeclSpecStart = nullptr); + DeclGroupPtrTy + ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, bool RequireSemi, + ForRangeInit *FRI = nullptr, + SourceLocation *DeclSpecStart = nullptr); bool MightBeDeclarator(DeclaratorContext Context); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, SourceLocation *DeclEnd = nullptr, Index: cfe/trunk/lib/Parse/ParseDecl.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp +++ cfe/trunk/lib/Parse/ParseDecl.cpp @@ -1741,9 +1741,10 @@ /// [C++11/C11] static_assert-declaration /// others... [FIXME] /// -Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributesWithRange &attrs) { +Parser::DeclGroupPtrTy +Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, + SourceLocation *DeclSpecStart) { ParenBraceBracketBalancer BalancerRAIIObj(*this); // Must temporarily exit the objective-c container scope for // parsing c none objective-c decls. @@ -1763,8 +1764,8 @@ SourceLocation InlineLoc = ConsumeToken(); return ParseNamespace(Context, DeclEnd, InlineLoc); } - return ParseSimpleDeclaration(Context, DeclEnd, attrs, - true); + return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr, + DeclSpecStart); case tok::kw_namespace: ProhibitAttributes(attrs); return ParseNamespace(Context, DeclEnd); @@ -1777,7 +1778,8 @@ SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; 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 @@ -1802,11 +1804,14 @@ /// 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 /// for-range-initializer, and place it here. -Parser::DeclGroupPtrTy -Parser::ParseSimpleDeclaration(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributesWithRange &Attrs, - bool RequireSemi, ForRangeInit *FRI) { +/// +/// DeclSpecStart is used when decl-specifiers are parsed before parsing +/// the Declaration. The SourceLocation for this Decl is set to +/// DeclSpecStart if DeclSpecStart is non-null. +Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &Attrs, bool RequireSemi, ForRangeInit *FRI, + SourceLocation *DeclSpecStart) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); @@ -1836,6 +1841,9 @@ return Actions.ConvertDeclToDeclGroup(TheDecl); } + if (DeclSpecStart) + DS.SetRangeStart(*DeclSpecStart); + DS.takeAttributesFrom(Attrs); return ParseDeclGroup(DS, Context, &DeclEnd, FRI); } Index: cfe/trunk/lib/Parse/ParseStmt.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseStmt.cpp +++ cfe/trunk/lib/Parse/ParseStmt.cpp @@ -153,6 +153,7 @@ SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { const char *SemiError = nullptr; StmtResult Res; + SourceLocation GNUAttributeLoc; // 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), @@ -208,10 +209,17 @@ if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && - isDeclarationStatement()) { + (GNUAttributeLoc.isValid() || isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Decl = ParseDeclaration(DeclaratorContext::BlockContext, - DeclEnd, Attrs); + DeclGroupPtrTy Decl; + 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); } @@ -223,6 +231,12 @@ return ParseExprStatement(StmtCtx); } + case tok::kw___attribute: { + GNUAttributeLoc = Tok.getLocation(); + ParseGNUAttributes(Attrs); + goto Retry; + } + case tok::kw_case: // C99 6.8.1: labeled-statement return ParseCaseStatement(StmtCtx); case tok::kw_default: // C99 6.8.1: labeled-statement Index: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp @@ -1215,7 +1215,7 @@ tok::r_square, tok::r_square }; - bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17; + bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x; StringRef MacroName; if (PreferClangAttr) @@ -1224,24 +1224,19 @@ MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); if (MacroName.empty() && !PreferClangAttr) MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); - if (MacroName.empty()) - MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]"; + if (MacroName.empty()) { + if (!PreferClangAttr) + MacroName = "[[fallthrough]]"; + else if (PP.getLangOpts().CPlusPlus) + MacroName = "[[clang::fallthrough]]"; + else + MacroName = "__attribute__((fallthrough))"; + } return MacroName; } static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, 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); FM.TraverseStmt(AC.getBody()); @@ -1281,25 +1276,24 @@ SourceLocation L = Label->getBeginLoc(); if (L.isMacroID()) continue; - if (S.getLangOpts().CPlusPlus11) { - const Stmt *Term = B->getTerminatorStmt(); - // Skip empty cases. - while (B->empty() && !Term && B->succ_size() == 1) { - B = *B->succ_begin(); - Term = B->getTerminatorStmt(); - } - if (!(B->empty() && Term && isa(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); - } + + const Stmt *Term = B->getTerminatorStmt(); + // Skip empty cases. + while (B->empty() && !Term && B->succ_size() == 1) { + B = *B->succ_begin(); + Term = B->getTerminatorStmt(); + } + if (!(B->empty() && Term && isa(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) << - FixItHint::CreateInsertion(L, "break; "); + S.Diag(L, diag::note_insert_break_fixit) + << FixItHint::CreateInsertion(L, "break; "); } } Index: cfe/trunk/test/Sema/fallthrough-attr.c =================================================================== --- cfe/trunk/test/Sema/fallthrough-attr.c +++ cfe/trunk/test/Sema/fallthrough-attr.c @@ -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; +} Index: cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp =================================================================== --- cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp +++ cfe/trunk/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -329,3 +329,15 @@ } return n; } + +int fallthrough_attribute_spelling(int n) { + switch (n) { + case 0: + n++; + __attribute__((fallthrough)); + case 1: + n++; + break; + } + return n; +} Index: cfe/trunk/test/SemaCXX/warn-unused-label-error.cpp =================================================================== --- cfe/trunk/test/SemaCXX/warn-unused-label-error.cpp +++ cfe/trunk/test/SemaCXX/warn-unused-label-error.cpp @@ -18,9 +18,9 @@ } void h() { - D: // expected-warning {{unused label 'D'}} - #pragma weak unused_local_static - __attribute__((unused)) // expected-warning {{declaration does not declare anything}} - ; + D: +#pragma weak unused_local_static + __attribute__((unused)) // expected-error {{'unused' attribute cannot be applied to a statement}} + ; } }