r196138 - Automate attribute language option checking by specifying the list of options to test in tablegen.

Aaron Ballman aaron at aaronballman.com
Mon Dec 2 11:30:36 PST 2013


Author: aaronballman
Date: Mon Dec  2 13:30:36 2013
New Revision: 196138

URL: http://llvm.org/viewvc/llvm-project?rev=196138&view=rev
Log:
Automate attribute language option checking by specifying the list of options to test in tablegen.

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=196138&r1=196137&r2=196138&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Mon Dec  2 13:30:36 2013
@@ -129,6 +129,13 @@ class SubjectList<list<AttrSubject> subj
   string CustomDiag = customDiag;
 }
 
+class LangOpt<string name> {
+  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<Spelling> 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<LangOpt> 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, TargetS
 
 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">];

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=196138&r1=196137&r2=196138&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Mon Dec  2 13:30:36 2013
@@ -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

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=196138&r1=196137&r2=196138&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Mon Dec  2 13:30:36 2013
@@ -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() c
 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);
+}

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=196138&r1=196137&r2=196138&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Dec  2 13:30:36 2013
@@ -3143,76 +3143,38 @@ static void handleNoDebugAttr(Sema &S, D
                          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<FunctionDecl>(D);
-    if (!FD->getResultType()->isVoidType()) {
-      TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
-      if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
-        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<FunctionDecl>(D);
+  if (!FD->getResultType()->isVoidType()) {
+    TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
+    if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
+      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 Attrib
 }
 
 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 handleObjCPreciseLifetimeAtt
 // 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
     return;
   }
 
-  if (!checkMicrosoftExt(S, Attr, S.LangOpts.Borland))
-    return;
-
   if (!isa<CXXRecordDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedClass;
@@ -3905,54 +3850,6 @@ static void handleUuidAttr(Sema &S, Decl
                                         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 handleCommonAttributeFeature
       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
     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<CUDAConstantAttr>(S, D, Attr); break;
   case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break;
   case AttributeList::AT_CXX11NoReturn:
   handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr); break;
@@ -4052,7 +3955,8 @@ static void ProcessDeclAttribute(Sema &S
   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<CUDAHostAttr>(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
     handleSimpleAttribute<NakedAttr>(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<CUDASharedAttr>(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
     handleUuidAttr(S, D, Attr);
     break;
   case AttributeList::AT_SingleInheritance:
+    handleSimpleAttribute<SingleInheritanceAttr>(S, D, Attr); break;
   case AttributeList::AT_MultipleInheritance:
+    handleSimpleAttribute<MultipleInheritanceAttr>(S, D, Attr); break;
   case AttributeList::AT_VirtualInheritance:
-    handleInheritanceAttr(S, D, Attr);
-    break;
+    handleSimpleAttribute<VirtualInheritanceAttr>(S, D, Attr); break;
   case AttributeList::AT_Win64:
-    handleWin64Attr(S, D, Attr); break;
+    handleSimpleAttribute<Win64Attr>(S, D, Attr); break;
   case AttributeList::AT_ForceInline:
-    handleForceInlineAttr(S, D, Attr);
-    break;
+    handleSimpleAttribute<ForceInlineAttr>(S, D, Attr); break;
   case AttributeList::AT_SelectAny:
-    handleSelectAnyAttr(S, D, Attr);
-    break;
+    handleSimpleAttribute<SelectAnyAttr>(S, D, Attr); break;
 
   // Thread safety attributes:
   case AttributeList::AT_AssertExclusiveLock:

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=196138&r1=196137&r2=196138&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Mon Dec  2 13:30:36 2013
@@ -1900,14 +1900,64 @@ static std::string GenerateAppertainsTo(
   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<Record *> 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<Record *>::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<std::string> CustomLangOptsSet;
+  std::set<std::string>::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(RecordK
     emitArgInfo(*I->second, SS);
     SS << ", " << I->second->getValueAsBit("HasCustomParsing");
     SS << ", " << GenerateAppertainsTo(*I->second, OS);
+    SS << ", " << GenerateLangOptRequirements(*I->second, OS);
     SS << " }";
 
     if (I + 1 != E)





More information about the cfe-commits mailing list