class TargetArch<list<string> arches> {
list<string> Arches = arches;
list<string> OSes;
+ list<string> CXXABIs;
}
def TargetARM : TargetArch<["arm", "thumb"]>;
+def TargetMips : TargetArch<["mips", "mipsel"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
def TargetX86 : TargetArch<["x86"]>;
def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
let OSes = ["Win32"];
}
-def TargetMips : TargetArch<["mips", "mipsel"]>;
+def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
+ let CXXABIs = ["Microsoft"];
+}
class Attr {
// The various ways in which an attribute can be spelled in source
// Microsoft-related attributes
-def MSNoVTable : InheritableAttr {
+def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
let Spellings = [Declspec<"novtable">];
let Subjects = SubjectList<[CXXRecord]>;
let Documentation = [MSNoVTableDocs];
#define LLVM_CLANG_BASIC_ATTRIBUTES_H
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/Triple.h"
+#include "clang/Basic/TargetInfo.h"
namespace clang {
/// \brief Return the version number associated with the attribute if we
/// recognize and implement the attribute specified by the given information.
int hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
- const IdentifierInfo *Attr, const llvm::Triple &T,
+ const IdentifierInfo *Attr, const TargetInfo &Target,
const LangOptions &LangOpts);
} // end namespace clang
#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/VersionTuple.h"
#include "clang/Sema/Ownership.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Support/Allocator.h"
#include <cassert>
bool hasVariadicArg() const;
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
bool diagnoseLangOpts(class Sema &S) const;
- bool existsInTarget(const llvm::Triple &T) const;
+ bool existsInTarget(const TargetInfo &Target) const;
bool isKnownToGCC() const;
/// \brief If the parsed attribute has a semantic equivalent, and it would
using namespace clang;
int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
- const IdentifierInfo *Attr, const llvm::Triple &T,
- const LangOptions &LangOpts) {
+ const IdentifierInfo *Attr, const TargetInfo &Target,
+ const LangOptions &LangOpts) {
StringRef Name = Attr->getName();
// Normalize the attribute name, __foo__ becomes foo.
if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
Value = FeatureII->getBuiltinID() != 0;
} else if (II == Ident__has_attribute)
Value = hasAttribute(AttrSyntax::GNU, nullptr, FeatureII,
- getTargetInfo().getTriple(), getLangOpts());
+ getTargetInfo(), getLangOpts());
else if (II == Ident__has_cpp_attribute)
Value = hasAttribute(AttrSyntax::CXX, ScopeII, FeatureII,
- getTargetInfo().getTriple(), getLangOpts());
+ getTargetInfo(), getLangOpts());
else if (II == Ident__has_declspec)
Value = hasAttribute(AttrSyntax::Declspec, nullptr, FeatureII,
- getTargetInfo().getTriple(), getLangOpts());
+ getTargetInfo(), getLangOpts());
else if (II == Ident__has_extension)
Value = HasExtension(*this, FeatureII);
else {
// If the attribute isn't known, we will not attempt to parse any
// arguments.
if (!hasAttribute(AttrSyntax::Declspec, nullptr, AttrName,
- getTargetInfo().getTriple(), getLangOpts())) {
+ getTargetInfo(), getLangOpts())) {
// Eat the left paren, then skip to the ending right paren.
ConsumeParen();
SkipUntil(tok::r_paren);
// If the attribute isn't known, we will not attempt to parse any
// arguments.
if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName,
- getTargetInfo().getTriple(), getLangOpts())) {
+ getTargetInfo(), getLangOpts())) {
// Eat the left paren, then skip to the ending right paren.
ConsumeParen();
SkipUntil(tok::r_paren);
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
const Decl *);
bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
- bool (*ExistsInTarget)(const llvm::Triple &T);
+ bool (*ExistsInTarget)(const TargetInfo &Target);
unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
};
return getInfo(*this).IsType;
}
-bool AttributeList::existsInTarget(const llvm::Triple &T) const {
- return getInfo(*this).ExistsInTarget(T);
+bool AttributeList::existsInTarget(const TargetInfo &Target) const {
+ return getInfo(*this).ExistsInTarget(Target);
}
bool AttributeList::isKnownToGCC() const {
// which do not apply to the current target architecture are treated as
// though they were unknown attributes.
if (Attr.getKind() == AttributeList::UnknownAttribute ||
- !Attr.existsInTarget(S.Context.getTargetInfo().getTriple())) {
+ !Attr.existsInTarget(S.Context.getTargetInfo())) {
S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute()
? diag::warn_unhandled_ms_attribute_ignored
: diag::warn_unknown_attribute_ignored)
-// RUN: %clang_cc1 %s -triple i386-mingw32 -std=c++14 -fsyntax-only -Wno-unused-getter-return-value -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fms-compatibility -fdelayed-template-parsing
+// RUN: %clang_cc1 %s -triple i386-pc-win32 -std=c++14 -fsyntax-only -Wno-unused-getter-return-value -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fms-compatibility -fdelayed-template-parsing
/* Microsoft attribute tests */
[repeatable][source_annotation_attribute( Parameter|ReturnValue )]
-// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
struct __declspec(novtable) S {};
enum __declspec(novtable) E {}; // expected-warning{{'novtable' attribute only applies to classes}}
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-pc-windows-gnu %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
+
+// "novtable" is ignored except with the Microsoft C++ ABI.
+// MinGW uses the Itanium C++ ABI so check that it is ignored there.
+struct __declspec(novtable) S {}; // expected-warning{{__declspec attribute 'novtable' is not supported}}
}
}
- // It is assumed that there will be an llvm::Triple object named T within
+ // It is assumed that there will be an llvm::Triple object
+ // named "T" and a TargetInfo object named "Target" within
// scope that can be used to determine whether the attribute exists in
// a given target.
std::string Test;
}
Test += ")";
+ // If the attribute is specific to particular OSes, check those.
std::vector<std::string> OSes;
if (!R->isValueUnset("OSes")) {
Test += " && (";
Test += ")";
}
+ // If one or more CXX ABIs are specified, check those as well.
+ if (!R->isValueUnset("CXXABIs")) {
+ Test += " && (";
+ std::vector<std::string> CXXABIs =
+ R->getValueAsListOfStrings("CXXABIs");
+ for (auto AI = CXXABIs.begin(), AE = CXXABIs.end(); AI != AE; ++AI) {
+ std::string Part = *AI;
+
+ Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part;
+ if (AI + 1 != AE)
+ Test += " || ";
+ }
+ Test += ")";
+ }
+
// If this is the C++11 variety, also add in the LangOpts test.
if (Variety == "CXX11")
Test += " && LangOpts.CPlusPlus11";
}
}
+ OS << "const llvm::Triple &T = Target.getTriple();\n";
OS << "switch (Syntax) {\n";
OS << "case AttrSyntax::GNU:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
}
static void GenerateDefaultTargetRequirements(raw_ostream &OS) {
- OS << "static bool defaultTargetRequirements(const llvm::Triple &) {\n";
+ OS << "static bool defaultTargetRequirements(const TargetInfo &) {\n";
OS << " return true;\n";
OS << "}\n\n";
}
Test += ")";
}
+ // Test for the C++ ABI, if specified.
+ if (!R->isValueUnset("CXXABIs")) {
+ Test += " && (";
+ std::vector<std::string> CXXABIs = R->getValueAsListOfStrings("CXXABIs");
+ for (auto I = CXXABIs.begin(), E = CXXABIs.end(); I != E; ++I) {
+ std::string Part = *I;
+ Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part;
+ if (I + 1 != E)
+ Test += " || ";
+ FnName += Part;
+ }
+ Test += ")";
+ }
+
// If this code has already been generated, simply return the previous
// instance of it.
static std::set<std::string> CustomTargetSet;
if (I != CustomTargetSet.end())
return *I;
- OS << "static bool " << FnName << "(const llvm::Triple &T) {\n";
+ OS << "static bool " << FnName << "(const TargetInfo &Target) {\n";
+ OS << " const llvm::Triple &T = Target.getTriple();\n";
OS << " llvm::Triple::ArchType Arch = T.getArch();\n";
if (UsesOS)
OS << " llvm::Triple::OSType OS = T.getOS();\n";