mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 23:26:05 +00:00
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:
parent
d170206761
commit
80e58cd3e9
@ -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*"
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user