From 51b58b36f8e3d39eec770d9c0795efa787e47223 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Thu, 9 Jan 2014 22:57:44 +0000 Subject: [PATCH] __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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@198897 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Lex/PPMacroExpansion.cpp | 4 +-- test/Preprocessor/has_attribute.c | 12 ++++++- utils/TableGen/ClangAttrEmitter.cpp | 49 +++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 3f59758123..c6559b460b 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/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/test/Preprocessor/has_attribute.c b/test/Preprocessor/has_attribute.c index 555c2b3f9e..5fe060e68d 100644 --- a/test/Preprocessor/has_attribute.c +++ b/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/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index a3edd787a4..ed451d559f 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/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 Attrs = Records.getAllDerivedDefinitions("Attr"); - for (std::vector::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { + for (std::vector::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { Record &Attr = **I; - std::vector 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 Arches = R->getValueAsListOfStrings("Arches"); + + Test += "("; + for (std::vector::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 OSes; + if (!R->isValueUnset("OSes")) { + Test += " && ("; + std::vector OSes = R->getValueAsListOfStrings("OSes"); + for (std::vector::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::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { - OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", true)\n"; + std::vector Spellings = Attr.getValueAsListOfDefs("Spellings"); + for (std::vector::const_iterator I = Spellings.begin(), + E = Spellings.end(); I != E; ++I) { + OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", " << Test; + OS << ")\n"; } } -- 2.40.0