]> granicus.if.org Git - clang/commitdiff
Introduce the _Clang scoped attribute token.
authorAaron Ballman <aaron@aaronballman.com>
Fri, 9 Nov 2018 17:19:45 +0000 (17:19 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Fri, 9 Nov 2018 17:19:45 +0000 (17:19 +0000)
Currently, we only accept clang as the scoped attribute identifier for double square bracket attributes provided by Clang, but this has the potential to conflict with user-defined macros. To help alleviate these concerns, this introduces the _Clang scoped attribute identifier as an alias for clang. It also introduces a warning with a fixit on the off chance someone attempts to use __clang__ as the scoped attribute (which is a predefined compiler identification macro).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@346521 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticParseKinds.td
lib/Basic/Attributes.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/ParsedAttr.cpp
test/FixIt/fixit-cxx11-attributes.cpp
test/Parser/cxx0x-attributes.cpp
test/Preprocessor/has_attribute.cpp
test/SemaCXX/attr-optnone.cpp

index 1ca7c4a74efcad3241786b3963894ea7793df20e..f47d88a82a43eed636437503a7cba018fc0b0c8e 100644 (file)
@@ -575,6 +575,9 @@ def warn_cxx98_compat_noexcept_expr : Warning<
 def warn_cxx98_compat_nullptr : Warning<
   "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
 
+def warn_wrong_clang_attr_namespace : Warning<
+  "'__clang__' is a predefined macro name, not an attribute scope specifier; "
+  "did you mean '_Clang' instead?">, InGroup<IgnoredAttributes>;
 def ext_ns_enum_attribute : Extension<
   "attributes on %select{a namespace|an enumerator}0 declaration are "
   "a C++17 extension">, InGroup<CXX17>;
index 1c84d0779e1dab385ecfdaafeaeb62041849c879..9a8eb3d932cc64356a172e1b5cb4ed4edba5a4ce 100644 (file)
@@ -9,16 +9,18 @@ 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("__"))\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
+  if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
+    Name = Name.substr(2, Name.size() - 4);
+
+  // Normalize the scope name, but only for gnu and clang attributes.
+  StringRef ScopeName = Scope ? Scope->getName() : "";
+  if (ScopeName == "__gnu__")
+    ScopeName = "gnu";
+  else if (ScopeName == "_Clang")
+    ScopeName = "clang";
+
+#include "clang/Basic/AttrHasAttributeImpl.inc"
+
   return 0;\r
 }
 
index 9369f0f56c95f4c30912f62cb32689d3855cc4e9..c814775c77e6aabeada7458f86e511ff2685951f 100644 (file)
@@ -3790,6 +3790,28 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
     }
     return nullptr;
 
+  case tok::numeric_constant: {
+    // If we got a numeric constant, check to see if it comes from a macro that
+    // corresponds to the predefined __clang__ macro. If it does, warn the user
+    // and recover by pretending they said _Clang instead.
+    if (Tok.getLocation().isMacroID()) {
+      SmallString<8> ExpansionBuf;
+      SourceLocation ExpansionLoc =
+          PP.getSourceManager().getExpansionLoc(Tok.getLocation());
+      StringRef Spelling = PP.getSpelling(ExpansionLoc, ExpansionBuf);
+      if (Spelling == "__clang__") {
+        SourceRange TokRange(
+            ExpansionLoc,
+            PP.getSourceManager().getExpansionLoc(Tok.getEndLoc()));
+        Diag(Tok, diag::warn_wrong_clang_attr_namespace)
+            << FixItHint::CreateReplacement(TokRange, "_Clang");
+        Loc = ConsumeToken();
+        return &PP.getIdentifierTable().get("_Clang");
+      }
+    }
+    return nullptr;
+  }
+
   case tok::ampamp:       // 'and'
   case tok::pipe:         // 'bitor'
   case tok::pipepipe:     // 'or'
@@ -3865,24 +3887,22 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
     // Eat the left paren, then skip to the ending right paren.
     ConsumeParen();
     SkipUntil(tok::r_paren);
-    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
+    return false;
+  }
+
+  if (ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"))) {
+    // GNU-scoped attributes have some special cases to handle GNU-specific
+    // behaviors.
+    ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
                           ScopeLoc, Syntax, nullptr);
     return true;
   }
 
   unsigned NumArgs;
   // Some Clang-scoped attributes have some special parsing behavior.
