From: Aaron Ballman Date: Mon, 2 Dec 2013 19:30:36 +0000 (+0000) Subject: Automate attribute language option checking by specifying the list of options to... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=694680f7c42c75b64a676f447473df6f91a29cb7;p=clang Automate attribute language option checking by specifying the list of options to test in tablegen. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196138 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index c7223d6512..df8c4edc2c 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -129,6 +129,13 @@ class SubjectList subjects, SubjectDiag diag = WarnDiag, string CustomDiag = customDiag; } +class LangOpt { + string Name = name; +} +def MicrosoftExt : LangOpt<"MicrosoftExt">; +def Borland : LangOpt<"Borland">; +def CUDA : LangOpt<"CUDA">; + class Attr { // The various ways in which an attribute can be spelled in source list Spellings; @@ -155,6 +162,9 @@ class Attr { // content. Eg) It parses 3 args, but semantically takes 4 args. Opts out of // common attribute error checking. bit HasCustomParsing = 0; + // Lists language options, one of which is required to be true for the + // attribute to be applicable. If empty, no language options are required. + list LangOpts = []; // Any additional text that should be included verbatim in the class. code AdditionalMembers = [{}]; } @@ -352,31 +362,37 @@ def Constructor : InheritableAttr { def CUDAConstant : InheritableAttr { let Spellings = [GNU<"constant">]; let Subjects = SubjectList<[Var]>; + let LangOpts = [CUDA]; } def CUDADevice : InheritableAttr { let Spellings = [GNU<"device">]; let Subjects = SubjectList<[Function, Var]>; + let LangOpts = [CUDA]; } def CUDAGlobal : InheritableAttr { let Spellings = [GNU<"global">]; let Subjects = SubjectList<[Function]>; + let LangOpts = [CUDA]; } def CUDAHost : InheritableAttr { let Spellings = [GNU<"host">]; let Subjects = SubjectList<[Function]>; + let LangOpts = [CUDA]; } def CUDALaunchBounds : InheritableAttr { let Spellings = [GNU<"launch_bounds">]; let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>]; + let LangOpts = [CUDA]; } def CUDAShared : InheritableAttr { let Spellings = [GNU<"shared">]; let Subjects = SubjectList<[Var]>; + let LangOpts = [CUDA]; } def C11NoReturn : InheritableAttr { @@ -823,6 +839,7 @@ def Uuid : InheritableAttr { let Spellings = [GNU<"uuid">]; let Args = [StringArgument<"Guid">]; // let Subjects = SubjectList<[CXXRecord]>; + let LangOpts = [MicrosoftExt, Borland]; } def VectorSize : TypeAttr { @@ -1159,14 +1176,17 @@ def DLLImport : InheritableAttr, TargetSpecificAttr { def ForceInline : InheritableAttr { let Spellings = [Keyword<"__forceinline">]; + let LangOpts = [MicrosoftExt]; } def SelectAny : InheritableAttr { let Spellings = [Declspec<"selectany">]; + let LangOpts = [MicrosoftExt]; } def Win64 : InheritableAttr { let Spellings = [Keyword<"__w64">]; + let LangOpts = [MicrosoftExt]; } def Ptr32 : TypeAttr { @@ -1185,7 +1205,9 @@ def UPtr : TypeAttr { let Spellings = [Keyword<"__uptr">]; } -class MSInheritanceAttr : InheritableAttr; +class MSInheritanceAttr : InheritableAttr { + let LangOpts = [MicrosoftExt]; +} def SingleInheritance : MSInheritanceAttr { let Spellings = [Keyword<"__single_inheritance">]; diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index e27209525e..96a9efee91 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -468,6 +468,7 @@ public: unsigned getMinArgs() const; unsigned getMaxArgs() const; bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const; + bool diagnoseLangOpts(class Sema &S) const; }; /// A factory, from which one makes pools, from which one creates diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index c99d126700..aa7f9df6bc 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -155,6 +155,7 @@ struct ParsedAttrInfo { bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr, const Decl *); + bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr); }; namespace { @@ -180,3 +181,7 @@ bool AttributeList::hasCustomParsing() const { bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const { return getInfo(*this).DiagAppertainsToDecl(S, *this, D); } + +bool AttributeList::diagnoseLangOpts(Sema &S) const { + return getInfo(*this).DiagLangOpts(S, *this); +} diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index f3e2ff8564..687f8a014e 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3143,76 +3143,38 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - D->addAttr(::new (S.Context) - CUDAConstantAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - } -} - static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 0; - return; - } - - D->addAttr(::new (S.Context) - CUDADeviceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr.getName() << 0; + return; } + + D->addAttr(::new (S.Context) + CUDADeviceAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - FunctionDecl *FD = cast(D); - if (!FD->getResultType()->isVoidType()) { - TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens(); - if (FunctionTypeLoc FTL = TL.getAs()) { - S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) - << FD->getType() - << FixItHint::CreateReplacement(FTL.getResultLoc().getSourceRange(), - "void"); - } else { - S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) - << FD->getType(); - } - return; + FunctionDecl *FD = cast(D); + if (!FD->getResultType()->isVoidType()) { + TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens(); + if (FunctionTypeLoc FTL = TL.getAs()) { + S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) + << FD->getType() + << FixItHint::CreateReplacement(FTL.getResultLoc().getSourceRange(), + "void"); + } else { + S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) + << FD->getType(); } - - D->addAttr(::new (S.Context) - CUDAGlobalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + return; } -} -static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - D->addAttr(::new (S.Context) - CUDAHostAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) + CUDAGlobalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - } -} - -static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.CUDA) { - D->addAttr(::new (S.Context) - CUDASharedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - } } static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3443,32 +3405,28 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { } static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ - if (S.LangOpts.CUDA) { - // check the attribute arguments. - if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { - // FIXME: 0 is not okay. - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2; - return; - } + // check the attribute arguments. + if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { + // FIXME: 0 is not okay. + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2; + return; + } - if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; - return; - } + if (!isFunctionOrMethod(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } - uint32_t MaxThreads, MinBlocks; - if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1) || - !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(1), MinBlocks, 2)) - return; + uint32_t MaxThreads, MinBlocks; + if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1) || + !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(1), MinBlocks, 2)) + return; - D->addAttr(::new (S.Context) - CUDALaunchBoundsAttr(Attr.getRange(), S.Context, - MaxThreads, MinBlocks, - Attr.getAttributeSpellingListIndex())); - } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "launch_bounds"; - } + D->addAttr(::new (S.Context) + CUDALaunchBoundsAttr(Attr.getRange(), S.Context, + MaxThreads, MinBlocks, + Attr.getAttributeSpellingListIndex())); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, @@ -3847,16 +3805,6 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// -// Check if MS extensions or some other language extensions are enabled. If -// not, issue a diagnostic that the given attribute is unused. -static bool checkMicrosoftExt(Sema &S, const AttributeList &Attr, - bool OtherExtension = false) { - if (S.LangOpts.MicrosoftExt || OtherExtension) - return true; - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return false; -} - static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!S.LangOpts.CPlusPlus) { S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) @@ -3864,9 +3812,6 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - if (!checkMicrosoftExt(S, Attr, S.LangOpts.Borland)) - return; - if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedClass; @@ -3905,54 +3850,6 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } -static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) - return; - - AttributeList::Kind Kind = Attr.getKind(); - if (Kind == AttributeList::AT_SingleInheritance) - D->addAttr( - ::new (S.Context) - SingleInheritanceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (Kind == AttributeList::AT_MultipleInheritance) - D->addAttr( - ::new (S.Context) - MultipleInheritanceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (Kind == AttributeList::AT_VirtualInheritance) - D->addAttr( - ::new (S.Context) - VirtualInheritanceAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleWin64Attr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) - return; - - D->addAttr(::new (S.Context) Win64Attr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) - return; - D->addAttr(::new (S.Context) - ForceInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleSelectAnyAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkMicrosoftExt(S, Attr)) - return; - // Check linkage after possibly merging declaratinos. See - // checkAttributesAfterMerging(). - D->addAttr(::new (S.Context) - SelectAnyAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - /// 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. @@ -3968,6 +3865,11 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, Attr.getKind() == AttributeList::IgnoredAttribute) return false; + // Check whether the attribute requires specific language extensions to be + // enabled. + if (!Attr.diagnoseLangOpts(S)) + return true; + // If there are no optional arguments, then checking for the argument count // is trivial. if (Attr.getMinArgs() == Attr.getMaxArgs() && @@ -4034,7 +3936,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleDependencyAttr(S, scope, D, Attr); break; case AttributeList::AT_Common: handleCommonAttr (S, D, Attr); break; - case AttributeList::AT_CUDAConstant:handleConstantAttr (S, D, Attr); break; + case AttributeList::AT_CUDAConstant: + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break; case AttributeList::AT_CXX11NoReturn: handleSimpleAttribute(S, D, Attr); break; @@ -4052,7 +3955,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break; case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break; case AttributeList::AT_CUDADevice: handleDeviceAttr (S, D, Attr); break; - case AttributeList::AT_CUDAHost: handleHostAttr (S, D, Attr); break; + case AttributeList::AT_CUDAHost: + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_GNUInline: handleGNUInlineAttr (S, D, Attr); break; case AttributeList::AT_CUDALaunchBounds: handleLaunchBoundsAttr(S, D, Attr); @@ -4073,7 +3977,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_NoReturn: handleNoReturnAttr (S, D, Attr); break; case AttributeList::AT_NoThrow: handleNothrowAttr (S, D, Attr); break; - case AttributeList::AT_CUDAShared: handleSharedAttr (S, D, Attr); break; + case AttributeList::AT_CUDAShared: + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_VecReturn: handleVecReturnAttr (S, D, Attr); break; case AttributeList::AT_ObjCOwnership: @@ -4206,18 +4111,17 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleUuidAttr(S, D, Attr); break; case AttributeList::AT_SingleInheritance: + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_MultipleInheritance: + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_VirtualInheritance: - handleInheritanceAttr(S, D, Attr); - break; + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_Win64: - handleWin64Attr(S, D, Attr); break; + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_ForceInline: - handleForceInlineAttr(S, D, Attr); - break; + handleSimpleAttribute(S, D, Attr); break; case AttributeList::AT_SelectAny: - handleSelectAnyAttr(S, D, Attr); - break; + handleSimpleAttribute(S, D, Attr); break; // Thread safety attributes: case AttributeList::AT_AssertExclusiveLock: diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index d459059745..526b5fe9e1 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -1900,14 +1900,64 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { return FnName; } +static void GenerateDefaultLangOptRequirements(raw_ostream &OS) { + OS << "static bool defaultDiagnoseLangOpts(Sema &, "; + OS << "const AttributeList &) {\n"; + OS << " return true;\n"; + OS << "}\n\n"; +} + +static std::string GenerateLangOptRequirements(const Record &R, + raw_ostream &OS) { + // If the attribute has an empty or unset list of language requirements, + // return the default handler. + std::vector LangOpts = R.getValueAsListOfDefs("LangOpts"); + if (LangOpts.empty()) + return "defaultDiagnoseLangOpts"; + + // Generate the test condition, as well as a unique function name for the + // diagnostic test. The list of options should usually be short (one or two + // options), and the uniqueness isn't strictly necessary (it is just for + // codegen efficiency). + std::string FnName = "check", Test; + for (std::vector::const_iterator I = LangOpts.begin(), + E = LangOpts.end(); I != E; ++I) { + std::string Part = (*I)->getValueAsString("Name"); + Test += "S.LangOpts." + Part; + if (I + 1 != E) + Test += " || "; + FnName += Part; + } + FnName += "LangOpts"; + + // If this code has already been generated, simply return the previous + // instance of it. + static std::set CustomLangOptsSet; + std::set::iterator I = CustomLangOptsSet.find(FnName); + if (I != CustomLangOptsSet.end()) + return *I; + + OS << "static bool " << FnName << "(Sema &S, const AttributeList &Attr) {\n"; + OS << " if (" << Test << ")\n"; + OS << " return true;\n\n"; + OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; + OS << "<< Attr.getName();\n"; + OS << " return false;\n"; + OS << "}\n\n"; + + CustomLangOptsSet.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); - // Generate the default appertainsTo diagnostic method. + // Generate the default appertainsTo and language option diagnostic methods. GenerateDefaultAppertainsTo(OS); + GenerateDefaultLangOptRequirements(OS); // Generate the appertainsTo diagnostic methods and write their names into // another mapping. At the same time, generate the AttrInfoMap object @@ -1922,6 +1972,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { emitArgInfo(*I->second, SS); SS << ", " << I->second->getValueAsBit("HasCustomParsing"); SS << ", " << GenerateAppertainsTo(*I->second, OS); + SS << ", " << GenerateLangOptRequirements(*I->second, OS); SS << " }"; if (I + 1 != E)