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,17 +2704,50 @@ D.takeAttributes(attrs, endLoc); } } - bool MaybeParseGNUAttributes(ParsedAttributes &attrs, - SourceLocation *endLoc = nullptr, + + /// Parses GNU-style attributes and returns them without source range + /// information. + /// + /// This API is discouraged. Use the version that takes a + /// ParsedAttributesWithRange instead. + bool MaybeParseGNUAttributes(ParsedAttributes &Attrs, + SourceLocation *EndLoc = nullptr, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.is(tok::kw___attribute)) { - ParseGNUAttributes(attrs, endLoc, LateAttrs); + ParsedAttributesWithRange AttrsWithRange(AttrFactory); + ParseGNUAttributes(Attrs, EndLoc, LateAttrs); + Attrs.takeAllFrom(AttrsWithRange); return true; } return false; } - void ParseGNUAttributes(ParsedAttributes &attrs, - SourceLocation *endLoc = nullptr, + + bool MaybeParseGNUAttributes(ParsedAttributesWithRange &Attrs, + SourceLocation *EndLoc = nullptr, + LateParsedAttrList *LateAttrs = nullptr) { + if (Tok.is(tok::kw___attribute)) { + ParseGNUAttributes(Attrs, EndLoc, LateAttrs); + return true; + } + return false; + } + + /// Parses GNU-style attributes and returns them without source range + /// information. + /// + /// This API is discouraged. Use the version that takes a + /// ParsedAttributesWithRange instead. + 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); void ParseGNUAttributeArgs(IdentifierInfo *AttrName, 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,15 +162,19 @@ /// ',' 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, - SourceLocation *endLoc, - LateParsedAttrList *LateAttrs, - Declarator *D) { +void Parser::ParseGNUAttributes(ParsedAttributesWithRange &Attrs, + SourceLocation *EndLoc, + 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(); + unsigned OldNumAttrs = Attrs.size(); unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0; if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, @@ -198,14 +202,14 @@ SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, ParsedAttr::AS_GNU); continue; } // Handle "parameterized" attributes if (!LateAttrs || !isAttributeLateParsed(*AttrName)) { - ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr, + ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, nullptr, SourceLocation(), ParsedAttr::AS_GNU, D); continue; } @@ -238,8 +242,8 @@ SourceLocation Loc = Tok.getLocation(); if (ExpectAndConsume(tok::r_paren)) SkipUntil(tok::r_paren, StopAtSemi); - if (endLoc) - *endLoc = Loc; + if (EndLoc) + *EndLoc = Loc; // If this was declared in a macro, attach the macro IdentifierInfo to the // parsed attribute. @@ -251,8 +255,8 @@ Lexer::getSourceText(ExpansionRange, SM, PP.getLangOpts()); IdentifierInfo *MacroII = PP.getIdentifierInfo(FoundName); - for (unsigned i = OldNumAttrs; i < attrs.size(); ++i) - attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin()); + for (unsigned i = OldNumAttrs; i < Attrs.size(); ++i) + Attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin()); if (LateAttrs) { for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i) @@ -260,6 +264,8 @@ } } } + + Attrs.Range = SourceRange(StartLoc, *EndLoc); } /// Determine whether the given attribute has an identifier argument. Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -1852,7 +1852,8 @@ } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { - ProhibitAttributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + /*DiagnoseEmptyAttrs=*/true); TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, SS, TemplateId->TemplateKWLoc, @@ -1924,7 +1925,8 @@ TagType, StartLoc, SS, Name, NameLoc, attrs); } else if (TUK == Sema::TUK_Friend && TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { - ProhibitAttributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + /*DiagnoseEmptyAttrs=*/true); TagOrTempResult = Actions.ActOnTemplatedFriendTag( getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name, 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/Parser/cxx0x-attributes.cpp =================================================================== --- clang/test/Parser/cxx0x-attributes.cpp +++ clang/test/Parser/cxx0x-attributes.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++17-extensions %s +// RUN: %clang_cc1 -fcxx-exceptions -fdeclspec -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++17-extensions %s // Need std::initializer_list namespace std { @@ -368,6 +368,22 @@ return n; } +template struct TemplateStruct {}; +class FriendClassesWithAttributes { + // We allow GNU-style attributes here + template friend class __attribute__((__type_visibility__("default"))) vector; + template friend class __declspec(code_seg("whatever")) vector2; + // But not C++11 ones + template friend class[[]] vector3; // expected-error {{an attribute list cannot appear here}} + template friend class [[clang::__type_visibility__(("default"))]] vector4; // expected-error {{an attribute list cannot appear here}} + + // Also allowed + friend struct __attribute__((__type_visibility__("default"))) TemplateStruct; + friend struct __declspec(code_seg("whatever")) TemplateStruct; + friend struct[[]] TemplateStruct; // expected-error {{an attribute list cannot appear here}} + friend struct [[clang::__type_visibility__("default")]] TemplateStruct; // expected-error {{an attribute list cannot appear here}} +}; + #define attr_name bitand #define attr_name_2(x) x #define attr_name_3(x, y) x##y 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;