Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -1572,27 +1572,6 @@ //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. - struct ParsedAttributesWithRange : ParsedAttributes { - ParsedAttributesWithRange(AttributeFactory &factory) - : ParsedAttributes(factory) {} - - void clear() { - ParsedAttributes::clear(); - Range = SourceRange(); - } - - SourceRange Range; - }; - struct ParsedAttributesViewWithRange : ParsedAttributesView { - ParsedAttributesViewWithRange() : ParsedAttributesView() {} - void clearListOnly() { - ParsedAttributesView::clearListOnly(); - Range = SourceRange(); - } - - SourceRange Range; - }; - DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParsingDeclSpec *DS = nullptr); bool isDeclarationAfterDeclarator(); @@ -2725,16 +2704,39 @@ D.takeAttributes(attrs, endLoc); } } + bool MaybeParseGNUAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = nullptr, LateParsedAttrList *LateAttrs = nullptr) { + if (Tok.is(tok::kw___attribute)) { + ParsedAttributesWithRange attrsWithRange(AttrFactory); + ParseGNUAttributes(attrs, endLoc, LateAttrs); + attrs.takeAllFrom(attrsWithRange); + return true; + } + return false; + } + + bool MaybeParseGNUAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc = nullptr, + LateParsedAttrList *LateAttrs = nullptr) { if (Tok.is(tok::kw___attribute)) { ParseGNUAttributes(attrs, endLoc, LateAttrs); return true; } return false; } + void ParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = nullptr, + LateParsedAttrList *LateAttrs = nullptr, + Declarator *D = nullptr) { + ParsedAttributesWithRange attrsWithRange(AttrFactory); + ParseGNUAttributes(attrsWithRange, endLoc, LateAttrs, D); + attrs.takeAllFrom(attrsWithRange); + } + + void ParseGNUAttributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc = nullptr, LateParsedAttrList *LateAttrs = nullptr, Declarator *D = nullptr); Index: clang/include/clang/Sema/ParsedAttr.h =================================================================== --- clang/include/clang/Sema/ParsedAttr.h +++ clang/include/clang/Sema/ParsedAttr.h @@ -1034,6 +1034,27 @@ mutable AttributePool pool; }; +struct ParsedAttributesWithRange : ParsedAttributes { + ParsedAttributesWithRange(AttributeFactory &factory) + : ParsedAttributes(factory) {} + + void clear() { + ParsedAttributes::clear(); + Range = SourceRange(); + } + + SourceRange Range; +}; +struct ParsedAttributesViewWithRange : ParsedAttributesView { + ParsedAttributesViewWithRange() : ParsedAttributesView() {} + void clearListOnly() { + ParsedAttributesView::clearListOnly(); + Range = SourceRange(); + } + + SourceRange Range; +}; + /// These constants match the enumerated choices of /// err_attribute_argument_n_type and err_attribute_argument_type. enum AttributeArgumentNType { Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -162,12 +162,16 @@ /// ',' or ')' are ignored, otherwise they produce a parse error. /// /// We follow the C++ model, but don't allow junk after the identifier. -void Parser::ParseGNUAttributes(ParsedAttributes &attrs, +void Parser::ParseGNUAttributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc, - LateParsedAttrList *LateAttrs, - Declarator *D) { + LateParsedAttrList *LateAttrs, Declarator *D) { assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); + SourceLocation StartLoc = Tok.getLocation(), Loc; + + if (!endLoc) + endLoc = &Loc; + while (Tok.is(tok::kw___attribute)) { SourceLocation AttrTokLoc = ConsumeToken(); unsigned OldNumAttrs = attrs.size(); @@ -260,6 +264,8 @@ } } } + + attrs.Range = SourceRange(StartLoc, *endLoc); } /// Determine whether the given attribute has an identifier argument. Index: clang/test/AST/sourceranges.cpp =================================================================== --- clang/test/AST/sourceranges.cpp +++ clang/test/AST/sourceranges.cpp @@ -108,6 +108,24 @@ } } +// CHECK-1Z: NamespaceDecl {{.*}} attributed_case +namespace attributed_case { +void f(int n) { + switch (n) { + case 0: + n--; + // CHECK: AttributedStmt {{.*}} + // CHECK: FallThroughAttr {{.*}} + __attribute__((fallthrough)) + // CHECK: FallThroughAttr {{.*}} + __attribute__((fallthrough)); + case 1: + n++; + break; + } +} +} // namespace attributed_case + // CHECK: NamespaceDecl {{.*}} attributed_stmt namespace attributed_stmt { // In DO_PRAGMA and _Pragma cases, `LoopHintAttr` comes from Index: clang/test/SemaCXX/switch-implicit-fallthrough.cpp =================================================================== --- clang/test/SemaCXX/switch-implicit-fallthrough.cpp +++ clang/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -185,9 +185,12 @@ return 1; [[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}} case 222: + return 2; + __attribute__((fallthrough)); // expected-warning{{fallthrough annotation in unreachable code}} + case 223: n += 400; - case 223: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}} - ; + case 224: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}} + ; } long p = static_cast(n) * n; @@ -341,3 +344,16 @@ } return n; } + +int fallthrough_in_unreachable_code(int n) { + switch (n) { + case 1: +#ifndef MAYBE_THIS_EXISTS + return -1; +#endif + __attribute__((fallthrough)); + case 2: + return 3; + } + return n; +}