Instantiate dependent attributes when instantiating templates.

llvm-svn: 148592
This commit is contained in:
DeLesley Hutchins 2012-01-20 22:37:06 +00:00
parent ce6a2ca8c8
commit ceec3063e2
13 changed files with 339 additions and 18 deletions

View 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;
}

View File

@ -3,4 +3,5 @@ add_subdirectory(Basic)
add_subdirectory(Driver)
add_subdirectory(Lex)
add_subdirectory(Parse)
add_subdirectory(Sema)
add_subdirectory(Serialization)

View 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

View File

@ -0,0 +1,4 @@
clang_tablegen(AttrTemplateInstantiate.inc -gen-clang-attr-template-instantiate
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrTemplateInstantiate)

View File

@ -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)/../../ $<

View File

@ -44,4 +44,5 @@ add_clang_library(clangSema
)
add_dependencies(clangSema ClangARMNeon ClangAttrClasses ClangAttrList
ClangDiagnosticSema ClangDeclNodes ClangStmtNodes)
ClangDiagnosticSema ClangDeclNodes ClangStmtNodes
ClangAttrTemplateInstantiate)

View 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());
}

View 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(),

View 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);
}
}

View 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

View 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";
}

View 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

View 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;