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>;
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
}
}
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'
// 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,
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;
}
// 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"
[[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?}}
// 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
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}}