]> granicus.if.org Git - clang/commitdiff
Instantiate dependent attributes when instantiating templates.
authorDeLesley Hutchins <delesley@google.com>
Fri, 20 Jan 2012 22:37:06 +0000 (22:37 +0000)
committerDeLesley Hutchins <delesley@google.com>
Fri, 20 Jan 2012 22:37:06 +0000 (22:37 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148592 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Basic/Attr.td
include/clang/CMakeLists.txt
include/clang/Makefile
include/clang/Sema/CMakeLists.txt [new file with mode: 0644]
include/clang/Sema/Makefile [new file with mode: 0644]
lib/Sema/CMakeLists.txt
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/warn-thread-safety-analysis.cpp
utils/TableGen/ClangAttrEmitter.cpp
utils/TableGen/ClangAttrEmitter.h
utils/TableGen/TableGen.cpp

index f414fc62373294dbb65e0f72b9963075d81a7a4f..292c9a396f58f88fd9e4bb2cec4592887499f6ac 100644 (file)
@@ -93,6 +93,8 @@ class Attr {
   list<string> Namespaces = [];
   // Set to true for attributes with arguments which require delayed parsing. 
   bit LateParsed = 0;  
+  // Set to true for attributes which must be instantiated within templates
+  bit TemplateDependent = 0;
   // Any additional text that should be included verbatim in the class.  
   code AdditionalMembers = [{}];
 }
@@ -601,36 +603,42 @@ def GuardedBy : InheritableAttr {
   let Spellings = ["guarded_by"];
   let Args = [ExprArgument<"Arg">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def PtGuardedBy : InheritableAttr {
   let Spellings = ["pt_guarded_by"];
   let Args = [ExprArgument<"Arg">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def AcquiredAfter : InheritableAttr {
   let Spellings = ["acquired_after"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def AcquiredBefore : InheritableAttr {
   let Spellings = ["acquired_before"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def ExclusiveLockFunction : InheritableAttr {
   let Spellings = ["exclusive_lock_function"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def SharedLockFunction : InheritableAttr {
   let Spellings = ["shared_lock_function"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 // The first argument is an integer or boolean value specifying the return value
@@ -639,6 +647,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
   let Spellings = ["exclusive_trylock_function"];
   let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 // The first argument is an integer or boolean value specifying the return value
@@ -647,34 +656,40 @@ def SharedTrylockFunction : InheritableAttr {
   let Spellings = ["shared_trylock_function"];
   let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def UnlockFunction : InheritableAttr {
   let Spellings = ["unlock_function"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def LockReturned : InheritableAttr {
   let Spellings = ["lock_returned"];
   let Args = [ExprArgument<"Arg">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def LocksExcluded : InheritableAttr {
   let Spellings = ["locks_excluded"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def ExclusiveLocksRequired : InheritableAttr {
   let Spellings = ["exclusive_locks_required"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
 
 def SharedLocksRequired : InheritableAttr {
   let Spellings = ["shared_locks_required"];
   let Args = [VariadicExprArgument<"Args">];
   let LateParsed = 1;
+  let TemplateDependent = 1;
 }
index fb4e04d55b1569b067546d1892d701ed487f2915..71c37fda7891ca5cfafc9f8b22b572f4b25aeb14 100644 (file)
@@ -3,4 +3,5 @@ add_subdirectory(Basic)
 add_subdirectory(Driver)
 add_subdirectory(Lex)
 add_subdirectory(Parse)
+add_subdirectory(Sema)
 add_subdirectory(Serialization)
index f7ce58bd56a168761e2b2ce401474198bd2968cd..4398f3aed5759e831de5eba05004428841b9a072 100644 (file)
@@ -1,5 +1,5 @@
 CLANG_LEVEL := ../..
-DIRS := AST Basic Driver Lex Parse Serialization
+DIRS := AST Basic Driver Lex Parse Sema Serialization
 
 include $(CLANG_LEVEL)/Makefile
 
diff --git a/include/clang/Sema/CMakeLists.txt b/include/clang/Sema/CMakeLists.txt
new file mode 100644 (file)
index 0000000..110c5f9
--- /dev/null
@@ -0,0 +1,4 @@
+clang_tablegen(AttrTemplateInstantiate.inc -gen-clang-attr-template-instantiate
+  -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+  SOURCE ../Basic/Attr.td
+  TARGET ClangAttrTemplateInstantiate)
diff --git a/include/clang/Sema/Makefile b/include/clang/Sema/Makefile
new file mode 100644 (file)
index 0000000..3ec9c8b
--- /dev/null
@@ -0,0 +1,14 @@
+CLANG_LEVEL := ../../..
+TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
+BUILT_SOURCES = AttrTemplateInstantiate.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(CLANG_LEVEL)/Makefile
+
+$(ObjDir)/AttrTemplateInstantiate.inc.tmp : $(TD_SRC_DIR)/Attr.td \
+                                            $(CLANG_TBLGEN) $(ObjDir)/.dir
+       $(Echo) "Building Clang attribute template instantiate code with tablegen"
+       $(Verb) $(ClangTableGen) -gen-clang-attr-template-instantiate -o \
+         $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
+
index 81cbd9594d052c8c867ea95e8163d3aea14bbf11..ae878b06494cc419f97d543aa5d666a3505ffdc2 100644 (file)
@@ -44,4 +44,5 @@ add_clang_library(clangSema
   )
 
 add_dependencies(clangSema ClangARMNeon ClangAttrClasses ClangAttrList 
-                 ClangDiagnosticSema ClangDeclNodes ClangStmtNodes)
+                 ClangDiagnosticSema ClangDeclNodes ClangStmtNodes 
+                 ClangAttrTemplateInstantiate)
index 9dc00c36259196f9f6ea6285f14cc8192103afec..7fd10735b7a4d3099a61e19d160860da104598cb 100644 (file)
@@ -7311,6 +7311,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
 /// relevant Decl.
 void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
                                        ParsedAttributes &Attrs) {
+  // Always attach attributes to the underlying decl.
+  if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
+    D = TD->getTemplatedDecl();
   ProcessDeclAttributeList(S, D, Attrs.getList());
 }
 
index ea736320f8767be7c7d8d39073046cad2d074d30..e06d637eeb7ec10cc1480d3b052b883a94343ebc 100644 (file)
@@ -393,13 +393,11 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
   if (pointer && !checkIsPointer(S, D, Attr))
     return;
 
-  if (Arg->isTypeDependent())
-    // FIXME: handle attributes with dependent types
-    return;
-
-  // check that the argument is lockable object
-  if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType())))
-    return;
+  if (!Arg->isTypeDependent()) {
+    if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType())))
+      return;
+    // FIXME -- semantic checks for dependent attributes
+  }
 
   if (pointer)
     D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
index 0d4ad3005b5c86977dc0fde16118633760e8c47e..60bcbfb255f8f430b9d515c13044045c888724da 100644 (file)
@@ -57,7 +57,9 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
   return false;
 }
 
-// FIXME: Is this still too simple?
+// Include attribute instantiation code.
+#include "clang/Sema/AttrTemplateInstantiate.inc"
+
 void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
                             const Decl *Tmpl, Decl *New) {
   for (AttrVec::const_iterator i = Tmpl->attr_begin(), e = Tmpl->attr_end();
@@ -87,8 +89,8 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
       }
     }
 
-    // FIXME: Is cloning correct for all attributes?
-    Attr *NewAttr = TmplAttr->clone(Context);
+    Attr *NewAttr =
+      instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs);
     New->addAttr(NewAttr);
   }
 }
index 497cd5c599322a6c07c87db3171a1e4340949f3f..a3d6a8b0bb870c30b7fd862bdbba23a848711a40 100644 (file)
@@ -1051,12 +1051,14 @@ class Foo {
  public:
   void func(T x) {
     mu_.Lock();
-    count_ = x;
+    // count_ = x;
     mu_.Unlock();
   }
 
  private:
-  T count_ GUARDED_BY(mu_);
+  // FIXME: This test passed earlier only because thread safety was turned
+  // off for templates.
+  // T count_ GUARDED_BY(mu_);
   Bar<T> bar_;
   Mutex mu_;
 };
@@ -1605,7 +1607,6 @@ struct TestScopedLockable {
 } // end namespace test_scoped_lockable
 
 
-
 namespace FunctionAttrTest {
 
 class Foo {
@@ -1727,4 +1728,127 @@ struct TestTryLock {
 };  // end TestTrylock
 
 
+namespace TestTemplateAttributeInstantiation {
+
+class Foo1 {
+public:
+  Mutex mu_;
+  int a GUARDED_BY(mu_);
+};
+
+class Foo2 {
+public:
+  int a GUARDED_BY(mu_);
+  Mutex mu_;
+};
+
+
+class Bar {
+public:
+  // Test non-dependent expressions in attributes on template functions
+  template <class T>
+  void barND(Foo1 *foo, T *fooT) EXCLUSIVE_LOCKS_REQUIRED(foo->mu_) {
+    foo->a = 0;
+  }
+
+  // Test dependent expressions in attributes on template functions
+  template <class T>
+  void barD(Foo1 *foo, T *fooT) EXCLUSIVE_LOCKS_REQUIRED(fooT->mu_) {
+    fooT->a = 0;
+  }
+};
+
+
+template <class T>
+class BarT {
+public:
+  Foo1 fooBase;
+  T    fooBaseT;
+
+  // Test non-dependent expression in ordinary method on template class
+  void barND() EXCLUSIVE_LOCKS_REQUIRED(fooBase.mu_) {
+    fooBase.a = 0;
+  }
+
+  // Test dependent expressions in ordinary methods on template class
+  void barD() EXCLUSIVE_LOCKS_REQUIRED(fooBaseT.mu_) {
+    fooBaseT.a = 0;
+  }
+
+  // Test dependent expressions in template method in template class
+  template <class T2>
+  void barTD(T2 *fooT) EXCLUSIVE_LOCKS_REQUIRED(fooBaseT.mu_, fooT->mu_) {
+    fooBaseT.a = 0;
+    fooT->a = 0;
+  }
+};
+
+template <class T>
+class Cell {
+public:
+  Mutex mu_;
+  // Test dependent guarded_by
+  T data GUARDED_BY(mu_);
+
+  void foo() {
+    mu_.Lock();
+    data = 0;
+    mu_.Unlock();
+  }
+};
+
+
+template <class T>
+class CellDelayed {
+public:
+  // Test dependent guarded_by
+  T data GUARDED_BY(mu_);
+
+  void foo() {
+    mu_.Lock();
+    data = 0;
+    mu_.Unlock();
+  }
+
+  Mutex mu_;
+};
+
+void test() {
+  Bar b;
+  BarT<Foo2> bt;
+  Foo1 f1;
+  Foo2 f2;
+
+  f1.mu_.Lock();
+  f2.mu_.Lock();
+  bt.fooBase.mu_.Lock();
+  bt.fooBaseT.mu_.Lock();
+
+  b.barND(&f1, &f2);
+  b.barD(&f1, &f2);
+  bt.barND();
+  bt.barD();
+  bt.barTD(&f2);
+
+  f1.mu_.Unlock();
+  bt.barTD(&f1);  // \
+    // expected-warning {{calling function 'barTD' requires exclusive lock on 'mu_'}}
+
+  bt.fooBase.mu_.Unlock();
+  bt.fooBaseT.mu_.Unlock();
+  f2.mu_.Unlock();
+
+  Cell<int> cell;
+  cell.data = 0; // \
+    // expected-warning {{writing variable 'data' requires locking 'mu_' exclusively}}
+  cell.foo();
+
+  // FIXME: This doesn't work yet
+  // CellDelayed<int> celld;
+  // celld.foo();
+}
+
+};  // end namespace TestTemplateAttributeInstantiation
+
+
 
index 16015429bf360b0fa5240a12072f379786c23193..dd3de66fbd8546a15c4d8aedf10cc5c74b5e6e87 100644 (file)
@@ -89,6 +89,8 @@ namespace {
     virtual void writeAccessors(raw_ostream &OS) const = 0;
     virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
     virtual void writeCloneArgs(raw_ostream &OS) const = 0;
+    virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0;
+    virtual void writeTemplateInstantiation(raw_ostream &OS) const {};
     virtual void writeCtorBody(raw_ostream &OS) const {}
     virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
     virtual void writeCtorParameters(raw_ostream &OS) const = 0;
@@ -107,6 +109,8 @@ namespace {
       : Argument(Arg, Attr), type(T)
     {}
 
+    std::string getType() const { return type; }
+
     void writeAccessors(raw_ostream &OS) const {
       OS << "  " << type << " get" << getUpperName() << "() const {\n";
       OS << "    return " << getLowerName() << ";\n";
@@ -115,6 +119,9 @@ namespace {
     void writeCloneArgs(raw_ostream &OS) const {
       OS << getLowerName();
     }
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      OS << "A->get" << getUpperName() << "()";
+    }
     void writeCtorInitializers(raw_ostream &OS) const {
       OS << getLowerName() << "(" << getUpperName() << ")";
     }
@@ -176,6 +183,9 @@ namespace {
     void writeCloneArgs(raw_ostream &OS) const {
       OS << "get" << getUpperName() << "()";
     }
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      OS << "A->get" << getUpperName() << "()";
+    }
     void writeCtorBody(raw_ostream &OS) const {
       OS << "      std::memcpy(" << getLowerName() << ", " << getUpperName()
          << ".data(), " << getLowerName() << "Length);";
@@ -266,6 +276,10 @@ namespace {
          << "Expr) : " << getLowerName()
          << "Type";
     }
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      // FIXME: move the definition in Sema::InstantiateAttrs to here.
+      // In the meantime, aligned attributes are cloned.
+    }
     void writeCtorBody(raw_ostream &OS) const {
       OS << "    if (is" << getLowerName() << "Expr)\n";
       OS << "       " << getLowerName() << "Expr = reinterpret_cast<Expr *>("
@@ -341,6 +355,11 @@ namespace {
     void writeCloneArgs(raw_ostream &OS) const {
       OS << getLowerName() << ", " << getLowerName() << "Size";
     }
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      // This isn't elegant, but we have to go through public methods...
+      OS << "A->" << getLowerName() << "_begin(), "
+         << "A->" << getLowerName() << "_size()";
+    }
     void writeCtorBody(raw_ostream &OS) const {
       // FIXME: memcpy is not safe on non-trivial types.
       OS << "    std::memcpy(" << getLowerName() << ", " << getUpperName()
@@ -412,6 +431,9 @@ namespace {
     void writeCloneArgs(raw_ostream &OS) const {
       OS << getLowerName();
     }
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      OS << "A->get" << getUpperName() << "()";
+    }
     void writeCtorInitializers(raw_ostream &OS) const {
       OS << getLowerName() << "(" << getUpperName() << ")";
     }
@@ -475,6 +497,9 @@ namespace {
     void writeCloneArgs(raw_ostream &OS) const {
       OS << "get" << getUpperName() << "()";
     }
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      OS << "A->get" << getUpperName() << "()";
+    }
     void writeCtorBody(raw_ostream &OS) const {
     }
     void writeCtorInitializers(raw_ostream &OS) const {
@@ -500,6 +525,61 @@ namespace {
       OS << getLowerName() << "=\" << get" << getUpperName() << "() << \"";
     }
   };
+
+  class ExprArgument : public SimpleArgument {
+  public:
+    ExprArgument(Record &Arg, StringRef Attr)
+      : SimpleArgument(Arg, Attr, "Expr *")
+    {}
+
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      OS << "tempInst" << getUpperName();
+    }
+
+    void writeTemplateInstantiation(raw_ostream &OS) const {
+      OS << "      " << getType() << " tempInst" << getUpperName() << ";\n";
+      OS << "      {\n";
+      OS << "        EnterExpressionEvaluationContext "
+         << "Unevaluated(S, Sema::Unevaluated);\n";
+      OS << "        ExprResult " << "Result = S.SubstExpr("
+         << "A->get" << getUpperName() << "(), TemplateArgs);\n";
+      OS << "        tempInst" << getUpperName() << " = "
+         << "Result.takeAs<Expr>();\n";
+      OS << "      }\n";
+    }
+  };
+
+  class VariadicExprArgument : public VariadicArgument {
+  public:
+    VariadicExprArgument(Record &Arg, StringRef Attr)
+      : VariadicArgument(Arg, Attr, "Expr *")
+    {}
+
+    void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+      OS << "tempInst" << getUpperName() << ", "
+         << "A->" << getLowerName() << "_size()";
+    }
+
+    void writeTemplateInstantiation(raw_ostream &OS) const {
+      OS << "      " << getType() << " *tempInst" << getUpperName()
+         << " = new (C, 16) " << getType()
+         << "[A->" << getLowerName() << "_size()];\n";
+      OS << "      {\n";
+      OS << "        EnterExpressionEvaluationContext "
+         << "Unevaluated(S, Sema::Unevaluated);\n";
+      OS << "        " << getType() << " *TI = tempInst" << getUpperName()
+         << ";\n";
+      OS << "        " << getType() << " *I = A->" << getLowerName()
+         << "_begin();\n";
+      OS << "        " << getType() << " *E = A->" << getLowerName()
+         << "_end();\n";
+      OS << "        for (; I != E; ++I, ++TI) {\n";
+      OS << "          ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n";
+      OS << "          *TI = Result.takeAs<Expr>();\n";
+      OS << "        }\n";
+      OS << "      }\n";
+    }
+  };
 }
 
 static Argument *createArgument(Record &Arg, StringRef Attr,
@@ -512,8 +592,7 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
 
   if (ArgName == "AlignedArgument") Ptr = new AlignedArgument(Arg, Attr);
   else if (ArgName == "EnumArgument") Ptr = new EnumArgument(Arg, Attr);
-  else if (ArgName == "ExprArgument") Ptr = new SimpleArgument(Arg, Attr,
-                                                               "Expr *");
+  else if (ArgName == "ExprArgument") Ptr = new ExprArgument(Arg, Attr);
   else if (ArgName == "FunctionArgument")
     Ptr = new SimpleArgument(Arg, Attr, "FunctionDecl *");
   else if (ArgName == "IdentifierArgument")
@@ -531,7 +610,7 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
   else if (ArgName == "VariadicUnsignedArgument")
     Ptr = new VariadicArgument(Arg, Attr, "unsigned");
   else if (ArgName == "VariadicExprArgument")
-    Ptr = new VariadicArgument(Arg, Attr, "Expr *");
+    Ptr = new VariadicExprArgument(Arg, Attr);
   else if (ArgName == "VersionArgument")
     Ptr = new VersionArgument(Arg, Attr);
 
@@ -851,3 +930,63 @@ void ClangAttrLateParsedListEmitter::run(raw_ostream &OS) {
     }
   }
 }
+
+
+void ClangAttrTemplateInstantiateEmitter::run(raw_ostream &OS) {
+  OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+  std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+  OS << "Attr* instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
+     << "Sema &S,\n"
+     << "        const MultiLevelTemplateArgumentList &TemplateArgs) {\n"
+     << "  switch (At->getKind()) {\n"
+     << "    default:\n"
+     << "      break;\n";
+
+  for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+       I != E; ++I) {
+    Record &R = **I;
+
+    OS << "    case attr::" << R.getName() << ": {\n";
+    OS << "      const " << R.getName() << "Attr *A = cast<"
+       << R.getName() << "Attr>(At);\n";
+    bool TDependent = R.getValueAsBit("TemplateDependent");
+
+    if (!TDependent) {
+      OS << "      return A->clone(C);\n";
+      OS << "    }\n";
+      continue;
+    }
+
+    std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
+    std::vector<Argument*> Args;
+    std::vector<Argument*>::iterator ai, ae;
+    Args.reserve(ArgRecords.size());
+
+    for (std::vector<Record*>::iterator ri = ArgRecords.begin(),
+                                        re = ArgRecords.end();
+         ri != re; ++ri) {
+      Record &ArgRecord = **ri;
+      Argument *Arg = createArgument(ArgRecord, R.getName());
+      assert(Arg);
+      Args.push_back(Arg);
+    }
+    ae = Args.end();
+
+    for (ai = Args.begin(); ai != ae; ++ai) {
+      (*ai)->writeTemplateInstantiation(OS);
+    }
+    OS << "      return new (C) " << R.getName() << "Attr(A->getLocation(), C";
+    for (ai = Args.begin(); ai != ae; ++ai) {
+      OS << ", ";
+      (*ai)->writeTemplateInstantiationArgs(OS);
+    }
+    OS << ");\n    }\n";
+  }
+  OS << "  } // end switch\n"
+     << "  llvm_unreachable(\"Unknown attribute!\");\n"
+     << "  return 0;\n"
+     << "}\n\n";
+}
+
index 5acca560f0131fd36fef6c30afa74ea12c99f8d0..91ec754346a1716e2eb2f9780522a68e536b237c 100644 (file)
@@ -109,6 +109,19 @@ class ClangAttrLateParsedListEmitter : public TableGenBackend {
   void run(raw_ostream &OS);
 };
 
+/// ClangAttrTemplateInstantiateEmitter emits code to instantiate dependent
+/// attributes on templates.
+class ClangAttrTemplateInstantiateEmitter : public TableGenBackend {
+  RecordKeeper &Records;
+
+ public:
+  explicit ClangAttrTemplateInstantiateEmitter(RecordKeeper &R)
+    : Records(R)
+    {}
+
+  void run(raw_ostream &OS);
+};
+
 }
 
 #endif
index 1d5e28d936ff8b7713b4528cdfc6f9d73f4d2ed7..6462b3bb74496ea5756d72c9f0edd528c7f5f242 100644 (file)
@@ -36,6 +36,7 @@ enum ActionType {
   GenClangAttrPCHWrite,
   GenClangAttrSpellingList,
   GenClangAttrLateParsedList,
+  GenClangAttrTemplateInstantiate,
   GenClangDiagsDefs,
   GenClangDiagGroups,
   GenClangDiagsIndexName,
@@ -71,6 +72,9 @@ namespace {
                     clEnumValN(GenClangAttrLateParsedList,
                                "gen-clang-attr-late-parsed-list",
                                "Generate a clang attribute LateParsed list"),
+                    clEnumValN(GenClangAttrTemplateInstantiate,
+                               "gen-clang-attr-template-instantiate",
+                               "Generate a clang template instantiate code"),
                     clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
                                "Generate Clang diagnostics definitions"),
                     clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
@@ -122,6 +126,9 @@ public:
     case GenClangAttrLateParsedList:
       ClangAttrLateParsedListEmitter(Records).run(OS);
       break;
+    case GenClangAttrTemplateInstantiate:
+      ClangAttrTemplateInstantiateEmitter(Records).run(OS);
+      break;
     case GenClangDiagsDefs:
       ClangDiagsDefsEmitter(Records, ClangComponent).run(OS);
       break;