[clang] 8bd0055 - [clang][parser] Allow GNU attributes before namespace identifier

Aleksandr Platonov via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 15 12:31:45 PDT 2022


Author: Aleksandr Platonov
Date: 2022-03-15T22:30:22+03:00
New Revision: 8bd00557e3f43b46a96cf0e357d5e65624c85a2b

URL: https://github.com/llvm/llvm-project/commit/8bd00557e3f43b46a96cf0e357d5e65624c85a2b
DIFF: https://github.com/llvm/llvm-project/commit/8bd00557e3f43b46a96cf0e357d5e65624c85a2b.diff

LOG: [clang][parser] Allow GNU attributes before namespace identifier

GCC supports:
- `namespace <gnu attributes> identifier`
- `namespace identifier <gnu attributes>`

But clang supports only `namespace identifier <gnu attributes>` and diagnostics for `namespace <gnu attributes> identifier` case looks unclear:
Code:
```
namespace __attribute__((visibility("hidden"))) A
{
}
```
Diags:
```
test.cpp:1:49: error: expected identifier or '{'
namespace __attribute__((visibility("hidden"))) A
                                                ^
test.cpp:1:49: error: C++ requires a type specifier for all declarations
test.cpp:3:2: error: expected ';' after top level declarator
}
```

This patch adds support for `namespace <gnu attributes> identifier` and also forbids gnu attributes for nested namespaces (this already done for C++ attributes).

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D121245

Added: 
    clang/test/Parser/namespace-attributes.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Parse/ParseDeclCXX.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2422c8f2cba7a..ed79b647ed794 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -94,6 +94,11 @@ Attribute Changes in Clang
   locations a declaration attribute may appear.
   This fixes `Issue 53805 <https://github.com/llvm/llvm-project/issues/53805>`_.
 
+- Improved namespace attributes handling:
+  - Handle GNU attributes before a namespace identifier and subsequent
+    attributes of 
diff erent kinds.
+  - Emit error on GNU attributes for a nested namespace definition.
+
 Windows Support
 ---------------
 

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 4ac3baba0d689..77fc504ebe462 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -74,15 +74,27 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
   SourceLocation FirstNestedInlineLoc;
 
   ParsedAttributesWithRange attrs(AttrFactory);
-  SourceLocation attrLoc;
-  if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
-    Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
-                                ? diag::warn_cxx14_compat_ns_enum_attribute
-                                : diag::ext_ns_enum_attribute)
-      << 0 /*namespace*/;
-    attrLoc = Tok.getLocation();
-    ParseCXX11Attributes(attrs);
-  }
+
+  auto ReadAttributes = [&] {
+    bool MoreToParse;
+    do {
+      MoreToParse = false;
+      if (Tok.is(tok::kw___attribute)) {
+        ParseGNUAttributes(attrs);
+        MoreToParse = true;
+      }
+      if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+        Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
+                                    ? diag::warn_cxx14_compat_ns_enum_attribute
+                                    : diag::ext_ns_enum_attribute)
+            << 0 /*namespace*/;
+        ParseCXX11Attributes(attrs);
+        MoreToParse = true;
+      }
+    } while (MoreToParse);
+  };
+
+  ReadAttributes();
 
   if (Tok.is(tok::identifier)) {
     Ident = Tok.getIdentifierInfo();
@@ -108,16 +120,14 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
     }
   }
 
+  ReadAttributes();
+
+  SourceLocation attrLoc = attrs.Range.getBegin();
+
   // A nested namespace definition cannot have attributes.
   if (!ExtraNSs.empty() && attrLoc.isValid())
     Diag(attrLoc, diag::err_unexpected_nested_namespace_attribute);
 
-  // Read label attributes, if present.
-  if (Tok.is(tok::kw___attribute)) {
-    attrLoc = Tok.getLocation();
-    ParseGNUAttributes(attrs);
-  }
-
   if (Tok.is(tok::equal)) {
     if (!Ident) {
       Diag(Tok, diag::err_expected) << tok::identifier;

diff  --git a/clang/test/Parser/namespace-attributes.cpp b/clang/test/Parser/namespace-attributes.cpp
new file mode 100644
index 0000000000000..9f925b742dfeb
--- /dev/null
+++ b/clang/test/Parser/namespace-attributes.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s
+
+namespace __attribute__(()) A
+{
+}
+
+namespace A __attribute__(())
+{
+}
+
+namespace __attribute__(()) [[]] A
+{
+}
+
+namespace [[]] __attribute__(()) A
+{
+}
+
+namespace A __attribute__(()) [[]]
+{
+}
+
+namespace A [[]] __attribute__(())
+{
+}
+
+namespace [[]] A __attribute__(())
+{
+}
+
+namespace __attribute__(()) A [[]]
+{
+}
+
+namespace A::B __attribute__(()) // expected-error{{attributes cannot be specified on a nested namespace definition}}
+{
+}
+
+namespace __attribute__(()) A::B // expected-error{{attributes cannot be specified on a nested namespace definition}}
+{
+}


        


More information about the cfe-commits mailing list