Improve our handling of local instantiation scopes in two related ways:
- When substituting template arguments as part of template argument
deduction, introduce a new local instantiation scope.
- When substituting into a function prototype type, introduce a new
"temporary" local instantiation scope that merges with its outer
scope but also keeps track of any additions it makes, removing
them when we exit that scope.
Fixes PR6700, where we were getting too much mixing of local
instantiation scopes due to template argument deduction that
substituted results into function types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99509 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index ba6d38f..7e2e614 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3487,15 +3487,27 @@
/// \brief Whether we have already exited this scope.
bool Exited;
+ /// \brief Whether this scope is temporary, meaning that we should
+ /// remove any additions we make once we exit this
+ /// scope. Temporary scopes are always combined with their outer
+ /// scopes.
+ bool Temporary;
+
+ /// \brief List of the declarations that we have added into this
+ /// temporary scope. They will be removed when we exit the
+ /// temporary scope.
+ llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
- LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
+ LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
+ bool Temporary = false)
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
- Exited(false) {
- if (!CombineWithOuterScope)
+ Exited(false), Temporary(Temporary) {
+ if (!CombineWithOuterScope && !Temporary)
SemaRef.CurrentInstantiationScope = this;
else
assert(SemaRef.CurrentInstantiationScope &&
@@ -3503,8 +3515,11 @@
}
~LocalInstantiationScope() {
- if (!Exited)
+ if (!Exited) {
SemaRef.CurrentInstantiationScope = Outer;
+ for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I)
+ LocalDecls.erase(AddedTemporaryDecls[I]);
+ }
}
/// \brief Exit this local instantiation scope early.
@@ -3537,6 +3552,10 @@
void InstantiatedLocal(const Decl *D, Decl *Inst) {
Decl *&Stored = LocalDecls[D];
assert((!Stored || Stored == Inst) && "Already instantiated this local");
+
+ if (Temporary && !Stored)
+ AddedTemporaryDecls.push_back(D);
+
Stored = Inst;
}
};