[cfe-commits] r148592 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/CMakeLists.txt include/clang/Makefile include/clang/Sema/CMakeLists.txt include/clang/Sema/Makefile 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

DeLesley Hutchins delesley at google.com
Fri Jan 20 14:37:07 PST 2012


Author: delesley
Date: Fri Jan 20 16:37:06 2012
New Revision: 148592

URL: http://llvm.org/viewvc/llvm-project?rev=148592&view=rev
Log:
Instantiate dependent attributes when instantiating templates.

Added:
    cfe/trunk/include/clang/Sema/CMakeLists.txt
    cfe/trunk/include/clang/Sema/Makefile
Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/CMakeLists.txt
    cfe/trunk/include/clang/Makefile
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.h
    cfe/trunk/utils/TableGen/TableGen.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Jan 20 16:37:06 2012
@@ -93,6 +93,8 @@
   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 @@
   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 @@
   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 @@
   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;
 }

Modified: cfe/trunk/include/clang/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CMakeLists.txt?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/include/clang/CMakeLists.txt (original)
+++ cfe/trunk/include/clang/CMakeLists.txt Fri Jan 20 16:37:06 2012
@@ -3,4 +3,5 @@
 add_subdirectory(Driver)
 add_subdirectory(Lex)
 add_subdirectory(Parse)
+add_subdirectory(Sema)
 add_subdirectory(Serialization)

Modified: cfe/trunk/include/clang/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Makefile?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/include/clang/Makefile (original)
+++ cfe/trunk/include/clang/Makefile Fri Jan 20 16:37:06 2012
@@ -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
 

Added: cfe/trunk/include/clang/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CMakeLists.txt?rev=148592&view=auto
==============================================================================
--- cfe/trunk/include/clang/Sema/CMakeLists.txt (added)
+++ cfe/trunk/include/clang/Sema/CMakeLists.txt Fri Jan 20 16:37:06 2012
@@ -0,0 +1,4 @@
+clang_tablegen(AttrTemplateInstantiate.inc -gen-clang-attr-template-instantiate
+  -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+  SOURCE ../Basic/Attr.td
+  TARGET ClangAttrTemplateInstantiate)

Added: cfe/trunk/include/clang/Sema/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Makefile?rev=148592&view=auto
==============================================================================
--- cfe/trunk/include/clang/Sema/Makefile (added)
+++ cfe/trunk/include/clang/Sema/Makefile Fri Jan 20 16:37:06 2012
@@ -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)/../../ $<
+

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Fri Jan 20 16:37:06 2012
@@ -44,4 +44,5 @@
   )
 
 add_dependencies(clangSema ClangARMNeon ClangAttrClasses ClangAttrList 
-                 ClangDiagnosticSema ClangDeclNodes ClangStmtNodes)
+                 ClangDiagnosticSema ClangDeclNodes ClangStmtNodes 
+                 ClangAttrTemplateInstantiate)

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jan 20 16:37:06 2012
@@ -7311,6 +7311,9 @@
 /// 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());
 }
 

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Jan 20 16:37:06 2012
@@ -393,13 +393,11 @@
   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(),

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Jan 20 16:37:06 2012
@@ -57,7 +57,9 @@
   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 @@
       }
     }
 
-    // FIXME: Is cloning correct for all attributes?
-    Attr *NewAttr = TmplAttr->clone(Context);
+    Attr *NewAttr =
+      instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs);
     New->addAttr(NewAttr);
   }
 }

Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Fri Jan 20 16:37:06 2012
@@ -1051,12 +1051,14 @@
  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 @@
 } // end namespace test_scoped_lockable
 
 
-
 namespace FunctionAttrTest {
 
 class Foo {
@@ -1727,4 +1728,127 @@
 };  // 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
+
+
 

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Jan 20 16:37:06 2012
@@ -89,6 +89,8 @@
     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 @@
       : 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 @@
     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 @@
     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 @@
          << "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 @@
     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 @@
     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 @@
     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 @@
       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 @@
 
   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 @@
   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 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";
+}
+

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.h?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.h (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.h Fri Jan 20 16:37:06 2012
@@ -109,6 +109,19 @@
   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

Modified: cfe/trunk/utils/TableGen/TableGen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/TableGen.cpp?rev=148592&r1=148591&r2=148592&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/TableGen.cpp (original)
+++ cfe/trunk/utils/TableGen/TableGen.cpp Fri Jan 20 16:37:06 2012
@@ -36,6 +36,7 @@
   GenClangAttrPCHWrite,
   GenClangAttrSpellingList,
   GenClangAttrLateParsedList,
+  GenClangAttrTemplateInstantiate,
   GenClangDiagsDefs,
   GenClangDiagGroups,
   GenClangDiagsIndexName,
@@ -71,6 +72,9 @@
                     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 @@
     case GenClangAttrLateParsedList:
       ClangAttrLateParsedListEmitter(Records).run(OS);
       break;
+    case GenClangAttrTemplateInstantiate:
+      ClangAttrTemplateInstantiateEmitter(Records).run(OS);
+      break;
     case GenClangDiagsDefs:
       ClangDiagsDefsEmitter(Records, ClangComponent).run(OS);
       break;





More information about the cfe-commits mailing list