summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2018-10-24 12:26:23 +0000
committerAaron Ballman <aaron@aaronballman.com>2018-10-24 12:26:23 +0000
commitad672ffb643c646ca7680c765342bd58252ecdbe (patch)
tree983949541e2d1345350ca5f6f01833b6db7a09da
parentc4a995c8e05bd63932677ee30e4f4cfd6623eaff (diff)
downloadbcm5719-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.h5
-rw-r--r--clang/lib/Basic/Attributes.cpp17
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp15
-rw-r--r--clang/lib/Sema/ParsedAttr.cpp26
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp18
-rw-r--r--clang/lib/Sema/SemaType.cpp2
-rw-r--r--clang/test/Preprocessor/has_attribute.cpp26
-rw-r--r--clang/test/SemaCXX/attr-gnu.cpp21
-rw-r--r--clang/utils/TableGen/ClangAttrEmitter.cpp18
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";
};
OpenPOWER on IntegriCloud