forked from OSchip/llvm-project
Instantiate dependent attributes when instantiating templates.
llvm-svn: 148592
This commit is contained in:
parent
ce6a2ca8c8
commit
ceec3063e2
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3,4 +3,5 @@ add_subdirectory(Basic)
|
|||
add_subdirectory(Driver)
|
||||
add_subdirectory(Lex)
|
||||
add_subdirectory(Parse)
|
||||
add_subdirectory(Sema)
|
||||
add_subdirectory(Serialization)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
clang_tablegen(AttrTemplateInstantiate.inc -gen-clang-attr-template-instantiate
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||
SOURCE ../Basic/Attr.td
|
||||
TARGET ClangAttrTemplateInstantiate)
|
|
@ -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)/../../ $<
|
||||
|
|
@ -44,4 +44,5 @@ add_clang_library(clangSema
|
|||
)
|
||||
|
||||
add_dependencies(clangSema ClangARMNeon ClangAttrClasses ClangAttrList
|
||||
ClangDiagnosticSema ClangDeclNodes ClangStmtNodes)
|
||||
ClangDiagnosticSema ClangDeclNodes ClangStmtNodes
|
||||
ClangAttrTemplateInstantiate)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue