Skip to content

Commit 24a137e

Browse files
committed
PR32185: Revert r291512 and add a testcase for PR32185.
This reverts an attempt to check that types match when matching a dependently-typed non-type template parameter. (This comes up when matching the parameters of a template template parameter against the parameters of a template template argument.) The matching rules here are murky at best. Our behavior after this revert is definitely wrong for certain C++17 features (for 'auto' template parameter types within the parameter list of a template template argument in particular), but our behavior before this revert is wrong for some pre-existing testcases, so reverting to our prior behavior seems like our best option. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@300262 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 08a97a0 commit 24a137e

File tree

6 files changed

+83
-49
lines changed

6 files changed

+83
-49
lines changed

lib/Sema/SemaTemplate.cpp

+19-19
Original file line numberDiff line numberDiff line change
@@ -2109,7 +2109,6 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
21092109
typedef RecursiveASTVisitor<DependencyChecker> super;
21102110

21112111
unsigned Depth;
2112-
bool FindLessThanDepth;
21132112

21142113
// Whether we're looking for a use of a template parameter that makes the
21152114
// overall construct type-dependent / a dependent type. This is strictly
@@ -2120,16 +2119,25 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
21202119
bool Match;
21212120
SourceLocation MatchLoc;
21222121

2123-
DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent,
2124-
bool FindLessThanDepth = false)
2125-
: Depth(Depth), FindLessThanDepth(FindLessThanDepth),
2126-
IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) {}
2122+
DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent)
2123+
: Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent),
2124+
Match(false) {}
21272125

21282126
DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent)
2129-
: DependencyChecker(Params->getDepth(), IgnoreNonTypeDependent) {}
2127+
: IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) {
2128+
NamedDecl *ND = Params->getParam(0);
2129+
if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) {
2130+
Depth = PD->getDepth();
2131+
} else if (NonTypeTemplateParmDecl *PD =
2132+
dyn_cast<NonTypeTemplateParmDecl>(ND)) {
2133+
Depth = PD->getDepth();
2134+
} else {
2135+
Depth = cast<TemplateTemplateParmDecl>(ND)->getDepth();
2136+
}
2137+
}
21302138

