diff options
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 20 | ||||
-rw-r--r-- | test/SemaCXX/warn-thread-safety-analysis.cpp | 79 |
2 files changed, 99 insertions, 0 deletions
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 621f92bb67..665dd07b8f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -2635,8 +2635,25 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, return Instantiator.TransformTemplateArguments(Args, NumArgs, Result); } + +static const Decl* getCanonicalParmVarDecl(const Decl *D) { + // When storing ParmVarDecls in the local instantiation scope, we always + // want to use the ParmVarDecl from the canonical function declaration, + // since the map is then valid for any redeclaration or definition of that + // function. + if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(D)) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { + unsigned i = PV->getFunctionScopeIndex(); + return FD->getCanonicalDecl()->getParamDecl(i); + } + } + return D; +} + + llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> * LocalInstantiationScope::findInstantiationOf(const Decl *D) { + D = getCanonicalParmVarDecl(D); for (LocalInstantiationScope *Current = this; Current; Current = Current->Outer) { @@ -2668,6 +2685,7 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { } void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { + D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; if (Stored.isNull()) Stored = Inst; @@ -2680,11 +2698,13 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, Decl *Inst) { + D = getCanonicalParmVarDecl(D); DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>(); Pack->push_back(Inst); } void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { + D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; assert(Stored.isNull() && "Already instantiated this local"); DeclArgumentPack *Pack = new DeclArgumentPack; diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp index fd3577c303..a82d265a7e 100644 --- a/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -3524,3 +3524,82 @@ void derivedFun(Derived *d) EXCLUSIVE_LOCKS_REQUIRED(d->getMutex()) { } // end namespace VirtualMethodCanonicalizationTest + +namespace TemplateFunctionParamRemapTest { + +template <class T> +struct Cell { + T dummy_; + Mutex* mu_; +}; + +class Foo { +public: + template <class T> + void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_))); + + void test(); +}; + +template<class T> +void Foo::elr(Cell<T>* c1) { } + +void Foo::test() { + Cell<int> cell; + elr(&cell); // \ + // expected-warning {{calling function 'elr' requires exclusive lock on 'cell.mu_'}} +} + + +template<class T> +void globalELR(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_))); + +template<class T> +void globalELR(Cell<T>* c1) { } + +void globalTest() { + Cell<int> cell; + globalELR(&cell); // \ + // expected-warning {{calling function 'globalELR' requires exclusive lock on 'cell.mu_'}} +} + + +template<class T> +void globalELR2(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_))); + +// second declaration +template<class T> +void globalELR2(Cell<T>* c2); + +template<class T> +void globalELR2(Cell<T>* c3) { } + +// re-declaration after definition +template<class T> +void globalELR2(Cell<T>* c4); + +void globalTest2() { + Cell<int> cell; + globalELR2(&cell); // \ + // expected-warning {{calling function 'globalELR2' requires exclusive lock on 'cell.mu_'}} +} + + +template<class T> +class FooT { +public: + void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_))); +}; + +template<class T> +void FooT<T>::elr(Cell<T>* c1) { } + +void testFooT() { + Cell<int> cell; + FooT<int> foo; + foo.elr(&cell); // \ + // expected-warning {{calling function 'elr' requires exclusive lock on 'cell.mu_'}} +} + +} // end namespace TemplateFunctionParamRemapTest + |