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, 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; def ext_ns_enum_attribute : Extension< "attributes on %select{a namespace|an enumerator}0 declaration are " "a C++17 extension">, InGroup; 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: 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/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: test/FixIt/fixit-cxx11-attributes.cpp =================================================================== --- test/FixIt/fixit-cxx11-attributes.cpp +++ test/FixIt/fixit-cxx11-attributes.cpp @@ -16,7 +16,7 @@ // 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} @@ -24,7 +24,7 @@ // 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: 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/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/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}}