PR12585: When processing a friend template inside a class template, don't

pretend there was no previous declaration -- that can lead us to injecting
a class template (with no access specifier) into a class scope. Instead,
just avoid the problematic checks.

llvm-svn: 155303
This commit is contained in:
Richard Smith 2012-04-22 02:13:50 +00:00
parent 4304101fb2
commit e85e176600
5 changed files with 69 additions and 15 deletions

View File

@ -3658,6 +3658,8 @@ def err_member_def_undefined_record : Error<
"out-of-line definition of %0 from class %1 without definition">;
def err_member_def_does_not_match : Error<
"out-of-line definition of %0 does not match any declaration in %1">;
def err_friend_decl_does_not_match : Error<
"friend declaration of %0 does not match any declaration in %1">;
def err_member_def_does_not_match_suggest : Error<
"out-of-line definition of %0 does not match any declaration in %1; "
"did you mean %2?">;

View File

@ -969,20 +969,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
}
}
if (CurContext->isDependentContext() && PrevClassTemplate) {
// If this is a dependent context, we don't want to link the friend
// class template to the template in scope, because that would perform
// checking of the template parameter lists that can't be performed
// until the outer context is instantiated.
PrevDecl = PrevClassTemplate = 0;
}
} else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = PrevClassTemplate = 0;
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible.
if (!TemplateParameterListsAreEqual(TemplateParams,
// Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself
// could be dependent.
if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
!TemplateParameterListsAreEqual(TemplateParams,
PrevClassTemplate->getTemplateParameters(),
/*Complain=*/true,
TPL_TemplateMatch))
@ -1031,8 +1026,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Check the template parameter list of this declaration, possibly
// merging in the template parameter list from the previous class
// template declaration.
if (CheckTemplateParameterList(TemplateParams,
// template declaration. Skip this check for a friend in a dependent
// context, because the template parameter list might be dependent.
if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
CheckTemplateParameterList(TemplateParams,
PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
(SS.isSet() && SemanticContext &&
SemanticContext->isRecord() &&
@ -1044,9 +1041,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (SS.isSet()) {
// If the name of the template was qualified, we must be defining the
// template out-of-line.
if (!SS.isInvalid() && !Invalid && !PrevClassTemplate &&
!(TUK == TUK_Friend && CurContext->isDependentContext())) {
Diag(NameLoc, diag::err_member_def_does_not_match)
if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) {
Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match
: diag::err_member_def_does_not_match)
<< Name << SemanticContext << SS.getRange();
Invalid = true;
}

View File

@ -11,3 +11,11 @@ class F {
a->x = 0;
}
};
template<typename T> class PR12585::future_base::setter {
public:
int f() {
return promise<T*>().k;
}
};
int k = PR12585::future_base::setter<int>().f();

View File

@ -4,3 +4,15 @@ class A {
int x;
friend class F;
};
namespace PR12585 {
struct future_base {
template<typename> class setter;
};
template<typename> class promise {
// We used to inject this into future_base with no access specifier,
// then crash during AST writing.
template<typename> friend class future_base::setter;
int k;
};
}

View File

@ -267,3 +267,38 @@ namespace PR12557 {
Bar<int> b;
}
namespace PR12585 {
struct A { };
template<typename> struct B {
template<typename> friend class A::does_not_exist; // \
// expected-error {{friend declaration of 'does_not_exist' does not match any declaration in 'PR12585::A'}}
};
struct C {
template<typename> struct D;
};
template<typename> class E {
int n;
template<typename> friend struct C::D;
};
template<typename T> struct C::D {
int f() {
return E<int>().n;
}
};
int n = C::D<void*>().f();
struct F {
template<int> struct G;
};
template<typename T> struct H {
// FIXME: As with cases above, the note here is on an unhelpful declaration,
// and should point to the declaration of G within F.
template<T> friend struct F::G; // \
// expected-error {{different type 'char' in template redeclaration}} \
// expected-note {{previous}}
};
H<int> h1; // ok
H<char> h2; // expected-note {{instantiation}}
}