Properly switch into the declaring scope of a template when performing

template argument deduction or (more importantly) the final substitution
required by such deduction.  Makes access control magically work in these
cases.

Fixes PR6967.

llvm-svn: 102572
This commit is contained in:
John McCall 2010-04-29 00:35:03 +00:00
parent d170206761
commit 80e58cd3e9
4 changed files with 85 additions and 3 deletions

View File

@ -233,6 +233,30 @@ public:
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
/// A RAII object to temporarily push a declaration context.
class ContextRAII {
private:
Sema &S;
DeclContext *SavedContext;
public:
ContextRAII(Sema &S, DeclContext *ContextToPush)
: S(S), SavedContext(S.CurContext) {
assert(ContextToPush && "pushing null context");
S.CurContext = ContextToPush;
}
void pop() {
if (!SavedContext) return;
S.CurContext = SavedContext;
SavedContext = 0;
}
~ContextRAII() {
pop();
}
};
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"

View File

@ -988,6 +988,8 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
if (Inst)
return TDK_InstantiationDepth;
ContextRAII SavedContext(*this, Partial->getDeclContext());
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
@ -1163,6 +1165,8 @@ Sema::SubstituteExplicitTemplateArguments(
if (Inst)
return TDK_InstantiationDepth;
ContextRAII SavedContext(*this, FunctionTemplate->getDeclContext());
if (CheckTemplateArgumentList(FunctionTemplate,
SourceLocation(),
ExplicitTemplateArgs,
@ -1311,6 +1315,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
if (Inst)
return TDK_InstantiationDepth;
ContextRAII SavedContext(*this, FunctionTemplate->getDeclContext());
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.

View File

@ -1167,8 +1167,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
DeclContext *PreviousContext = CurContext;
CurContext = Instantiation;
ContextRAII SavedContext(*this, Instantiation);
// If this is an instantiation of a local class, merge this local
// instantiation scope with the enclosing scope. Otherwise, every
@ -1209,7 +1208,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Invalid = true;
// Exit the scope of this instantiation.
CurContext = PreviousContext;
SavedContext.pop();
// If this is a polymorphic C++ class without a key function, we'll
// have to mark all of the virtual members to allow emission of a vtable

View File

@ -52,3 +52,56 @@ namespace test1 {
A apriv = priv; // expected-error {{private constructor}}
}
}
// PR6967
namespace test2 {
class A {
public:
template <class T> static void set(T &t, typename T::type v) {
t.value = v;
}
template <class T> static typename T::type get(const T &t) {
return t.value;
}
};
class B {
friend class A;
private:
typedef int type;
type value;
};
int test() {
B b;
A::set(b, 0);
return A::get(b);
}
}
namespace test3 {
class Green {}; class Blue {};
// We have to wrap this in a class because a partial specialization
// isn't actually in the context of the template.
struct Outer {
template <class T, class Nat> class A {
};
};
template <class T> class Outer::A<T, typename T::nature> {
public:
static void foo();
};
class B {
private: typedef Green nature;
friend class Outer;
};
void test() {
Outer::A<B, Green>::foo();
Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo'}}
}
}