Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -267,13 +267,24 @@ def ObjC : LangOpt<"ObjC1">; def BlocksSupported : LangOpt<"Blocks">; -// Defines targets for target-specific attributes. The list of strings should -// specify architectures for which the target applies, based off the ArchType -// enumeration in Triple.h. -class TargetArch arches> { - list Arches = arches; +// Defines targets for target-specific attributes. Empty lists are unchecked. +class TargetSpec { + // Specifies Architectures for which the target applies, based off the + // ArchType enumeration in Triple.h. + list Arches = []; + // Specifies Operating Systems for which the target applies, based off the + // OSType enumeration in Triple.h list OSes; + // Specifies the C++ ABIs for which the target applies, based off the + // TargetCXXABI::Kind in TargetCXXABI.h. list CXXABIs; + // Specifies Object Formats for which the target applies, based off the + // ObjectFormatType enumeration in Triple.h + list ObjectFormats; +} + +class TargetArch arches> : TargetSpec { + let Arches = arches; } def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>; def TargetAVR : TargetArch<["avr"]>; @@ -288,6 +299,9 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> { let CXXABIs = ["Microsoft"]; } +def TargetELF : TargetSpec { + let ObjectFormats = ["ELF"]; +} // Attribute subject match rules that are used for #pragma clang attribute. // @@ -465,8 +479,8 @@ /// A target-specific attribute. This class is meant to be used as a mixin /// with InheritableAttr or Attr depending on the attribute's needs. -class TargetSpecificAttr { - TargetArch Target = target; +class TargetSpecificAttr { + TargetSpec Target = target; // Attributes are generally required to have unique spellings for their names // so that the parser can determine what kind of attribute it has parsed. // However, target-specific attributes are special in that the attribute only @@ -1121,7 +1135,7 @@ let Documentation = [Undocumented]; } -def IFunc : Attr { +def IFunc : Attr, TargetSpecificAttr { let Spellings = [GCC<"ifunc">]; let Args = [StringArgument<"Resolver">]; let Subjects = SubjectList<[Function]>; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -1844,12 +1844,6 @@ S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1; return; } - // FIXME: it should be handled as a target specific attribute. - if (S.Context.getTargetInfo().getTriple().getObjectFormat() != - llvm::Triple::ELF) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return; - } D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str, Attr.getAttributeSpellingListIndex())); Index: test/Sema/attr-ifunc.c =================================================================== --- test/Sema/attr-ifunc.c +++ test/Sema/attr-ifunc.c @@ -5,7 +5,7 @@ #if defined(_WIN32) void foo() {} void bar() __attribute__((ifunc("foo"))); -//expected-warning@-1 {{'ifunc' attribute ignored}} +//expected-warning@-1 {{unknown attribute 'ifunc' ignored}} #else #if defined(CHECK_ALIASES) Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2622,6 +2622,31 @@ OS << " }\n"; } +// Helper function for GenerateTargetSpecificAttrChecks that alters the 'Test' +// parameter with only a single check type, if applicable. +static void GenerateTargetSpecificAttrCheck(const Record *R, std::string &Test, + std::string *FnName, + StringRef ListName, + StringRef CheckAgainst, + StringRef Scope) { + if (!R->isValueUnset(ListName)) { + Test += " && ("; + std::vector Items = R->getValueAsListOfStrings(ListName); + for (auto I = Items.begin(), E = Items.end(); I != E; ++I) { + StringRef Part = *I; + Test += CheckAgainst; + Test += " == "; + Test += Scope; + Test += Part; + if (I + 1 != E) + Test += " || "; + if (FnName) + *FnName += Part; + } + Test += ")"; + } +} + // Generate a conditional expression to check if the current target satisfies // the conditions for a TargetSpecificAttr record, and append the code for // those checks to the Test string. If the FnName string pointer is non-null, @@ -2635,29 +2660,15 @@ // named "T" and a TargetInfo object named "Target" within // scope that can be used to determine whether the attribute exists in // a given target. - Test += "("; - - for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) { - StringRef Part = *I; - Test += "T.getArch() == llvm::Triple::"; - Test += Part; - if (I + 1 != E) - Test += " || "; - if (FnName) - *FnName += Part; - } - Test += ")"; - - // If the attribute is specific to particular OSes, check those. - if (!R->isValueUnset("OSes")) { - // We know that there was at least one arch test, so we need to and in the - // OS tests. + Test += "true"; + // If one or more architectures is specified, check those. Arches are handled + // differently because GenerateTargetRequiresments needs to combine the list + // with ParseKind. + if (!Arches.empty()) { Test += " && ("; - std::vector OSes = R->getValueAsListOfStrings("OSes"); - for (auto I = OSes.begin(), E = OSes.end(); I != E; ++I) { + for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) { StringRef Part = *I; - - Test += "T.getOS() == llvm::Triple::"; + Test += "T.getArch() == llvm::Triple::"; Test += Part; if (I + 1 != E) Test += " || "; @@ -2667,21 +2678,17 @@ Test += ")"; } + // If the attribute is specific to particular OSes, check those. + GenerateTargetSpecificAttrCheck(R, Test, FnName, "OSes", "T.getOS()", + "llvm::Triple::"); + // If one or more CXX ABIs are specified, check those as well. - if (!R->isValueUnset("CXXABIs")) { - Test += " && ("; - std::vector CXXABIs = R->getValueAsListOfStrings("CXXABIs"); - for (auto I = CXXABIs.begin(), E = CXXABIs.end(); I != E; ++I) { - StringRef Part = *I; - Test += "Target.getCXXABI().getKind() == TargetCXXABI::"; - Test += Part; - if (I + 1 != E) - Test += " || "; - if (FnName) - *FnName += Part; - } - Test += ")"; - } + GenerateTargetSpecificAttrCheck(R, Test, FnName, "CXXABIs", + "Target.getCXXABI().getKind()", + "TargetCXXABI::"); + // If one or more object formats is specified, check those. + GenerateTargetSpecificAttrCheck(R, Test, FnName, "ObjectFormats", + "T.getObjectFormat()", "llvm::Triple::"); } static void GenerateHasAttrSpellingStringSwitch( @@ -3301,11 +3308,6 @@ // Get the list of architectures to be tested for. const Record *R = Attr.getValueAsDef("Target"); std::vector Arches = R->getValueAsListOfStrings("Arches"); - if (Arches.empty()) { - PrintError(Attr.getLoc(), "Empty list of target architectures for a " - "target-specific attr"); - return "defaultTargetRequirements"; - } // If there are other attributes which share the same parsed attribute kind, // such as target-specific attributes with a shared spelling, collapse the