Delayed template instantiation of late-parsed attributes.

llvm-svn: 148595
This commit is contained in:
DeLesley Hutchins 2012-01-20 22:50:54 +00:00
parent 52ee45d64a
commit 30398dd410
8 changed files with 172 additions and 31 deletions

View File

@ -104,6 +104,8 @@ public:
// Clone this attribute.
virtual Attr* clone(ASTContext &C) const = 0;
virtual bool isLateParsed() const { return false; }
// Pretty print this attribute.
virtual void printPretty(llvm::raw_ostream &OS, ASTContext &C) const = 0;

View File

@ -5131,8 +5131,22 @@ public:
TemplateSpecializationKind TSK,
bool Complain = true);
struct LateInstantiatedAttribute {
const Attr *TmplAttr;
LocalInstantiationScope *Scope;
Decl *NewDecl;
LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S,
Decl *D)
: TmplAttr(A), Scope(S), NewDecl(D)
{ }
};
typedef SmallVector<LateInstantiatedAttribute, 16> LateInstantiatedAttrVec;
void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Pattern, Decl *Inst);
const Decl *Pattern, Decl *Inst,
LateInstantiatedAttrVec *LateAttrs = 0,
LocalInstantiationScope *OuterMostScope = 0);
bool
InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation,

View File

@ -268,6 +268,50 @@ namespace clang {
Exited = true;
}
/// \brief Clone this scope, and all outer scopes, down to the given
/// outermost scope.
LocalInstantiationScope *cloneScopes(LocalInstantiationScope *Outermost) {
if (this == Outermost) return this;
LocalInstantiationScope *newScope =
new LocalInstantiationScope(SemaRef, CombineWithOuterScope);
newScope->Outer = 0;
if (Outer)
newScope->Outer = Outer->cloneScopes(Outermost);
newScope->PartiallySubstitutedPack = PartiallySubstitutedPack;
newScope->ArgsInPartiallySubstitutedPack = ArgsInPartiallySubstitutedPack;
newScope->NumArgsInPartiallySubstitutedPack =
NumArgsInPartiallySubstitutedPack;
for (LocalDeclsMap::iterator I = LocalDecls.begin(), E = LocalDecls.end();
I != E; ++I) {
const Decl *D = I->first;
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored =
newScope->LocalDecls[D];
if (I->second.is<Decl *>()) {
Stored = I->second.get<Decl *>();
} else {
DeclArgumentPack *OldPack = I->second.get<DeclArgumentPack *>();
DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack);
Stored = NewPack;
newScope->ArgumentPacks.push_back(NewPack);
}
}
return newScope;
}
/// \brief deletes the given scope, and all otuer scopes, down to the
/// given outermost scope.
static void deleteScopes(LocalInstantiationScope *Scope,
LocalInstantiationScope *Outermost) {
while (Scope && Scope != Outermost) {
LocalInstantiationScope *Out = Scope->Outer;
delete Scope;
Scope = Out;
}
}
/// \brief Find the instantiation of the declaration D within the current
/// instantiation scope.
///
@ -314,6 +358,8 @@ namespace clang {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex;
DeclContext *Owner;
const MultiLevelTemplateArgumentList &TemplateArgs;
Sema::LateInstantiatedAttrVec* LateAttrs;
LocalInstantiationScope *StartingScope;
/// \brief A list of out-of-line class template partial
/// specializations that will need to be instantiated after the
@ -326,7 +372,7 @@ namespace clang {
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs)
: SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner),
TemplateArgs(TemplateArgs) { }
TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0) { }
// FIXME: Once we get closer to completion, replace these manually-written
// declarations with automatically-generated ones from
@ -382,6 +428,21 @@ namespace clang {
return 0;
}
// Enable late instantiation of attributes. Late instantiated attributes
// will be stored in LA.
void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) {
LateAttrs = LA;
StartingScope = SemaRef.CurrentInstantiationScope;
}
// Disable late instantiation of attributes.
void disableLateAttributeInstantiation() {
LateAttrs = 0;
StartingScope = 0;
}
LocalInstantiationScope *getStartingScope() const { return StartingScope; }
typedef
SmallVectorImpl<std::pair<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *> >

View File

@ -857,7 +857,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
ConsumeToken(); // Eat the comma, move to the next argument
}
// Match the ')'.
if (ArgExprsOk && !T.consumeClose() && ArgExprs.size() > 0) {
if (ArgExprsOk && !T.consumeClose()) {
Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
ArgExprs.take(), ArgExprs.size());
}

View File

