aaron.ballman created this revision.
aaron.ballman added reviewers: rsmith, dblaikie, echristo.
Herald added a subscriber: krytarowski.

GCC is currently considering a patch to accept `__gnu__` as a scoped attribute 
namespace that aliases to `gnu`. This is useful for libstdc++ so that they 
don't have to worry about stepping on the user's namespace. The GCC bug can be 
found at: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86288

This patch supports parsing `__gnu__`, but it does support `__clang__` 
similarly because `__clang__` is a predefined macro that expands to an empty 
expansion. In order to support `[[__clang__::foobar]]` as an attribute 
spelling, I think we'd need to introduce some frontend hacks. Rather than get 
bogged down in that support, I am proposing to support only `__gnu__` for the 
moment, to ensure we remain compatible with libstdc++ when it makes the switch 
to the new attribute namespace.

Btw, an alternative implementation strategy here would be to make the `GCC` 
spelling introduce both the `gnu` and `__gnu__` variants of the attribute in 
addition to the GNU-style spelling. We have no CXX11 spellings that manually 
specify `gnu` as the vendor namespace, so this would suffice, but it feels a 
bit more fragile than baking this into the attribute system directly.


https://reviews.llvm.org/D53591

Files:
  include/clang/Sema/ParsedAttr.h
  lib/Basic/Attributes.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Sema/ParsedAttr.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaType.cpp
  test/Preprocessor/has_attribute.cpp
  test/SemaCXX/attr-gnu.cpp
  utils/TableGen/ClangAttrEmitter.cpp

Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -2935,9 +2935,9 @@
       if (I != List.cbegin())
         OS << " else ";
       if (I->first.empty())
-        OS << "if (!Scope || Scope->getName() == \"\") {\n";
+        OS << "if (ScopeName == \"\") {\n";
       else
-        OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
+        OS << "if (ScopeName == \"" << I->first << "\") {\n";
       OS << "  return llvm::StringSwitch<int>(Name)\n";
       GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first);
       OS << "}";
Index: test/SemaCXX/attr-gnu.cpp
===================================================================
--- test/SemaCXX/attr-gnu.cpp
+++ test/SemaCXX/attr-gnu.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -fms-compatibility -verify %s
+// RUN: %clang_cc1 -std=gnu++17 -fsyntax-only -fms-compatibility -verify %s
 
 void f() {
   // GNU-style attributes are prohibited in this position.
@@ -43,3 +43,10 @@
   tuTest1(x); // expected-error {{no matching function for call to 'tuTest1'}}
   tuTest2(x); // expected-error {{no matching function for call to 'tuTest2'}}
 }
+
+[[gnu::__const__]] int f2() { return 12; }
+[[__gnu__::__const__]] int f3() { return 12; }
+[[using __gnu__ : __const__]] int f4() { return 12; }
+
+static_assert(__has_cpp_attribute(gnu::__const__));
+static_assert(__has_cpp_attribute(__gnu__::__const__));
Index: test/Preprocessor/has_attribute.cpp
===================================================================
--- test/Preprocessor/has_attribute.cpp
+++ test/Preprocessor/has_attribute.cpp
@@ -21,11 +21,15 @@
   int has_clang_fallthrough_2();
 #endif
 
-// The scope cannot be bracketed with double underscores.
+// The scope cannot be bracketed with double underscores unless it is for gnu.
 // CHECK: does_not_have___clang___fallthrough
 #if !__has_cpp_attribute(__clang__::fallthrough)
   int does_not_have___clang___fallthrough();
 #endif
+// CHECK: has_gnu_const
+#if __has_cpp_attribute(__gnu__::__const__)
+  int has_gnu_const();
+#endif
 
 // Test that C++11, target-specific attributes behave properly.
 
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -7273,7 +7273,7 @@
       // not appertain to a DeclaratorChunk. If we handle them as type
       // attributes, accept them in that position and diagnose the GCC
       // incompatibility.