21312139
bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) {
2132-
if (FindLessThanDepth ^ (ParmDepth >= Depth)) {
2140+
if (ParmDepth >= Depth) {
21332141
Match = true;
21342142
MatchLoc = Loc;
21352143
return true;
@@ -6432,15 +6440,6 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
64326440
return E;
64336441
}
64346442

6435-
static bool isDependentOnOuter(NonTypeTemplateParmDecl *NTTP) {
6436-
if (NTTP->getDepth() == 0 || !NTTP->getType()->isDependentType())
6437-
return false;
6438-
DependencyChecker Checker(NTTP->getDepth(), /*IgnoreNonTypeDependent*/ false,
6439-
/*FindLessThanDepth*/ true);
6440-
Checker.TraverseType(NTTP->getType());
6441-
return Checker.Match;
6442-
}
6443-
64446443
/// \brief Match two template parameters within template parameter lists.
64456444
static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
64466445
bool Complain,
@@ -6497,10 +6496,11 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
64976496

64986497
// If we are matching a template template argument to a template
64996498
// template parameter and one of the non-type template parameter types
6500-
// is dependent on an outer template's parameter, then we must wait until
6501-
// template instantiation time to actually compare the arguments.
6499+
// is dependent, then we must wait until template instantiation time
6500+
// to actually compare the arguments.
65026501
if (Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
6503-
(isDependentOnOuter(OldNTTP) || isDependentOnOuter(NewNTTP)))
6502+
(OldNTTP->getType()->isDependentType() ||
6503+
NewNTTP->getType()->isDependentType()))
65046504
return true;
65056505

65066506
if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {

test/Modules/cxx-templates.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,14 @@ void g() {
4949
// expected-note@Inputs/cxx-templates-a.h:11 {{candidate}}
5050
// expected-note@Inputs/cxx-templates-b.h:11 {{candidate}}
5151

52-
template_param_kinds_3<Tmpl_T_T_A>();
53-
template_param_kinds_3<Tmpl_T_T_B>();
52+
// FIXME: This should be valid, but we incorrectly match the template template
53+
// argument against both template template parameters.
54+
template_param_kinds_3<Tmpl_T_T_A>(); // expected-error {{ambiguous}}
55+
// expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
56+
// expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
57+
template_param_kinds_3<Tmpl_T_T_B>(); // expected-error {{ambiguous}}
58+
// expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
59+
// expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
5460

5561
// Trigger the instantiation of a template in 'a' that uses a type defined in
5662
// 'common'. That type is not visible here.

test/SemaCXX/cxx1z-class-template-argument-deduction.cpp

+6-12
Original file line numberDiff line numberDiff line change
@@ -179,19 +179,17 @@ namespace default_args_from_ctor {
179179

180180
namespace transform_params {
181181
template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]>
182-
struct A { // expected-note 2{{candidate}}
182+
struct A {
183183
template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W>
184-
A(U<X>, W<Y>); // expected-note {{[with V = int, M = 12, Y = &transform_params::n]}}
184+
A(U<X>, W<Y>);
185185

186186
static constexpr T v = N;
187187
};
188188

189189
int n[12];
190190
template<int (*)[12]> struct Q {};
191191
Q<&n> qn;
192-
// FIXME: The class template argument deduction result here is correct, but
193-
// we incorrectly fail to deduce arguments for the constructor!
194-
A a(qn, qn); // expected-error {{no matching constructor for initialization of 'transform_params::A<int, 12, Q, &transform_params::n>'}}
192+
A a(qn, qn);
195193
static_assert(a.v == 12);
196194

197195
template<typename ...T> struct B {
@@ -203,16 +201,12 @@ namespace transform_params {
203201
};
204202
B b({1, 2, 3}, "foo", {'x', 'y', 'z', 'w'}); // ok
205203

206-
// This should be accepted once -std=c++1z implies
207-
// -frelaxed-template-template-args. Without that, a template template
208-
// parameter 'template<int, int, int> typename' cannot bind to a template
209-
// template argument 'template<int...> typename'.
210-
template<typename ...T> struct C { // expected-note {{candidate}}
204+
template<typename ...T> struct C {
211205
template<T ...V, template<T...> typename X>
212-
C(X<V...>); // expected-note {{substitution failure [with T = <int, int, int>, V = <0, 1, 2>]}}
206+
C(X<V...>);
213207
};
214208
template<int...> struct Y {};
215-
C c(Y<0, 1, 2>{}); // expected-error {{no viable constructor or deduction guide}}
209+
C c(Y<0, 1, 2>{});
216210

217211
template<typename ...T> struct D {
218212
template<T ...V> D(Y<V...>);

test/SemaTemplate/deduction.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -483,16 +483,15 @@ namespace check_extended_pack {
483483
}
484484

485485
namespace dependent_template_template_param_non_type_param_type {
486-
template<int N> struct A { // expected-note 2{{candidate}}
486+
template<int N> struct A {
487487
template<typename V = int, V M = 12, V (*Y)[M], template<V (*v)[M]> class W>
488-
A(W<Y>); // expected-note {{[with V = int, M = 12, Y = &dependent_template_template_param_non_type_param_type::n]}}
488+
A(W<Y>);
489489
};
490490

491491
int n[12];
492492
template<int (*)[12]> struct Q {};
493493
Q<&n> qn;
494-
// FIXME: This should be accepted, but we somehow fail to deduce W.
495-
A<0> a(qn); // expected-error {{no matching constructor for initialization}}
494+
A<0> a(qn);
496495
}
497496

498497
namespace dependent_list_deduction {

test/SemaTemplate/temp_arg_template.cpp

+38-3
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,42 @@ void foo() {
102102
}
103103

104104
namespace CheckDependentNonTypeParamTypes {
105-
template<template<typename T, typename U, T v> class> struct A {}; // expected-note {{previous}}
106-
template<typename T, typename U, U v> struct B {}; // expected-note {{different type}}
107-
A<B> ab; // expected-error {{different template parameters}}
105+
template<template<typename T, typename U, T v> class X> struct A {
106+
void f() {
107+
X<int, void*, 3> x; // expected-error {{does not refer to any declaration}}
108+
}
109+
void g() {
110+
X<int, long, 3> x;
111+
}
112+
void h() {
113+
// FIXME: If we accept A<B> at all, it's not obvious what should happen
114+
// here. While parsing the template, we form
115+
// X<unsigned char, int, (unsigned char)1234>
116+
// but in the final instantiation do we get
117+
// B<unsigned char, int, (int)1234>
118+
// or
119+
// B<unsigned char, int, (int)(unsigned char)1234>
120+
// ?
121+
X<unsigned char, int, 1234> x;
122+
int check[x.value == 1234 ? 1 : -1];
123+
}
124+
};
125+
126+
template<typename T, typename U, U v> struct B { // expected-note {{parameter}}
127+
static const U value = v;
128+
};
129+
130+
// FIXME: This should probably be rejected, but the rules are at best unclear.
131+
A<B> ab;
132+
133+
void use() {
134+
ab.f(); // expected-note {{instantiation of}}
135+
ab.g();
136+
ab.h();
137+
}
138+
}
139+
140+
namespace PR32185 {
141+
template<template<typename T, T> class U> struct A {};
142+
template<template<typename T, T> class U> struct B : A<U> {};
108143
}

test/SemaTemplate/temp_arg_template_cxx1z.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ namespace Auto {
7878
template<int*> struct IntPtr;
7979

8080
TInt<Auto> ia;
81-
TInt<AutoPtr> iap; // expected-error {{different template parameters}}
81+
TInt<AutoPtr> iap; // FIXME: ill-formed (?)
8282
TInt<DecltypeAuto> ida;
8383
TInt<Int> ii;
8484
TInt<IntPtr> iip; // expected-error {{different template parameters}}
@@ -90,18 +90,18 @@ namespace Auto {
9090
TIntPtr<IntPtr> ipip;
9191

9292
TAuto<Auto> aa;
93-
TAuto<AutoPtr> aap; // expected-error {{different template parameters}}
94-
TAuto<Int> ai; // expected-error {{different template parameters}}
95-
TAuto<IntPtr> aip; // expected-error {{different template parameters}}
93+
TAuto<AutoPtr> aap; // FIXME: ill-formed (?)
94+
TAuto<Int> ai; // FIXME: ill-formed (?)
95+
TAuto<IntPtr> aip; // FIXME: ill-formed (?)
9696

9797
TAutoPtr<Auto> apa;
9898
TAutoPtr<AutoPtr> apap;
99-
TAutoPtr<Int> api; // expected-error {{different template parameters}}
100-
TAutoPtr<IntPtr> apip; // expected-error {{different template parameters}}
99+
TAutoPtr<Int> api; // FIXME: ill-formed (?)
100+
TAutoPtr<IntPtr> apip; // FIXME: ill-formed (?)
101101

102102
TDecltypeAuto<DecltypeAuto> dada;
103-
TDecltypeAuto<Int> dai; // expected-error {{different template parameters}}
104-
TDecltypeAuto<IntPtr> daip; // expected-error {{different template parameters}}
103+
TDecltypeAuto<Int> dai; // FIXME: ill-formed (?)
104+
TDecltypeAuto<IntPtr> daip; // FIXME: ill-formed (?)
105105

106106
// FIXME: It's completely unclear what should happen here, but these results
107107
// seem at least plausible:
@@ -111,7 +111,7 @@ namespace Auto {
111111
// parameters (such as 'user-defined-type &') that are not valid 'auto'
112112
// parameters.
113113
TDecltypeAuto<Auto> daa;
114-
TDecltypeAuto<AutoPtr> daa; // expected-error {{different template parameters}}
114+
TDecltypeAuto<AutoPtr> daap; // FIXME: should probably be ill-formed
115115

116116
int n;
117117
template<auto A, decltype(A) B = &n> struct SubstFailure;

0 commit comments

Comments
 (0)