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

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 patch 
introduces the `_Clang` scoped attribute identifier as an alias for `clang`.

GCC elected to go with `__gnu__` for their protected name, but we cannot follow 
suit due to `__clang__` being a predefined macro that identifies the 
implementation.  I added a warning with a fixit on the off chance someone 
attempts to use `__clang__` as the scoped attribute identifier, but do not 
support the spelling fully (for instance, `__has_cpp_attribute` does not 
support `__clang__`).


https://reviews.llvm.org/D53700

Files:
  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: test/SemaCXX/attr-optnone.cpp
===================================================================
--- test/SemaCXX/attr-optnone.cpp
+++ test/SemaCXX/attr-optnone.cpp
@@ -71,3 +71,9 @@
   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}}
Index: test/Preprocessor/has_attribute.cpp
===================================================================
--- test/Preprocessor/has_attribute.cpp
+++ test/Preprocessor/has_attribute.cpp
@@ -21,11 +21,27 @@
   int has_clang_fallthrough_2();
 #endif
 
-// The scope cannot be bracketed with double underscores unless it is for gnu.
+// 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();
Index: test/Parser/cxx0x-attributes.cpp
===================================================================
--- test/Parser/cxx0x-attributes.cpp
+++ test/Parser/cxx0x-attributes.cpp
@@ -373,3 +373,11 @@
 [[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: test/FixIt/fixit-cxx11-attributes.cpp
===================================================================
--- test/FixIt/fixit-cxx11-attributes.cpp
+++ test/FixIt/fixit-cxx11-attributes.cpp
@@ -16,15 +16,15 @@
    // CHECK: fix-it:{{.*}}:{14:37-14:51}
 
   class base {};
-  class [[]] [[]] final_class 
+  class [[]] [[]] final_class
     alignas(float) [[]] final // expected-error {{an attribute list cannot appear here}}
     alignas(float) [[]] [[]] alignas(float): base{}; // expected-error {{an attribute list cannot appear here}}
     // CHECK: fix-it:{{.*}}:{19:19-19:19}
     // CHECK: fix-it:{{.*}}:{20:5-20:25}
     // CHECK: fix-it:{{.*}}:{19:19-19:19}
     // CHECK: fix-it:{{.*}}:{21:5-21:44}
 
-  class [[]] [[]] final_class_another 
+  class [[]] [[]] final_class_another
     [[]] [[]] alignas(16) final // expected-error {{an attribute list cannot appear here}}
     [[]] [[]] alignas(16) [[]]{}; // expected-error {{an attribute list cannot appear here}}
     // CHECK: fix-it:{{.*}}:{27:19-27:19}
@@ -49,3 +49,6 @@
   // 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: lib/Sema/ParsedAttr.cpp
===================================================================
--- lib/Sema/ParsedAttr.cpp
+++ lib/Sema/ParsedAttr.cpp
@@ -105,11 +105,15 @@
 
 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: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -3790,6 +3790,28 @@
     }
     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'
@@ -3868,8 +3890,7 @@
     return false;
   }
 
-  if (ScopeName &&
-      (ScopeName->getName() == "gnu" || ScopeName->getName() == "__gnu__")) {
+  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,
@@ -3879,10 +3900,9 @@
 
   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: lib/Basic/Attributes.cpp
===================================================================
--- lib/Basic/Attributes.cpp
+++ lib/Basic/Attributes.cpp
@@ -12,10 +12,12 @@
   if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
     Name = Name.substr(2, Name.size() - 4);
 
-  // Normalize the scope name, but only for gnu attributes.
+  // Normalize the scope name, but only for gnu and clang attributes.
   StringRef ScopeName = Scope ? Scope->getName() : "";
   if (ScopeName == "__gnu__")
-    ScopeName = ScopeName.slice(2, ScopeName.size() - 2);
+    ScopeName = "gnu";
+  else if (ScopeName == "_Clang")
+    ScopeName = "clang";
 
 #include "clang/Basic/AttrHasAttributeImpl.inc"
 
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -575,6 +575,9 @@
 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>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D53700: S... Aaron Ballman via Phabricator via cfe-commits

Reply via email to