Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -1507,17 +1507,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() { @@ -2535,19 +2524,19 @@ void MaybeParseGNUAttributes(Declarator &D, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.is(tok::kw___attribute)) { - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); SourceLocation endLoc; ParseGNUAttributes(attrs, &endLoc, LateAttrs, &D); D.takeAttributes(attrs, endLoc); } } - void MaybeParseGNUAttributes(ParsedAttributes &attrs, + void MaybeParseGNUAttributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc = nullptr, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(attrs, endLoc, LateAttrs); } - void ParseGNUAttributes(ParsedAttributes &attrs, + void ParseGNUAttributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc = nullptr, LateParsedAttrList *LateAttrs = nullptr, Declarator *D = nullptr); @@ -2631,14 +2620,14 @@ /// Parses opencl_unroll_hint attribute if language is OpenCL v2.0 /// or higher. /// \return false if error happens. - bool MaybeParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) { + bool MaybeParseOpenCLUnrollHintAttribute(ParsedAttributesWithRange &Attrs) { if (getLangOpts().OpenCL) return ParseOpenCLUnrollHintAttribute(Attrs); return true; } /// Parses opencl_unroll_hint attribute. /// \return false if error happens. - bool ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs); + bool ParseOpenCLUnrollHintAttribute(ParsedAttributesWithRange &Attrs); void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs); VersionTuple ParseVersionTuple(SourceRange &Range); @@ -2830,7 +2819,7 @@ Decl *ParseUsingDirective(DeclaratorContext Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, - ParsedAttributes &attrs); + ParsedAttributesWithRange &attrs); struct UsingDeclarator { SourceLocation TypenameLoc; Index: clang/include/clang/Sema/DeclSpec.h =================================================================== --- clang/include/clang/Sema/DeclSpec.h +++ clang/include/clang/Sema/DeclSpec.h @@ -377,7 +377,7 @@ ExplicitSpecifier FS_explicit_specifier; // attributes. - ParsedAttributes Attrs; + ParsedAttributesWithRange Attrs; // Scope specifier for the type spec, if applicable. CXXScopeSpec TypeScope; @@ -784,8 +784,8 @@ bool hasAttributes() const { return !Attrs.empty(); } - ParsedAttributes &getAttributes() { return Attrs; } - const ParsedAttributes &getAttributes() const { return Attrs; } + ParsedAttributesWithRange &getAttributes() { return Attrs; } + const ParsedAttributesWithRange &getAttributes() const { return Attrs; } void takeAttributesFrom(ParsedAttributes &attrs) { Attrs.takeAllFrom(attrs); Index: clang/include/clang/Sema/ParsedAttr.h =================================================================== --- clang/include/clang/Sema/ParsedAttr.h +++ clang/include/clang/Sema/ParsedAttr.h @@ -1001,6 +1001,19 @@ mutable AttributePool pool; }; +struct ParsedAttributesWithRange : ParsedAttributes { + ParsedAttributesWithRange(AttributeFactory &factory) + : ParsedAttributes(factory) {} + + void clear() { + ParsedAttributes::clear(); + 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 @@ -143,12 +143,15 @@ /// ',' 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) { assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); + if (attrs.Range.getBegin().isInvalid()) + attrs.Range.setBegin(Tok.getLocation()); + while (Tok.is(tok::kw___attribute)) { SourceLocation AttrTokLoc = ConsumeToken(); unsigned OldNumAttrs = attrs.size(); @@ -241,6 +244,9 @@ } } } + + if (attrs.Range.getEnd().isInvalid()) + attrs.Range.setEnd(Tok.getLocation()); } /// Determine whether the given attribute has an identifier argument. @@ -4318,7 +4324,7 @@ T.consumeClose(); - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after struct contents, parse them. MaybeParseGNUAttributes(attrs); @@ -4826,7 +4832,7 @@ T.consumeClose(); // If attributes exist after the identifier list, parse them. - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); Actions.ActOnEnumBody(StartLoc, T.getRange(), EnumDecl, EnumConstantDecls, @@ -6244,7 +6250,7 @@ // In either case, we need to eat any attributes to be able to determine what // sort of paren this is. // - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { ParseGNUAttributes(attrs); Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -516,7 +516,7 @@ Decl *Parser::ParseUsingDirective(DeclaratorContext Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, - ParsedAttributes &attrs) { + ParsedAttributesWithRange &attrs) { assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token"); // Eat 'namespace'. @@ -3050,7 +3050,7 @@ T.skipToEnd(); // Parse and discard any trailing attributes. - ParsedAttributes Attrs(AttrFactory); + ParsedAttributesWithRange Attrs(AttrFactory); if (Tok.is(tok::kw___attribute)) MaybeParseGNUAttributes(Attrs); } @@ -3343,7 +3343,7 @@ } // If attributes exist after class contents, parse them. - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); if (TagDecl) Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ clang/lib/Parse/ParseExprCXX.cpp @@ -1234,7 +1234,7 @@ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); Actions.PushLambdaScope(); - ParsedAttributes Attr(AttrFactory); + ParsedAttributesWithRange Attr(AttrFactory); SourceLocation DeclLoc = Tok.getLocation(); if (getLangOpts().CUDA) { // In CUDA code, GNU attributes are allowed to appear immediately after the Index: clang/lib/Parse/ParseObjc.cpp =================================================================== --- clang/lib/Parse/ParseObjc.cpp +++ clang/lib/Parse/ParseObjc.cpp @@ -25,7 +25,7 @@ /// Skips attributes after an Objective-C @ directive. Emits a diagnostic. void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) { - ParsedAttributes attrs(AttrFactory); + ParsedAttributesWithRange attrs(AttrFactory); if (Tok.is(tok::kw___attribute)) { if (Kind == tok::objc_interface || Kind == tok::objc_protocol) Diag(Tok, diag::err_objc_postfix_attribute_hint) @@ -1348,7 +1348,7 @@ nullptr); // If attributes exist before the method, parse them. - ParsedAttributes methodAttrs(AttrFactory); + ParsedAttributesWithRange methodAttrs(AttrFactory); if (getLangOpts().ObjC) MaybeParseGNUAttributes(methodAttrs); MaybeParseCXX11Attributes(methodAttrs); @@ -1397,7 +1397,7 @@ AttributePool allParamAttrs(AttrFactory); while (1) { - ParsedAttributes paramAttrs(AttrFactory); + ParsedAttributesWithRange paramAttrs(AttrFactory); Sema::ObjCArgInfo ArgInfo; // Each iteration parses a single keyword argument. Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -2493,7 +2493,7 @@ Braces.consumeClose(); } -bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) { +bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributesWithRange &Attrs) { MaybeParseGNUAttributes(Attrs); if (Attrs.empty()) Index: clang/test/AST/sourceranges.cpp =================================================================== --- clang/test/AST/sourceranges.cpp +++ clang/test/AST/sourceranges.cpp @@ -108,6 +108,25 @@ } } +// 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; + } + } +} + #if __cplusplus >= 201703L // CHECK-1Z: FunctionDecl {{.*}} construct_with_init_list std::map construct_with_init_list() { Index: clang/test/SemaCXX/switch-implicit-fallthrough.cpp =================================================================== --- clang/test/SemaCXX/switch-implicit-fallthrough.cpp +++ clang/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -107,6 +107,11 @@ break; case 25: // no warning here, there's no fall-through break; + case 26: + return 0; + __attribute__((fallthrough)); // expected-warning{{fallthrough annotation in unreachable code}} + case 27: + break; } return n;