diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 3 | ||||
-rw-r--r-- | clang/lib/Basic/Attributes.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 44 | ||||
-rw-r--r-- | clang/lib/Sema/ParsedAttr.cpp | 14 | ||||
-rw-r--r-- | clang/test/FixIt/fixit-cxx11-attributes.cpp | 3 | ||||
-rw-r--r-- | clang/test/Parser/cxx0x-attributes.cpp | 8 | ||||
-rw-r--r-- | clang/test/Preprocessor/has_attribute.cpp | 38 | ||||
-rw-r--r-- | clang/test/SemaCXX/attr-optnone.cpp | 6 |
8 files changed, 100 insertions, 38 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 1ca7c4a74ef..f47d88a82a4 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -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>; diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index 1c84d0779e1..9a8eb3d932c 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -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("__"))
- Name = Name.substr(2, Name.size() - 4);
-
- // Normalize the scope name, but only for gnu attributes.
- StringRef ScopeName = Scope ? Scope->getName() : "";
- if (ScopeName == "__gnu__")
- ScopeName = ScopeName.slice(2, ScopeName.size() - 2);
-
-#include "clang/Basic/AttrHasAttributeImpl.inc"
-
+ 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;
} diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 9369f0f56c9..c814775c77e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -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;
- }
-
- if (ScopeName &&
- (ScopeName->getName() == "gnu" || ScopeName->getName() == "__gnu__")) {
- // GNU-scoped attributes have some special cases to handle GNU-specific
- // behaviors.
- ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ 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, diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index ccfbe66db97..4c46063e2c1 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -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; } diff --git a/clang/test/FixIt/fixit-cxx11-attributes.cpp b/clang/test/FixIt/fixit-cxx11-attributes.cpp index 30697a90002..996fd185c37 100644 --- a/clang/test/FixIt/fixit-cxx11-attributes.cpp +++ b/clang/test/FixIt/fixit-cxx11-attributes.cpp @@ -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" diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp index e01491db413..101e03845b8 100644 --- a/clang/test/Parser/cxx0x-attributes.cpp +++ b/clang/test/Parser/cxx0x-attributes.cpp @@ -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?}} diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index 53d1fb07b9e..91f3501666f 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -18,17 +18,33 @@ // 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 unless it is for gnu.
-// CHECK: does_not_have___clang___fallthrough
-#if !__has_cpp_attribute(__clang__::fallthrough)
- int does_not_have___clang___fallthrough();
-#endif
-// CHECK: has_gnu_const
-#if __has_cpp_attribute(__gnu__::__const__)
- int has_gnu_const();
+ 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
// Test that C++11, target-specific attributes behave properly.
diff --git a/clang/test/SemaCXX/attr-optnone.cpp b/clang/test/SemaCXX/attr-optnone.cpp index 58776caf7ae..1e02653b95e 100644 --- a/clang/test/SemaCXX/attr-optnone.cpp +++ b/clang/test/SemaCXX/attr-optnone.cpp @@ -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}} |