diff options
-rw-r--r-- | clang/include/clang/Basic/Attr.td | 42 | ||||
-rw-r--r-- | clang/include/clang/Sema/AttributeList.h | 5 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | clang/lib/Sema/AttributeList.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 235 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmtAttr.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/TargetAttributesSema.cpp | 295 | ||||
-rw-r--r-- | clang/lib/Sema/TargetAttributesSema.h | 27 | ||||
-rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.cpp | 117 |
11 files changed, 367 insertions, 378 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index e5265f2b7fc..33e58f46bb1 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -142,6 +142,21 @@ def MicrosoftExt : LangOpt<"MicrosoftExt">; def Borland : LangOpt<"Borland">; def CUDA : LangOpt<"CUDA">; +// 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<list<string> arches> { + list<string> Arches = arches; + list<string> OSes; +} +def TargetARM : TargetArch<["arm", "thumb"]>; +def TargetMSP430 : TargetArch<["msp430"]>; +def TargetX86 : TargetArch<["x86"]>; +def TargetX86Win : TargetArch<["x86", "x86_64"]> { + let OSes = ["Win32", "MinGW32"]; +} +def TargetMips : TargetArch<["mips", "mipsel"]>; + class Attr { // The various ways in which an attribute can be spelled in source list<Spelling> Spellings; @@ -187,10 +202,10 @@ class TypeAttr : Attr { /// An inheritable attribute is inherited by later redeclarations. class InheritableAttr : Attr; -/// A target-specific attribute that is meant to be processed via -/// TargetAttributesSema::ProcessDeclAttribute. This class is meant to be used -/// as a mixin with InheritableAttr or Attr depending on the attribute's needs. -class TargetSpecificAttr { +/// 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> { + TargetArch 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 @@ -269,7 +284,7 @@ def Annotate : InheritableParamAttr { let Args = [StringArgument<"Annotation">]; } -def ARMInterrupt : InheritableAttr, TargetSpecificAttr { +def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> { // NOTE: If you add any additional spellings, MSP430Interrupt's spellings // must match. let Spellings = [GNU<"interrupt">]; @@ -547,7 +562,7 @@ def MSABI : InheritableAttr { // let Subjects = [Function, ObjCMethod]; } -def MSP430Interrupt : InheritableAttr, TargetSpecificAttr { +def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> { // NOTE: If you add any additional spellings, ARMInterrupt's spellings must // match. let Spellings = [GNU<"interrupt">]; @@ -556,7 +571,7 @@ def MSP430Interrupt : InheritableAttr, TargetSpecificAttr { let HasCustomParsing = 1; } -def Mips16 : InheritableAttr, TargetSpecificAttr { +def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { let Spellings = [GNU<"mips16">, CXX11<"gnu", "mips16">]; let Subjects = SubjectList<[Function], ErrorDiag>; } @@ -600,7 +615,7 @@ def NoInline : InheritableAttr { let Subjects = SubjectList<[Function]>; } -def NoMips16 : InheritableAttr, TargetSpecificAttr { +def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> { let Spellings = [GNU<"nomips16">, CXX11<"gnu", "nomips16">]; let Subjects = SubjectList<[Function], ErrorDiag>; } @@ -952,8 +967,11 @@ def WeakRef : InheritableAttr { let Subjects = SubjectList<[Var, Function], ErrorDiag>; } -def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr { - let Spellings = []; +def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> { + let Spellings = [GNU<"force_align_arg_pointer">]; + // Technically, this appertains to a FunctionDecl, but the target-specific + // code silently allows anything function-like (such as typedefs or function + // pointers), but does not apply the attribute to them. } // Attribute to disable AddressSanitizer (or equivalent) checks. @@ -1232,12 +1250,12 @@ def MsStruct : InheritableAttr { let Subjects = SubjectList<[Record]>; } -def DLLExport : InheritableAttr, TargetSpecificAttr { +def DLLExport : InheritableAttr, TargetSpecificAttr<TargetX86Win> { let Spellings = [Declspec<"dllexport">]; let Subjects = SubjectList<[Function, Var]>; } -def DLLImport : InheritableAttr, TargetSpecificAttr { +def DLLImport : InheritableAttr, TargetSpecificAttr<TargetX86Win> { let Spellings = [Declspec<"dllimport">]; // Technically, the subjects for DllImport are Function and Var, but there is // custom semantic handling required when MicrosoftExt is true. diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h index 359259b9e8d..7311a8fdfb1 100644 --- a/clang/include/clang/Sema/AttributeList.h +++ b/clang/include/clang/Sema/AttributeList.h @@ -20,6 +20,7 @@ #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> @@ -484,11 +485,15 @@ public: /// to pretty print itself. unsigned getAttributeSpellingListIndex() const; + bool isTargetSpecificAttr() const; + bool isTypeAttr() const; + bool hasCustomParsing() const; unsigned getMinArgs() const; unsigned getMaxArgs() const; bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const; bool diagnoseLangOpts(class Sema &S) const; + bool existsInTarget(llvm::Triple T) const; }; /// A factory, from which one makes pools, from which one creates diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 270d18dde62..733f0262e2b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -152,7 +152,6 @@ namespace clang { class Stmt; class StringLiteral; class SwitchStmt; - class TargetAttributesSema; class TemplateArgument; class TemplateArgumentList; class TemplateArgumentLoc; @@ -204,7 +203,6 @@ typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>, class Sema { Sema(const Sema &) LLVM_DELETED_FUNCTION; void operator=(const Sema &) LLVM_DELETED_FUNCTION; - mutable const TargetAttributesSema* TheTargetAttributesSema; ///\brief Source of additional semantic information. ExternalSemaSource *ExternalSource; @@ -875,7 +873,6 @@ public: DiagnosticsEngine &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } - const TargetAttributesSema &getTargetAttributesSema() const; Preprocessor &getPreprocessor() const { return PP; } ASTContext &getASTContext() const { return Context; } ASTConsumer &getASTConsumer() const { return Consumer; } diff --git a/clang/lib/Sema/AttributeList.cpp b/clang/lib/Sema/AttributeList.cpp index c079c30382c..58a3e23c1b0 100644 --- a/clang/lib/Sema/AttributeList.cpp +++ b/clang/lib/Sema/AttributeList.cpp @@ -156,10 +156,13 @@ struct ParsedAttrInfo { unsigned NumArgs : 4; unsigned OptArgs : 4; unsigned HasCustomParsing : 1; + unsigned IsTargetSpecific : 1; + unsigned IsType : 1; bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr, const Decl *); bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr); + bool (*ExistsInTarget)(llvm::Triple T); }; namespace { @@ -189,3 +192,15 @@ bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const { bool AttributeList::diagnoseLangOpts(Sema &S) const { return getInfo(*this).DiagLangOpts(S, *this); } + +bool AttributeList::isTargetSpecificAttr() const { + return getInfo(*this).IsTargetSpecific; +} + +bool AttributeList::isTypeAttr() const { + return getInfo(*this).IsType; +} + +bool AttributeList::existsInTarget(llvm::Triple T) const { + return getInfo(*this).ExistsInTarget(T); +} diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index c4ebeb59407..75702e1d8b2 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -47,7 +47,6 @@ add_clang_library(clangSema SemaTemplateInstantiateDecl.cpp SemaTemplateVariadic.cpp SemaType.cpp - TargetAttributesSema.cpp TypeLocBuilder.cpp ) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 1c748f61e06..c824921a4f1 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" -#include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclCXX.h" @@ -70,7 +69,7 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) - : TheTargetAttributesSema(0), ExternalSource(0), + : ExternalSource(0), isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), @@ -209,7 +208,6 @@ Sema::~Sema() { delete I->second; if (PackContext) FreePackedContext(); if (VisContext) FreeVisContext(); - delete TheTargetAttributesSema; MSStructPragmaOn = false; // Kill all the active scopes. for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 23649c66940..945525bdd54 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" -#include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -205,7 +204,6 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, return true; } - /// \brief Check if the attribute has at least as many args as Num. May /// output an error. static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, @@ -3174,8 +3172,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, return true; } - // TODO: diagnose uses of these conventions on the wrong target. Or, better - // move to TargetAttributesSema one day. + // TODO: diagnose uses of these conventions on the wrong target. switch (attr.getKind()) { case AttributeList::AT_CDecl: CC = CC_C; break; case AttributeList::AT_FastCall: CC = CC_X86FastCall; break; @@ -3712,6 +3709,179 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleARMInterruptAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // Check the attribute arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 1; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + + if (Attr.getNumArgs() == 0) + Str = ""; + else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + return; + + ARMInterruptAttr::InterruptType Kind; + if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << Attr.getName() << Str << ArgLoc; + return; + } + + unsigned Index = Attr.getAttributeSpellingListIndex(); + D->addAttr(::new (S.Context) + ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); +} + +static void handleMSP430InterruptAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!checkAttributeNumArgs(S, Attr, 1)) + return; + + if (!Attr.isArgExpr(0)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + << AANT_ArgumentIntegerConstant; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + llvm::APSInt NumParams(32); + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) + << Attr.getName() << AANT_ArgumentIntegerConstant + << NumParamsExpr->getSourceRange(); + return; + } + + unsigned Num = NumParams.getLimitedValue(255); + if ((Num & 1) || Num > 30) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << Attr.getName() << (int)NumParams.getSExtValue() + << NumParamsExpr->getSourceRange(); + return; + } + + D->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num)); + D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); +} + +static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { + // Dispatch the interrupt attribute based on the current target. + if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430) + handleMSP430InterruptAttr(S, D, Attr); + else + handleARMInterruptAttr(S, D, Attr); +} + +static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, + const AttributeList& Attr) { + // If we try to apply it to a function pointer, don't warn, but don't + // do anything, either. It doesn't matter anyway, because there's nothing + // special about calling a force_align_arg_pointer function. + ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (VD && VD->getType()->isFunctionPointerType()) + return; + // Also don't warn on function pointer typedefs. + TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || + TD->getUnderlyingType()->isFunctionType())) + return; + // Attribute can only be applied to function types. + if (!isa<FunctionDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << /* function */0; + return; + } + + D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(), + S.Context)); +} + +DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (D->hasAttr<DLLExportAttr>()) { + Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport"; + return NULL; + } + + if (D->hasAttr<DLLImportAttr>()) + return NULL; + + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasDefinition()) { + // dllimport cannot be applied to definitions. + Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition) + << "dllimport"; + return NULL; + } + } + + return ::new (Context)DLLImportAttr(Range, Context, + AttrSpellingListIndex); +} + +static void handleDLLImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { + // Attribute can be applied only to functions or variables. + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD && !isa<VarDecl>(D)) { + // Apparently Visual C++ thinks it is okay to not emit a warning + // in this case, so only emit a warning when -fms-extensions is not + // specified. + if (!S.getLangOpts().MicrosoftExt) + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; + } + + // Currently, the dllimport attribute is ignored for inlined functions. + // Warning is emitted. + if (FD && FD->isInlineSpecified()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + return; + } + + unsigned Index = Attr.getAttributeSpellingListIndex(); + DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index); + if (NewAttr) + D->addAttr(NewAttr); +} + +DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) { + Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport"; + D->dropAttr<DLLImportAttr>(); + } + + if (D->hasAttr<DLLExportAttr>()) + return NULL; + + return ::new (Context)DLLExportAttr(Range, Context, + AttrSpellingListIndex); +} + +static void handleDLLExportAttr(Sema &S, Decl *D, const AttributeList &Attr) { + // Currently, the dllexport attribute is ignored for inlined functions, unless + // the -fkeep-inline-functions flag has been used. Warning is emitted; + if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isInlineSpecified()) { + // FIXME: ... unless the -fkeep-inline-functions flag has been used. + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + return; + } + + unsigned Index = Attr.getAttributeSpellingListIndex(); + DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index); + if (NewAttr) + D->addAttr(NewAttr); +} + /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. @@ -3723,8 +3893,7 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, // We also bail on unknown and ignored attributes because those are handled // as part of the target-specific handling logic. if (Attr.hasCustomParsing() || - Attr.getKind() == AttributeList::UnknownAttribute || - Attr.getKind() == AttributeList::IgnoredAttribute) + Attr.getKind() == AttributeList::UnknownAttribute) return false; // Check whether the attribute requires specific language extensions to be @@ -3755,7 +3924,7 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr, bool IncludeCXX11Attributes) { - if (Attr.isInvalid()) + if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute) return; // Ignore C++11 attributes on declarator chunks: they appertain to the type @@ -3763,28 +3932,42 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes) return; + // Unknown attributes are automatically warned on. Target-specific attributes + // 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())) { + S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ? + diag::warn_unhandled_ms_attribute_ignored : + diag::warn_unknown_attribute_ignored) << Attr.getName(); + return; + } + if (handleCommonAttributeFeatures(S, scope, D, Attr)) return; switch (Attr.getKind()) { + default: + // Type attributes are handled elsewhere; silently move on. + assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + break; + case AttributeList::AT_Interrupt: + handleInterruptAttr(S, D, Attr); break; + case AttributeList::AT_X86ForceAlignArgPointer: + handleX86ForceAlignArgPointerAttr(S, D, Attr); break; + case AttributeList::AT_DLLExport: + handleDLLExportAttr(S, D, Attr); break; + case AttributeList::AT_DLLImport: + handleDLLImportAttr(S, D, Attr); break; + case AttributeList::AT_Mips16: + handleSimpleAttribute<Mips16Attr>(S, D, Attr); break; + case AttributeList::AT_NoMips16: + handleSimpleAttribute<NoMips16Attr>(S, D, Attr); break; case AttributeList::AT_IBAction: handleSimpleAttribute<IBActionAttr>(S, D, Attr); break; case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break; case AttributeList::AT_IBOutletCollection: handleIBOutletCollection(S, D, Attr); break; - case AttributeList::AT_AddressSpace: - case AttributeList::AT_ObjCGC: - case AttributeList::AT_VectorSize: - case AttributeList::AT_NeonVectorType: - case AttributeList::AT_NeonPolyVectorType: - case AttributeList::AT_Ptr32: - case AttributeList::AT_Ptr64: - case AttributeList::AT_SPtr: - case AttributeList::AT_UPtr: - case AttributeList::AT_Regparm: - // Ignore these, these are type attributes, handled by - // ProcessTypeAttributes. - break; case AttributeList::AT_Alias: handleAliasAttr (S, D, Attr); break; case AttributeList::AT_Aligned: handleAlignedAttr (S, D, Attr); break; case AttributeList::AT_AlwaysInline: @@ -3946,9 +4129,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NoDebug: handleNoDebugAttr (S, D, Attr); break; case AttributeList::AT_NoInline: handleSimpleAttribute<NoInlineAttr>(S, D, Attr); break; - case AttributeList::IgnoredAttribute: - // Just ignore - break; case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg. handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, Attr); break; case AttributeList::AT_StdCall: @@ -4078,15 +4258,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; - - default: - // Ask target about the attribute. - const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); - if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S)) - S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ? - diag::warn_unhandled_ms_attribute_ignored : - diag::warn_unknown_attribute_ignored) << Attr.getName(); - break; } } diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index eb0188a0db3..80d203e3f5b 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" -#include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" diff --git a/clang/lib/Sema/TargetAttributesSema.cpp b/clang/lib/Sema/TargetAttributesSema.cpp deleted file mode 100644 index b70b15c37b2..00000000000 --- a/clang/lib/Sema/TargetAttributesSema.cpp +++ /dev/null @@ -1,295 +0,0 @@ -//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains semantic analysis implementation for target-specific -// attributes. -// -//===----------------------------------------------------------------------===// - -#include "TargetAttributesSema.h" -#include "clang/AST/DeclCXX.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Sema/SemaInternal.h" -#include "llvm/ADT/Triple.h" - -using namespace clang; - -TargetAttributesSema::~TargetAttributesSema() {} -bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) const { - return false; -} - -static void HandleARMInterruptAttr(Decl *d, - const AttributeList &Attr, Sema &S) { - // Check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; - return; - } - - StringRef Str; - SourceLocation ArgLoc; - - if (Attr.getNumArgs() == 0) - Str = ""; - else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) - return; - - ARMInterruptAttr::InterruptType Kind; - if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << Str << ArgLoc; - return; - } - - unsigned Index = Attr.getAttributeSpellingListIndex(); - d->addAttr(::new (S.Context) - ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); -} - -namespace { - class ARMAttributesSema : public TargetAttributesSema { - public: - ARMAttributesSema() { } - bool ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) const { - if (Attr.getKind() == AttributeList::AT_Interrupt) { - HandleARMInterruptAttr(D, Attr, S); - return true; - } - return false; - } - }; -} - -static void HandleMSP430InterruptAttr(Decl *d, - const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; - return; - } - - if (!Attr.isArgExpr(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() - << AANT_ArgumentIntegerConstant; - return; - } - - // FIXME: Check for decl - it should be void ()(void). - Expr *NumParamsExpr = Attr.getArgAsExpr(0); - llvm::APSInt NumParams(32); - if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << NumParamsExpr->getSourceRange(); - return; - } - - unsigned Num = NumParams.getLimitedValue(255); - if ((Num & 1) || Num > 30) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << (int)NumParams.getSExtValue() - << NumParamsExpr->getSourceRange(); - return; - } - - d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num)); - d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); -} - -namespace { - class MSP430AttributesSema : public TargetAttributesSema { - public: - MSP430AttributesSema() { } - bool ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) const { - if (Attr.getKind() == AttributeList::AT_Interrupt) { - HandleMSP430InterruptAttr(D, Attr, S); - return true; - } - return false; - } - }; -} - -static void HandleX86ForceAlignArgPointerAttr(Decl *D, - const AttributeList& Attr, - Sema &S) { - // If we try to apply it to a function pointer, don't warn, but don't - // do anything, either. It doesn't matter anyway, because there's nothing - // special about calling a force_align_arg_pointer function. - ValueDecl *VD = dyn_cast<ValueDecl>(D); - if (VD && VD->getType()->isFunctionPointerType()) - return; - // Also don't warn on function pointer typedefs. - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); - if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || - TD->getUnderlyingType()->isFunctionType())) - return; - // Attribute can only be applied to function types. - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << /* function */0; - return; - } - - D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(), - S.Context)); -} - -DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex) { - if (D->hasAttr<DLLExportAttr>()) { - Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport"; - return NULL; - } - - if (D->hasAttr<DLLImportAttr>()) - return NULL; - - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (VD->hasDefinition()) { - // dllimport cannot be applied to definitions. - Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition) - << "dllimport"; - return NULL; - } - } - - return ::new (Context) DLLImportAttr(Range, Context, - AttrSpellingListIndex); -} - -static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { - // Attribute can be applied only to functions or variables. - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (!FD && !isa<VarDecl>(D)) { - // Apparently Visual C++ thinks it is okay to not emit a warning - // in this case, so only emit a warning when -fms-extensions is not - // specified. - if (!S.getLangOpts().MicrosoftExt) - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; - return; - } - - // Currently, the dllimport attribute is ignored for inlined functions. - // Warning is emitted. - if (FD && FD->isInlineSpecified()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return; - } - - unsigned Index = Attr.getAttributeSpellingListIndex(); - DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index); - if (NewAttr) - D->addAttr(NewAttr); -} - -DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex) { - if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) { - Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport"; - D->dropAttr<DLLImportAttr>(); - } - - if (D->hasAttr<DLLExportAttr>()) - return NULL; - - return ::new (Context) DLLExportAttr(Range, Context, - AttrSpellingListIndex); -} - -static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { - // Currently, the dllexport attribute is ignored for inlined functions, unless - // the -fkeep-inline-functions flag has been used. Warning is emitted; - if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isInlineSpecified()) { - // FIXME: ... unless the -fkeep-inline-functions flag has been used. - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return; - } - - unsigned Index = Attr.getAttributeSpellingListIndex(); - DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index); - if (NewAttr) - D->addAttr(NewAttr); -} - -namespace { - class X86AttributesSema : public TargetAttributesSema { - public: - X86AttributesSema() { } - bool ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) const { - const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple()); - if (Triple.getOS() == llvm::Triple::Win32 || - Triple.getOS() == llvm::Triple::MinGW32) { - switch (Attr.getKind()) { - case AttributeList::AT_DLLImport: HandleDLLImportAttr(D, Attr, S); - return true; - case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S); - return true; - default: break; - } - } - if (Triple.getArch() != llvm::Triple::x86_64 && - (Attr.getName()->getName() == "force_align_arg_pointer" || - Attr.getName()->getName() == "__force_align_arg_pointer__")) { - HandleX86ForceAlignArgPointerAttr(D, Attr, S); - return true; - } - return false; - } - }; -} - -namespace { - class MipsAttributesSema : public TargetAttributesSema { - public: - MipsAttributesSema() { } - bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, - Sema &S) const { - if (Attr.getKind() == AttributeList::AT_Mips16) { - D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - return true; - } else if (Attr.getKind() == AttributeList::AT_NoMips16) { - D->addAttr(::new (S.Context) NoMips16Attr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - return true; - } - return false; - } - }; -} - -const TargetAttributesSema &Sema::getTargetAttributesSema() const { - if (TheTargetAttributesSema) - return *TheTargetAttributesSema; - - const llvm::Triple &Triple(Context.getTargetInfo().getTriple()); - switch (Triple.getArch()) { - case llvm::Triple::arm: - case llvm::Triple::thumb: - return *(TheTargetAttributesSema = new ARMAttributesSema); - case llvm::Triple::msp430: - return *(TheTargetAttributesSema = new MSP430AttributesSema); - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return *(TheTargetAttributesSema = new X86AttributesSema); - case llvm::Triple::mips: - case llvm::Triple::mipsel: - return *(TheTargetAttributesSema = new MipsAttributesSema); - default: - return *(TheTargetAttributesSema = new TargetAttributesSema); - } -} diff --git a/clang/lib/Sema/TargetAttributesSema.h b/clang/lib/Sema/TargetAttributesSema.h deleted file mode 100644 index 410c900222f..00000000000 --- a/clang/lib/Sema/TargetAttributesSema.h +++ /dev/null @@ -1,27 +0,0 @@ -//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_SEMA_TARGETSEMA_H -#define CLANG_SEMA_TARGETSEMA_H - -namespace clang { - class Scope; - class Decl; - class AttributeList; - class Sema; - - class TargetAttributesSema { - public: - virtual ~TargetAttributesSema(); - virtual bool ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) const; - }; -} - -#endif diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 02a2e48376c..a3edd787a44 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -74,7 +74,8 @@ static StringRef NormalizeAttrSpelling(StringRef AttrSpelling) { typedef std::vector<std::pair<std::string, Record *> > ParsedAttrMap; -static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records) { +static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records, + ParsedAttrMap *Dupes = 0) { std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); std::set<std::string> Seen; ParsedAttrMap R; @@ -89,8 +90,11 @@ static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records) { // If this attribute has already been handled, it does not need to be // handled again. - if (Seen.find(AN) != Seen.end()) + if (Seen.find(AN) != Seen.end()) { + if (Dupes) + Dupes->push_back(std::make_pair(AN, *I)); continue; + } Seen.insert(AN); } else AN = NormalizeAttrName(Attr.getName()).str(); @@ -2063,15 +2067,111 @@ static std::string GenerateLangOptRequirements(const Record &R, return FnName; } +static void GenerateDefaultTargetRequirements(raw_ostream &OS) { + OS << "static bool defaultTargetRequirements(llvm::Triple) {\n"; + OS << " return true;\n"; + OS << "}\n\n"; +} + +static std::string GenerateTargetRequirements(const Record &Attr, + const ParsedAttrMap &Dupes, + raw_ostream &OS) { + // If the attribute is not a target specific attribute, return the default + // target handler. + if (!Attr.isSubClassOf("TargetSpecificAttr")) + return "defaultTargetRequirements"; + + // Get the list of architectures to be tested for. + const Record *R = Attr.getValueAsDef("Target"); + std::vector<std::string> 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 + // duplicate architectures. This is required because a shared target-specific + // attribute has only one AttributeList::Kind enumeration value, but it + // applies to multiple target architectures. In order for the attribute to be + // considered valid, all of its architectures need to be included. + if (!Attr.isValueUnset("ParseKind")) { + std::string APK = Attr.getValueAsString("ParseKind"); + for (ParsedAttrMap::const_iterator I = Dupes.begin(), E = Dupes.end(); + I != E; ++I) { + if (I->first == APK) { + std::vector<std::string> DA = I->second->getValueAsDef("Target")-> + getValueAsListOfStrings("Arches"); + std::copy(DA.begin(), DA.end(), std::back_inserter(Arches)); + } + } + } + + std::string FnName = "isTarget", Test = "("; + for (std::vector<std::string>::const_iterator I = Arches.begin(), + E = Arches.end(); I != E; ++I) { + std::string Part = *I; + Test += "Arch == llvm::Triple::" + Part; + if (I + 1 != E) + Test += " || "; + FnName += Part; + } + Test += ")"; + + // If the target also requires OS testing, generate those tests as well. + bool UsesOS = false; + if (!R->isValueUnset("OSes")) { + UsesOS = true; + + // We know that there was at least one arch test, so we need to and in the + // OS tests. + Test += " && ("; + std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes"); + for (std::vector<std::string>::const_iterator I = OSes.begin(), + E = OSes.end(); I != E; ++I) { + std::string Part = *I; + + Test += "OS == llvm::Triple::" + 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; + std::set<std::string>::iterator I = CustomTargetSet.find(FnName); + if (I != CustomTargetSet.end()) + return *I; + + OS << "static bool " << FnName << "(llvm::Triple T) {\n"; + OS << " llvm::Triple::ArchType Arch = T.getArch();\n"; + if (UsesOS) + OS << " llvm::Triple::OSType OS = T.getOS();\n"; + OS << " return " << Test << ";\n"; + OS << "}\n\n"; + + CustomTargetSet.insert(FnName); + return FnName; +} + /// Emits the parsed attribute helpers void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Parsed attribute helpers", OS); - ParsedAttrMap Attrs = getParsedAttrList(Records); + // Get the list of parsed attributes, and accept the optional list of + // duplicates due to the ParseKind. + ParsedAttrMap Dupes; + ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes); - // Generate the default appertainsTo and language option diagnostic methods. + // Generate the default appertainsTo, target and language option diagnostic + // methods. GenerateDefaultAppertainsTo(OS); GenerateDefaultLangOptRequirements(OS); + GenerateDefaultTargetRequirements(OS); // Generate the appertainsTo diagnostic methods and write their names into // another mapping. At the same time, generate the AttrInfoMap object @@ -2080,13 +2180,22 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { std::stringstream SS; for (ParsedAttrMap::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { + // TODO: If the attribute's kind appears in the list of duplicates, that is + // because it is a target-specific attribute that appears multiple times. + // It would be beneficial to test whether the duplicates are "similar + // enough" to each other to not cause problems. For instance, check that + // the spellings are identicial, and custom parsing rules match, etc. + // We need to generate struct instances based off ParsedAttrInfo from // AttributeList.cpp. SS << " { "; emitArgInfo(*I->second, SS); SS << ", " << I->second->getValueAsBit("HasCustomParsing"); + SS << ", " << I->second->isSubClassOf("TargetSpecificAttr"); + SS << ", " << I->second->isSubClassOf("TypeAttr"); SS << ", " << GenerateAppertainsTo(*I->second, OS); SS << ", " << GenerateLangOptRequirements(*I->second, OS); + SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS); SS << " }"; if (I + 1 != E) |