Support accepting __gnu__ as a scoped attribute namespace that aliases to gnu.
authorAaron Ballman <aaron@aaronballman.com>
Wed, 24 Oct 2018 12:26:23 +0000 (12:26 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Wed, 24 Oct 2018 12:26:23 +0000 (12:26 +0000)
This is useful in libstdc++ to avoid clashes with identifiers in the user's namespace.

llvm-svn: 345132

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

index 7561e835747a0a09ea18dfbc770228e13a0b76df..11202cb137b5b7d0a18326a7ea0b470e0607f058 100644 (file)
@@ -383,6 +383,11 @@ public:
   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?
index b7570d03c85aebb40b8a196f7c21f3218c695d24..1c84d0779e1dab385ecfdaafeaeb62041849c879 100644 (file)
@@ -9,12 +9,17 @@ int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
                         const LangOptions &LangOpts) {
   StringRef Name = Attr->getName();
   // Normalize the attribute name, __foo__ becomes foo.
-  if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
-    Name = Name.substr(2, Name.size() - 4);
-
-#include "clang/Basic/AttrHasAttributeImpl.inc"
-
-  return 0;
+  if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))\r
+    Name = Name.substr(2, Name.size() - 4);\r
+\r
+  // Normalize the scope name, but only for gnu attributes.\r
+  StringRef ScopeName = Scope ? Scope->getName() : "";\r
+  if (ScopeName == "__gnu__")\r
+    ScopeName = ScopeName.slice(2, ScopeName.size() - 2);\r
+\r
+#include "clang/Basic/AttrHasAttributeImpl.inc"\r
+\r
+  return 0;\r
 }
 
 const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
index a86f7ed8642b7226b793583204d3fe82d8d24850..63e7179a74c2d9d321816f0b6e91293d718a577e 100644 (file)
@@ -3865,13 +3865,14 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
     // Eat the left paren, then skip to the ending right paren.
     ConsumeParen();
     SkipUntil(tok::r_paren);
-    return false;
-  }
-
-  if (ScopeName && ScopeName->getName() == "gnu") {
-    // GNU-scoped attributes have some special cases to handle GNU-specific
-    // behaviors.
-    ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+    return false;\r
+  }\r
+\r
+  if (ScopeName &&\r
+      (ScopeName->getName() == "gnu" || ScopeName->getName() == "__gnu__")) {\r
+    // GNU-scoped attributes have some special cases to handle GNU-specific\r
+    // behaviors.\r
+    ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,\r
                           ScopeLoc, Syntax, nullptr);
     return true;
   }
index 3dff0ad63e227b6b8c41fe9bbca87485b717ae5c..ccfbe66db97e4e3d95d8e9ff33e1149e490978a2 100644 (file)
@@ -103,14 +103,25 @@ void AttributePool::takePool(AttributePool &pool) {
 
 #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 @@ ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name,
 
   SmallString<64> FullName;
   if (ScopeName)
-    FullName += ScopeName->getName();
+    FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
 
   AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
 
@@ -141,9 +152,10 @@ ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name,
 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 c0fb3356bae0f442e08caabd046b5807f04115be..a0faf8409582b8a4d6853ec5745aa40b6abf8202 100644 (file)
@@ -5831,16 +5831,14 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (AL.isDeclspecAttribute() || AL.isCXX11Attribute())
     checkAttributeAtMostNumArgs(S, AL, 1);
   else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) &&
-           !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;
-
-  D->addAttr(::new (S.Context)
-                 DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement,
+           !S.checkStringLiteralArgumentAttr(AL, 1, Replacement))\r
+    return;\r
+\r
+  if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope())\r
+    S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;\r
+\r
+  D->addAttr(::new (S.Context)\r
+                 DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement,\r
                                 AL.getAttributeSpellingListIndex()));
 }
 
index 27dbf70498d39b5b506a20eafa6b1fe482c27a9a..85a57e751032a26dfda708aa5a3578bd8ec87482 100644 (file)
@@ -7273,7 +7273,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
       // 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 2cfa005fb09faefe293e88cc3d4b150f827eb8de..53d1fb07b9ebb626fab2e7a5f43ae32e5208363f 100644 (file)
 // The attribute name can be bracketed with double underscores.
 // CHECK: has_clang_fallthrough_2
 #if __has_cpp_attribute(clang::__fallthrough__)
