diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2018-10-24 12:26:23 +0000 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2018-10-24 12:26:23 +0000 |
commit | ad672ffb643c646ca7680c765342bd58252ecdbe (patch) | |
tree | 983949541e2d1345350ca5f6f01833b6db7a09da | |
parent | c4a995c8e05bd63932677ee30e4f4cfd6623eaff (diff) | |
download | bcm5719-llvm-ad672ffb643c646ca7680c765342bd58252ecdbe.tar.gz bcm5719-llvm-ad672ffb643c646ca7680c765342bd58252ecdbe.zip |
Support accepting __gnu__ as a scoped attribute namespace that aliases to gnu.
This is useful in libstdc++ to avoid clashes with identifiers in the user's namespace.
llvm-svn: 345132
-rw-r--r-- | clang/include/clang/Sema/ParsedAttr.h | 5 | ||||
-rw-r--r-- | clang/lib/Basic/Attributes.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Sema/ParsedAttr.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 2 | ||||
-rw-r--r-- | clang/test/Preprocessor/has_attribute.cpp | 26 | ||||
-rw-r--r-- | clang/test/SemaCXX/attr-gnu.cpp | 21 | ||||
-rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.cpp | 18 |
9 files changed, 90 insertions, 58 deletions
diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 7561e835747..11202cb137b 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -383,6 +383,11 @@ public: IdentifierInfo *getScopeName() const { return ScopeName; } SourceLocation getScopeLoc() const { return ScopeLoc; } + bool isGNUScope() const { + return ScopeName && + (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); + } + bool hasParsedType() const { return HasParsedType; } /// Is this the Microsoft __declspec(property) attribute? diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index b7570d03c85..1c84d0779e1 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -9,12 +9,17 @@ 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); - -#include "clang/Basic/AttrHasAttributeImpl.inc" - - return 0; + 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"
+
+ return 0;
} const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) { diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index a86f7ed8642..63e7179a74c 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3865,13 +3865,14 @@ 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") { - // GNU-scoped attributes have some special cases to handle GNU-specific - // behaviors. - ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, + 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,
ScopeLoc, Syntax, nullptr); return true; } diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 3dff0ad63e2..ccfbe66db97 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -103,14 +103,25 @@ void AttributePool::takePool(AttributePool &pool) { #include "clang/Sema/AttrParsedAttrKinds.inc" -static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName, +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); + return ScopeName; +} + +static StringRef normalizeAttrName(StringRef AttrName, + StringRef NormalizedScopeName, ParsedAttr::Syntax SyntaxUsed) { // Normalize the attribute name, __foo__ becomes foo. This is only allowable - // for GNU attributes. + // for GNU attributes, and attributes using the double square bracket syntax. bool IsGNU = SyntaxUsed == ParsedAttr::AS_GNU || ((SyntaxUsed == ParsedAttr::AS_CXX11 || SyntaxUsed == ParsedAttr::AS_C2x) && - ScopeName == "gnu"); + NormalizedScopeName == "gnu"); if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") && AttrName.endswith("__")) AttrName = AttrName.slice(2, AttrName.size() - 2); @@ -125,7 +136,7 @@ ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name, SmallString<64> FullName; if (ScopeName) - FullName += ScopeName->getName(); + FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed); AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed); @@ -141,9 +152,10 @@ ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name, unsigned ParsedAttr::getAttributeSpellingListIndex() const { // Both variables will be used in tablegen generated // attribute spell list index matching code. - StringRef Scope = ScopeName ? ScopeName->getName() : ""; - StringRef Name = normalizeAttrName(AttrName->getName(), Scope, - (ParsedAttr::Syntax)SyntaxUsed); + auto Syntax = static_cast<ParsedAttr::Syntax>(SyntaxUsed); + StringRef Scope = + ScopeName ? normalizeAttrScopeName(ScopeName->getName(), Syntax) : ""; + StringRef Name = normalizeAttrName(AttrName->getName(), Scope, Syntax); #include "clang/Sema/AttrSpellingListIndex.inc" diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c0fb3356bae..a0faf840958 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5831,16 +5831,14 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.isDeclspecAttribute() || AL.isCXX11Attribute()) checkAttributeAtMostNumArgs(S, AL, 1); else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) && - !S.checkStringLiteralArgumentAttr(AL, 1, Replacement)) - return; - - if (!S.getLangOpts().CPlusPlus14) - if (AL.isCXX11Attribute() && - !(AL.hasScope() && AL.getScopeName()->isStr("gnu"))) - S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL; - - D->addAttr(::new (S.Context) - DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement, + !S.checkStringLiteralArgumentAttr(AL, 1, Replacement))
+ return;
+
+ if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope())
+ S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;
+
+ D->addAttr(::new (S.Context)
+ DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement,
AL.getAttributeSpellingListIndex())); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 27dbf70498d..85a57e75103 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -7273,7 +7273,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // not appertain to a DeclaratorChunk. If we handle them as type // attributes, accept them in that position and diagnose the GCC // incompatibility. - if (attr.getScopeName() && attr.getScopeName()->isStr("gnu")) { + if (attr.isGNUScope()) { bool IsTypeAttr = attr.isTypeAttr(); if (TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index 2cfa005fb09..53d1fb07b9e 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -18,17 +18,21 @@ // 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. -// CHECK: does_not_have___clang___fallthrough -#if !__has_cpp_attribute(__clang__::fallthrough) - int does_not_have___clang___fallthrough(); -#endif - -// Test that C++11, target-specific attributes behave properly. - + 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();
+#endif
+
+// Test that C++11, target-specific attributes behave properly.
+
// CHECK: does_not_have_mips16 #if !__has_cpp_attribute(gnu::mips16) int does_not_have_mips16(); diff --git a/clang/test/SemaCXX/attr-gnu.cpp b/clang/test/SemaCXX/attr-gnu.cpp index a553f0d2100..9eb42342df3 100644 --- a/clang/test/SemaCXX/attr-gnu.cpp +++ b/clang/test/SemaCXX/attr-gnu.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -fms-compatibility -verify %s - -void f() { - // GNU-style attributes are prohibited in this position. +// RUN: %clang_cc1 -std=gnu++17 -fsyntax-only -fms-compatibility -verify %s
+
+void f() {
+ // GNU-style attributes are prohibited in this position.
auto P = new int * __attribute__((vector_size(8))); // expected-error {{an attribute list cannot appear here}} \ // expected-error {{invalid vector element type 'int *'}} @@ -40,6 +40,13 @@ void tuTest1(Tu<int> u); // expected-note {{candidate function not viable: no kn void tuTest2(Tu3 u); // expected-note {{candidate function not viable: no known conversion from 'int' to 'Tu3' for 1st argument}} void tu() { int x = 2; - tuTest1(x); // expected-error {{no matching function for call to 'tuTest1'}} - tuTest2(x); // expected-error {{no matching function for call to 'tuTest2'}} -} + tuTest1(x); // expected-error {{no matching function for call to 'tuTest1'}}
+ tuTest2(x); // expected-error {{no matching function for call to 'tuTest2'}}
+}
+
+[[gnu::__const__]] int f2() { return 12; }
+[[__gnu__::__const__]] int f3() { return 12; }
+[[using __gnu__ : __const__]] int f4() { return 12; }
+
+static_assert(__has_cpp_attribute(gnu::__const__));
+static_assert(__has_cpp_attribute(__gnu__::__const__));
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 59eab397733..43e6638f7f4 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2932,15 +2932,15 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << "case AttrSyntax::" << Variety << ": {\n"; // C++11-style attributes are further split out based on the Scope. for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { - if (I != List.cbegin()) - OS << " else "; - if (I->first.empty()) - OS << "if (!Scope || Scope->getName() == \"\") {\n"; - else - OS << "if (Scope->getName() == \"" << I->first << "\") {\n"; - OS << " return llvm::StringSwitch<int>(Name)\n"; - GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); - OS << "}"; + if (I != List.cbegin())
+ OS << " else ";
+ if (I->first.empty())
+ OS << "if (ScopeName == \"\") {\n";
+ else
+ OS << "if (ScopeName == \"" << I->first << "\") {\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first);
+ OS << "}";
} OS << "\n} break;\n"; }; |