erik.pilkington created this revision.
erik.pilkington added reviewers: aaron.ballman, rsmith, ldionne, Mordante.
Herald added subscribers: jdoerfert, ributzka, jkorous.
erik.pilkington requested review of this revision.

This is split off from D90188 <https://reviews.llvm.org/D90188>.


https://reviews.llvm.org/D91630

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Parse/Parser.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/test/Parser/cxx0x-attributes.cpp

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<typename T> 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}}
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<Decl *, 8> 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/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/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/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<DiagGroup<"cxx-attribute-extension">>;
 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 "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to