@ -1654,6 +1654,10 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
return Invalid;
}
// Defined via #include from SemaTemplateInstantiateDecl.cpp
Attr* instantiateTemplateAttribute(const Attr *At, ASTContext &C, Sema &S,
const MultiLevelTemplateArgumentList &TemplateArgs);
/// \brief Instantiate the definition of a class from a given pattern.
///
/// \param PointOfInstantiation The point of instantiation within the
@ -1763,6 +1767,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
SmallVector<Decl*, 4> Fields;
SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
FieldsWithMemberInitializers;
// Delay instantiation of late parsed attributes.
LateInstantiatedAttrVec LateAttrs;
Instantiator.enableLateAttributeInstantiation(&LateAttrs);
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
@ -1822,6 +1830,21 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
}
}
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
E = LateAttrs.end(); I != E; ++I) {
assert(CurrentInstantiationScope == Instantiator.getStartingScope());
CurrentInstantiationScope = I->Scope;
Attr *NewAttr =
instantiateTemplateAttribute(I->TmplAttr, Context, *this, TemplateArgs);
I->NewDecl->addAttr(NewAttr);
LocalInstantiationScope::deleteScopes(I->Scope,
Instantiator.getStartingScope());
}
Instantiator.disableLateAttributeInstantiation();
LateAttrs.clear();
if (!FieldsWithMemberInitializers.empty())
ActOnFinishDelayedMemberInitializers(Instantiation);

View File

@ -61,10 +61,13 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
#include "clang/Sema/AttrTemplateInstantiate.inc"
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New) {
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
for (AttrVec::const_iterator i = Tmpl->attr_begin(), e = Tmpl->attr_end();
i != e; ++i) {
const Attr *TmplAttr = *i;
// FIXME: This should be generalized to more than just the AlignedAttr.
if (const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr)) {
if (Aligned->isAlignmentDependent()) {
@ -89,9 +92,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
}
Attr *NewAttr =
instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs);
New->addAttr(NewAttr);
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
// enclosing class has been instantiated. See Sema::InstantiateClass.
LocalInstantiationScope *Saved = 0;
if (CurrentInstantiationScope)
Saved = CurrentInstantiationScope->cloneScopes(OuterMostScope);
LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New));
} else {
Attr *NewAttr =
instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs);
New->addAttr(NewAttr);
}
}
}
@ -495,7 +507,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
return 0;
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Field);
SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
if (Invalid)
Field->setInvalidDecl();
@ -2378,7 +2390,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
// Get the definition. Leaves the variable unchanged if undefined.
Tmpl->isDefined(Definition);
SemaRef.InstantiateAttrs(TemplateArgs, Definition, New);
SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,
LateAttrs, StartingScope);
return false;
}

View File

@ -1051,14 +1051,12 @@ class Foo {
public:
void func(T x) {
mu_.Lock();
// count_ = x;
count_ = x;
mu_.Unlock();
}
private:
// FIXME: This test passed earlier only because thread safety was turned
// off for templates.
// T count_ GUARDED_BY(mu_);
T count_ GUARDED_BY(mu_);
Bar<T> bar_;
Mutex mu_;
};
@ -1790,27 +1788,15 @@ public:
// Test dependent guarded_by
T data GUARDED_BY(mu_);
void foo() {
mu_.Lock();
void fooEx() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
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() {
@ -1842,13 +1828,50 @@ void test() {
cell.data = 0; // \
// expected-warning {{writing variable 'data' requires locking 'mu_' exclusively}}
cell.foo();
cell.mu_.Lock();
cell.fooEx();
cell.mu_.Unlock();
}
// FIXME: This doesn't work yet
// CellDelayed<int> celld;
// celld.foo();
template <class T>
class CellDelayed {
public:
// Test dependent guarded_by
T data GUARDED_BY(mu_);
void fooEx(CellDelayed<T> *other) EXCLUSIVE_LOCKS_REQUIRED(mu_, other->mu_) {
this->data = other->data;
}
template <class T2>
void fooExT(CellDelayed<T2> *otherT) EXCLUSIVE_LOCKS_REQUIRED(mu_, otherT->mu_) {
this->data = otherT->data;
}
void foo() {
mu_.Lock();
data = 0;
mu_.Unlock();
}
Mutex mu_;
};
void testDelayed() {
CellDelayed<int> celld;
CellDelayed<int> celld2;
celld.foo();
celld.mu_.Lock();
celld2.mu_.Lock();
celld.fooEx(&celld2);
celld.fooExT(&celld2);
celld2.mu_.Unlock();
celld.mu_.Unlock();
}
}; // end namespace TestTemplateAttributeInstantiation

View File

@ -349,7 +349,7 @@ namespace {
<< "Size;\n";
OS << " }\n";
OS << " unsigned " << getLowerName() << "_size() const {\n"
<< " return " << getLowerName() << "Size;\n;";
<< " return " << getLowerName() << "Size;\n";
OS << " }";
}
void writeCloneArgs(raw_ostream &OS) const {
@ -709,6 +709,11 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) {
<< "attr::" << R.getName() << "; }\n";
OS << " static bool classof(const " << R.getName()
<< "Attr *) { return true; }\n";
bool LateParsed = R.getValueAsBit("LateParsed");
OS << " virtual bool isLateParsed() const { return "
<< LateParsed << "; }\n";
OS << "};\n\n";
}