-  if (ScopeName && ScopeName->getName() == "clang")
-    NumArgs =
-        ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
-                                ScopeLoc, Syntax);
+  if (ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")))
+    NumArgs = ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc,
+                                      ScopeName, ScopeLoc, Syntax);
   else
     NumArgs =
         ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
index ccfbe66db97e4e3d95d8e9ff33e1149e490978a2..4c46063e2c18e57a6a32facfad7266bdb5a8f918 100644 (file)
@@ -105,11 +105,15 @@ void AttributePool::takePool(AttributePool &pool) {
 
 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);
+  // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
+  // to be "clang".
+  if (SyntaxUsed == ParsedAttr::AS_CXX11 ||
+    SyntaxUsed == ParsedAttr::AS_C2x) {
+    if (ScopeName == "__gnu__")
+      ScopeName = "gnu";
+    else if (ScopeName == "_Clang")
+      ScopeName = "clang";
+  }
   return ScopeName;
 }
 
index 30697a90002670d6fcd3539fd9392d4183f7a8a5..996fd185c37d9a2e460ae7039f3e6de4b09f23f2 100644 (file)
@@ -49,3 +49,6 @@ namespace BaseSpecifier {
   // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:26}:"[{{\[}}d]]"
   // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:33-[[@LINE-2]]:39}:""
 }
+
+[[__clang__::annotate("test")]] void annotate3();  // expected-warning {{'__clang__' is a predefined macro name, not an attribute scope specifier; did you mean '_Clang' instead?}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"_Clang"
index e01491db41339a66f6f6f63df633b28438ec9b42..101e03845b8f26d5654a7720e3ccdfac3c03b9ac 100644 (file)
@@ -373,3 +373,11 @@ int fallthru(int n) {
 [[attr_name, attr_name_2(bitor), attr_name_3(com, pl)]] int macro_attrs; // expected-warning {{unknown attribute 'compl' ignored}} \
    expected-warning {{unknown attribute 'bitor' ignored}} \
    expected-warning {{unknown attribute 'bitand' ignored}}
+
+// Check that we can parse an attribute in our vendor namespace.
+[[clang::annotate("test")]] void annotate1();
+[[_Clang::annotate("test")]] void annotate2();
+// Note: __clang__ is a predefined macro, which is why _Clang is the
+// prefered "protected" vendor namespace. We support __clang__ only for
+// people expecting it to behave the same as __gnu__.
+[[__clang__::annotate("test")]] void annotate3();  // expected-warning {{'__clang__' is a predefined macro name, not an attribute scope specifier; did you mean '_Clang' instead?}}
index 53d1fb07b9ebb626fab2e7a5f43ae32e5208363f..91f3501666fc7e7d88e8404c6bc374147bdd9f7b 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();\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
+  int has_clang_fallthrough_2();
+#endif
+
+// The scope cannot be bracketed with double underscores unless it is
+// for gnu or clang.
+// CHECK: does_not_have___gsl___suppress
+#if !__has_cpp_attribute(__gsl__::suppress)
+  int does_not_have___gsl___suppress();
+#endif
+
+// We do somewhat support the __clang__ vendor namespace, but it is a
+// predefined macro and thus we encourage users to use _Clang instead.
+// Because of this, we do not support __has_cpp_attribute for that
+// vendor namespace.
+// CHECK: does_not_have___clang___fallthrough
+#if !__has_cpp_attribute(__clang__::fallthrough)
+  int does_not_have___clang___fallthrough();
+#endif
+
+// CHECK: does_have_Clang_fallthrough
+#if __has_cpp_attribute(_Clang::fallthrough)
+  int does_have_Clang_fallthrough();
+#endif
+
+// CHECK: has_gnu_const
+#if __has_cpp_attribute(__gnu__::__const__)
+  int has_gnu_const();
 #endif\r
 \r
 // Test that C++11, target-specific attributes behave properly.\r
index 58776caf7ae60b47967ab0f83ed18fab2255b56f..1e02653b95ead8180eeff03e2606a01444134e1b 100644 (file)
@@ -71,3 +71,9 @@ struct B2 {
   static void bar();
 };
 
+// Verify that we can handle the [[_Clang::optnone]] and
+// [[__clang__::optnone]] spellings.
+[[_Clang::optnone]] int foo3();
+[[__clang__::optnone]] int foo4(); // expected-warning {{'__clang__' is a predefined macro name, not an attribute scope specifier; did you mean '_Clang' instead?}}
+
+[[_Clang::optnone]] int foo5; // expected-warning {{'optnone' attribute only applies to functions}}