Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -686,6 +686,9 @@ def err_using_attribute_ns_conflict : Error< "attribute with scope specifier cannot follow default scope specifier">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; +def ext_cxx11_attr_placement : ExtWarn< + "ISO C++ does not allow an attribute list to appear here">, + InGroup>; def err_attributes_misplaced : Error<"misplaced attributes; expected attributes here">; def err_l_square_l_square_not_attribute : Error< "C++11 only allows consecutive left square brackets when " Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -2645,6 +2645,10 @@ void ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, unsigned DiagID); + /// Emit warnings for C++11 attributes that are in a position that clang + /// accepts as an extension. + void DiagnoseCXX11AttributeExtension(ParsedAttributesWithRange &Attrs); + /// Skip C++11 and C2x attributes and return the end location of the /// last one. /// \returns SourceLocation() if there are no attributes. @@ -2993,6 +2997,7 @@ const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, + ParsedAttributesWithRange &Attrs, AccessSpecifier AS = AS_none); Decl *ParseAliasDeclarationAfterDeclarator( const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -1601,6 +1601,13 @@ } } +void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributesWithRange &Attrs) { + for (const ParsedAttr &PA : Attrs) { + if (PA.isCXX11Attribute()) + Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA; + } +} + // Usually, `__attribute__((attrib)) class Foo {} var` means that attribute // applies to var, not the type Foo. // As an exception to the rule, __declspec(align(...)) before the Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -497,12 +497,8 @@ } // Otherwise, it must be a using-declaration or an alias-declaration. - - // Using declarations can't have attributes. - ProhibitAttributes(attrs); - return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, - AS_none); + attrs, AS_none); } /// ParseUsingDirective - Parse C++ using-directive, assumes @@ -675,6 +671,7 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, + ParsedAttributesWithRange &PrefixAttrs, AccessSpecifier AS) { // Check for misplaced attributes before the identifier in an // alias-declaration. @@ -695,6 +692,8 @@ return nullptr; } + ProhibitAttributes(PrefixAttrs); + // If we had any misplaced attributes from earlier, this is where they // should have been written. if (MisplacedAttrs.Range.isValid()) { @@ -712,10 +711,8 @@ return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec); } - // C++11 attributes are not allowed on a using-declaration, but GNU ones - // are. ProhibitAttributes(MisplacedAttrs); - ProhibitAttributes(Attrs); + DiagnoseCXX11AttributeExtension(PrefixAttrs); // Diagnose an attempt to declare a templated using-declaration. // In C++11, alias-declarations can be templates: @@ -733,8 +730,11 @@ SmallVector DeclsInGroup; while (true) { - // Parse (optional) attributes (most likely GNU strong-using extension). + // Parse (optional) attributes. MaybeParseGNUAttributes(Attrs); + MaybeParseCXX11Attributes(Attrs); + DiagnoseCXX11AttributeExtension(Attrs); + Attrs.addAll(PrefixAttrs.begin(), PrefixAttrs.end()); if (InvalidDeclarator) SkipUntil(tok::comma, tok::semi, StopBeforeMatch); @@ -2590,8 +2590,6 @@ MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { - ProhibitAttributes(attrs); - // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); @@ -2610,7 +2608,7 @@ SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. return ParseUsingDeclaration(DeclaratorContext::MemberContext, TemplateInfo, - UsingLoc, DeclEnd, AS); + UsingLoc, DeclEnd, attrs, AS); } // Hold late-parsed attributes so we can attach a Decl to them later. Index: clang/test/Parser/cxx0x-attributes.cpp =================================================================== --- clang/test/Parser/cxx0x-attributes.cpp +++ clang/test/Parser/cxx0x-attributes.cpp @@ -131,7 +131,7 @@ [[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}} [[]] asm(""); // expected-error {{an attribute list cannot appear here}} -[[]] using ns::i; // expected-error {{an attribute list cannot appear here}} +[[]] using ns::i; [[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}} [[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions}} namespace [[]] ns2 {} // expected-warning {{attributes on a namespace declaration are a C++17 extension}} @@ -157,7 +157,16 @@ [[]] using T = int; // expected-error {{an attribute list cannot appear here}} using T [[]] = int; // ok template using U [[]] = T; -using ns::i [[]]; // expected-error {{an attribute list cannot appear here}} +using ns::i [[]]; +using ns::i [[]], ns::i [[]]; // expected-warning {{use of multiple declarators in a single using declaration is a C++17 extension}} +struct using_in_struct_base { + typedef int i, j, k, l; +}; +struct using_in_struct : using_in_struct_base { + [[]] using using_in_struct_base::i; + using using_in_struct_base::j [[]]; + [[]] using using_in_struct_base::k [[]], using_in_struct_base::l [[]]; // expected-warning {{use of multiple declarators in a single using declaration is a C++17 extension}} +}; using [[]] ns::i; // expected-error {{an attribute list cannot appear here}} using T [[unknown]] = int; // expected-warning {{unknown attribute 'unknown' ignored}} using T [[noreturn]] = int; // expected-error {{'noreturn' attribute only applies to functions}}