-  int has_clang_fallthrough_2();
-#endif
-
-// The scope cannot be bracketed with double underscores.
-// CHECK: does_not_have___clang___fallthrough
-#if !__has_cpp_attribute(__clang__::fallthrough)
-  int does_not_have___clang___fallthrough();
-#endif
-
-// Test that C++11, target-specific attributes behave properly.
-
+  int has_clang_fallthrough_2();\r
+#endif\r
+\r
+// The scope cannot be bracketed with double underscores unless it is for gnu.\r
+// CHECK: does_not_have___clang___fallthrough\r
+#if !__has_cpp_attribute(__clang__::fallthrough)\r
+  int does_not_have___clang___fallthrough();\r
+#endif\r
+// CHECK: has_gnu_const\r
+#if __has_cpp_attribute(__gnu__::__const__)\r
+  int has_gnu_const();\r
+#endif\r
+\r
+// Test that C++11, target-specific attributes behave properly.\r
+\r
 // CHECK: does_not_have_mips16
 #if !__has_cpp_attribute(gnu::mips16)
   int does_not_have_mips16();
index a553f0d210003f6c4bd13788bfdf54393fae8790..9eb42342df31a0e173bcc93016cd901efedc315a 100644 (file)
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -fms-compatibility -verify %s
-
-void f() {
-  // GNU-style attributes are prohibited in this position.
+// RUN: %clang_cc1 -std=gnu++17 -fsyntax-only -fms-compatibility -verify %s\r
+\r
+void f() {\r
+  // GNU-style attributes are prohibited in this position.\r
   auto P = new int * __attribute__((vector_size(8))); // expected-error {{an attribute list cannot appear here}} \
                                                       // expected-error {{invalid vector element type 'int *'}}
 
@@ -40,6 +40,13 @@ void tuTest1(Tu<int> u); // expected-note {{candidate function not viable: no kn
 void tuTest2(Tu3 u); // expected-note {{candidate function not viable: no known conversion from 'int' to 'Tu3' for 1st argument}}
 void tu() {
   int x = 2;
-  tuTest1(x); // expected-error {{no matching function for call to 'tuTest1'}}
-  tuTest2(x); // expected-error {{no matching function for call to 'tuTest2'}}
-}
+  tuTest1(x); // expected-error {{no matching function for call to 'tuTest1'}}\r
+  tuTest2(x); // expected-error {{no matching function for call to 'tuTest2'}}\r
+}\r
+\r
+[[gnu::__const__]] int f2() { return 12; }\r
+[[__gnu__::__const__]] int f3() { return 12; }\r
+[[using __gnu__ : __const__]] int f4() { return 12; }\r
+\r
+static_assert(__has_cpp_attribute(gnu::__const__));\r
+static_assert(__has_cpp_attribute(__gnu__::__const__));\r
index 59eab3977335815decffbdab05661b0f86c922b7..43e6638f7f4728f2c9f8306b895c74c9b4bb6e80 100644 (file)
@@ -2932,15 +2932,15 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
     OS << "case AttrSyntax::" << Variety << ": {\n";
     // C++11-style attributes are further split out based on the Scope.
     for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) {
-      if (I != List.cbegin())
-        OS << " else ";
-      if (I->first.empty())
-        OS << "if (!Scope || Scope->getName() == \"\") {\n";
-      else
-        OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
-      OS << "  return llvm::StringSwitch<int>(Name)\n";
-      GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first);
-      OS << "}";
+      if (I != List.cbegin())\r
+        OS << " else ";\r
+      if (I->first.empty())\r
+        OS << "if (ScopeName == \"\") {\n";\r
+      else\r
+        OS << "if (ScopeName == \"" << I->first << "\") {\n";\r
+      OS << "  return llvm::StringSwitch<int>(Name)\n";\r
+      GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first);\r
+      OS << "}";\r
     }
     OS << "\n} break;\n";
   };