-      if (attr.getScopeName() && attr.getScopeName()->isStr("gnu")) {
+      if (attr.isGNUScope()) {
         bool IsTypeAttr = attr.isTypeAttr();
         if (TAL == TAL_DeclChunk) {
           state.getSema().Diag(attr.getLoc(),
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -5834,10 +5834,8 @@
            !S.checkStringLiteralArgumentAttr(AL, 1, Replacement))
     return;
 
-  if (!S.getLangOpts().CPlusPlus14)
-    if (AL.isCXX11Attribute() &&
-        !(AL.hasScope() && AL.getScopeName()->isStr("gnu")))
-      S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;
+  if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope())
+    S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;
 
   D->addAttr(::new (S.Context)
                  DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement,
Index: lib/Sema/ParsedAttr.cpp
===================================================================
--- lib/Sema/ParsedAttr.cpp
+++ lib/Sema/ParsedAttr.cpp
@@ -103,14 +103,25 @@
 
 #include "clang/Sema/AttrParsedAttrKinds.inc"
 
-static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName,
+static StringRef normalizeAttrScopeName(StringRef ScopeName,
+                                        ParsedAttr::Syntax SyntaxUsed) {
+  // We currently only normalize the "__gnu__" scope name to be "gnu".
+  if ((SyntaxUsed == ParsedAttr::AS_CXX11 ||
+       SyntaxUsed == ParsedAttr::AS_C2x) &&
+      ScopeName == "__gnu__")
+    ScopeName = ScopeName.slice(2, ScopeName.size() - 2);
+  return ScopeName;
+}
+
+static StringRef normalizeAttrName(StringRef AttrName,
+                                   StringRef NormalizedScopeName,
                                    ParsedAttr::Syntax SyntaxUsed) {
   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
-  // for GNU attributes.
+  // for GNU attributes, and attributes using the double square bracket syntax.
   bool IsGNU = SyntaxUsed == ParsedAttr::AS_GNU ||
                ((SyntaxUsed == ParsedAttr::AS_CXX11 ||
                  SyntaxUsed == ParsedAttr::AS_C2x) &&
-                ScopeName == "gnu");
+                NormalizedScopeName == "gnu");
   if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") &&
       AttrName.endswith("__"))
     AttrName = AttrName.slice(2, AttrName.size() - 2);
@@ -125,7 +136,7 @@
 
   SmallString<64> FullName;
   if (ScopeName)
-    FullName += ScopeName->getName();
+    FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
 
   AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
 
@@ -141,9 +152,10 @@
 unsigned ParsedAttr::getAttributeSpellingListIndex() const {
   // Both variables will be used in tablegen generated
   // attribute spell list index matching code.
-  StringRef Scope = ScopeName ? ScopeName->getName() : "";
-  StringRef Name = normalizeAttrName(AttrName->getName(), Scope,
-                                     (ParsedAttr::Syntax)SyntaxUsed);
+  auto Syntax = static_cast<ParsedAttr::Syntax>(SyntaxUsed);
+  StringRef Scope =
+      ScopeName ? normalizeAttrScopeName(ScopeName->getName(), Syntax) : "";
+  StringRef Name = normalizeAttrName(AttrName->getName(), Scope, Syntax);
 
 #include "clang/Sema/AttrSpellingListIndex.inc"
 
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -3868,7 +3868,8 @@
     return false;
   }
 
-  if (ScopeName && ScopeName->getName() == "gnu") {
+  if (ScopeName &&
+      (ScopeName->getName() == "gnu" || ScopeName->getName() == "__gnu__")) {
     // GNU-scoped attributes have some special cases to handle GNU-specific
     // behaviors.
     ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
Index: lib/Basic/Attributes.cpp
===================================================================
--- lib/Basic/Attributes.cpp
+++ lib/Basic/Attributes.cpp
@@ -12,6 +12,11 @@
   if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
     Name = Name.substr(2, Name.size() - 4);
 
+  // Normalize the scope name, but only for gnu attributes.
+  StringRef ScopeName = Scope ? Scope->getName() : "";
+  if (ScopeName == "__gnu__")
+    ScopeName = ScopeName.slice(2, ScopeName.size() - 2);
+
 #include "clang/Basic/AttrHasAttributeImpl.inc"
 
   return 0;
Index: include/clang/Sema/ParsedAttr.h
===================================================================
--- include/clang/Sema/ParsedAttr.h
+++ include/clang/Sema/ParsedAttr.h
@@ -383,6 +383,11 @@
   IdentifierInfo *getScopeName() const { return ScopeName; }
   SourceLocation getScopeLoc() const { return ScopeLoc; }
 
+  bool isGNUScope() const {
+    return ScopeName &&
+           (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
+  }
+
   bool hasParsedType() const { return HasParsedType; }
 
   /// Is this the Microsoft __declspec(property) attribute?
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D53591: S... Aaron Ballman via Phabricator via cfe-commits

Reply via email to