diff options
author | DeLesley Hutchins <delesley@google.com> | 2012-01-20 22:50:54 +0000 |
---|---|---|
committer | DeLesley Hutchins <delesley@google.com> | 2012-01-20 22:50:54 +0000 |
commit | 23323e0253716ff03c95a00fb6903019daafe3aa (patch) | |
tree | 765f6ebb8f08a68f2881021e582472a27fcb1d24 | |
parent | 7b9ff0c09025dcbe48ec7db71330e2066d1e1863 (diff) |
Delayed template instantiation of late-parsed attributes.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148595 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Attr.h | 2 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 16 | ||||
-rw-r--r-- | include/clang/Sema/Template.h | 63 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 25 | ||||
-rw-r--r-- | test/SemaCXX/warn-thread-safety-analysis.cpp | 65 | ||||
-rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 7 |
8 files changed, 172 insertions, 31 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 449e916eb1..55c9cb59e5 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -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; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 923209bbed..b6126033da 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index 78f50fa9ff..bc3eba3f2d 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -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 *> > diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 00a03390da..ad31cbd643 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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()); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index a41878fcc1..2b96a1c744 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 60bcbfb255..c9d2cf6e18 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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; } diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp index a3d6a8b0bb..f992380433 100644 --- a/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -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(); +} + + +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; + } - // FIXME: This doesn't work yet - // CellDelayed<int> celld; - // celld.foo(); + 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 - diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index dd3de66fbd..7db1ababb1 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -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"; } |