summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2014-01-09 22:57:44 +0000
committerAaron Ballman <aaron@aaronballman.com>2014-01-09 22:57:44 +0000
commit0fa06d879ace8a2c934590a8f4e461875bd2745c (patch)
tree7b82dcb898402d0e534b603c70a6ffaa433edfdf
parentab7691c4ce72faf49e14fe715ec608f236742e24 (diff)
downloadbcm5719-llvm-0fa06d879ace8a2c934590a8f4e461875bd2745c.tar.gz
bcm5719-llvm-0fa06d879ace8a2c934590a8f4e461875bd2745c.zip
__has_attribute now understands target-specific attributes. So when you ask whether an ARM target has the "interrupt" attribute, it will return true for ARM and MSP430 targets, and false for others.
llvm-svn: 198897
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp4
-rw-r--r--clang/test/Preprocessor/has_attribute.c12
-rw-r--r--clang/utils/TableGen/ClangAttrEmitter.cpp49
3 files changed, 56 insertions, 9 deletions
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 3f597581234..c6559b460be 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1045,7 +1045,7 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
/// HasAttribute - Return true if we recognize and implement the attribute
/// specified by the given identifier.
-static bool HasAttribute(const IdentifierInfo *II) {
+static bool HasAttribute(const IdentifierInfo *II, const llvm::Triple &T) {
StringRef Name = II->getName();
// Normalize the attribute name, __foo__ becomes foo.
if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
@@ -1395,7 +1395,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// Check for a builtin is trivial.
Value = FeatureII->getBuiltinID() != 0;
} else if (II == Ident__has_attribute)
- Value = HasAttribute(FeatureII);
+ Value = HasAttribute(FeatureII, getTargetInfo().getTriple());
else if (II == Ident__has_extension)
Value = HasExtension(*this, FeatureII);
else {
diff --git a/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c
index 555c2b3f9e2..5fe060e68d3 100644
--- a/clang/test/Preprocessor/has_attribute.c
+++ b/clang/test/Preprocessor/has_attribute.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -E %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm-unknown-linux -E %s -o - | FileCheck %s
// CHECK: always_inline
#if __has_attribute(always_inline)
@@ -38,3 +38,13 @@ int has_something_we_dont_have();
#if !__has_attribute(volatile)
int has_no_volatile_attribute();
#endif
+
+// CHECK: has_arm_interrupt
+#if __has_attribute(interrupt)
+ int has_arm_interrupt();
+#endif
+
+// CHECK: does_not_have_dllexport
+#if !__has_attribute(dllexport)
+ int does_not_have_dllexport();
+#endif
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index a3edd787a44..ed451d559ff 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -1537,18 +1537,55 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
// Emits the list of spellings for attributes.
void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("llvm::StringSwitch code to match all known attributes",
- OS);
+ emitSourceFileHeader("llvm::StringSwitch code to match attributes based on "
+ "the target triple, T", OS);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
- for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
Record &Attr = **I;
- std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
+ // It is assumed that there will be an llvm::Triple object named T within
+ // scope that can be used to determine whether the attribute exists in
+ // a given target.
+ std::string Test;
+ if (Attr.isSubClassOf("TargetSpecificAttr")) {
+ const Record *R = Attr.getValueAsDef("Target");
+ std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
+
+ Test += "(";
+ for (std::vector<std::string>::const_iterator AI = Arches.begin(),
+ AE = Arches.end(); AI != AE; ++AI) {
+ std::string Part = *AI;
+ Test += "T.getArch() == llvm::Triple::" + Part;
+ if (AI + 1 != AE)
+ Test += " || ";
+ }
+ Test += ")";
+
+ std::vector<std::string> OSes;
+ if (!R->isValueUnset("OSes")) {
+ Test += " && (";
+ std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes");
+ for (std::vector<std::string>::const_iterator AI = OSes.begin(),
+ AE = OSes.end(); AI != AE; ++AI) {
+ std::string Part = *AI;
+
+ Test += "T.getOS() == llvm::Triple::" + Part;
+ if (AI + 1 != AE)
+ Test += " || ";
+ }
+ Test += ")";
+ }
+ } else
+ Test = "true";
- for (std::vector<Record*>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) {
- OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", true)\n";
+ std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
+ for (std::vector<Record*>::const_iterator I = Spellings.begin(),
+ E = Spellings.end(); I != E; ++I) {
+ OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", " << Test;
+ OS << ")\n";
}
}
OpenPOWER on IntegriCloud