Author: rsmith Date: Thu Apr 13 16:37:24 2017 New Revision: 300262 URL: http://llvm.org/viewvc/llvm-project?rev=300262&view=rev Log: 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. Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/Modules/cxx-templates.cpp cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp cfe/trunk/test/SemaTemplate/deduction.cpp cfe/trunk/test/SemaTemplate/temp_arg_template.cpp cfe/trunk/test/SemaTemplate/temp_arg_template_cxx1z.cpp Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=300262&r1=300261&r2=300262&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr 13 16:37:24 2017 @@ -2109,7 +2109,6 @@ struct DependencyChecker : RecursiveASTV typedef RecursiveASTVisitor<DependencyChecker> super; unsigned Depth; - bool FindLessThanDepth; // Whether we're looking for a use of a template parameter that makes the // overall construct type-dependent / a dependent type. This is strictly @@ -2120,16 +2119,25 @@ struct DependencyChecker : RecursiveASTV bool Match; SourceLocation MatchLoc; - DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent, - bool FindLessThanDepth = false) - : Depth(Depth), FindLessThanDepth(FindLessThanDepth), - IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) {} + DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent) + : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent), + Match(false) {} DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent) - : DependencyChecker(Params->getDepth(), IgnoreNonTypeDependent) {} + : IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) { + NamedDecl *ND = Params->getParam(0); + if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) { + Depth = PD->getDepth(); + } else if (NonTypeTemplateParmDecl *PD = + dyn_cast<NonTypeTemplateParmDecl>(ND)) { + Depth = PD->getDepth(); + } else { + Depth = cast<TemplateTemplateParmDecl>(ND)->getDepth(); + } + } bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) { - if (FindLessThanDepth ^ (ParmDepth >= Depth)) { + if (ParmDepth >= Depth) { Match = true; MatchLoc = Loc; return true; @@ -6432,15 +6440,6 @@ Sema::BuildExpressionFromIntegralTemplat return E; } -static bool isDependentOnOuter(NonTypeTemplateParmDecl *NTTP) { - if (NTTP->getDepth() == 0 || !NTTP->getType()->isDependentType()) - return false; - DependencyChecker Checker(NTTP->getDepth(), /*IgnoreNonTypeDependent*/ false, - /*FindLessThanDepth*/ true); - Checker.TraverseType(NTTP->getType()); - return Checker.Match; -} - /// \brief Match two template parameters within template parameter lists. static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, bool Complain, @@ -6497,10 +6496,11 @@ static bool MatchTemplateParameterKind(S // If we are matching a template template argument to a template // template parameter and one of the non-type template parameter types - // is dependent on an outer template's parameter, then we must wait until - // template instantiation time to actually compare the arguments. + // is dependent, then we must wait until template instantiation time + // to actually compare the arguments. if (Kind == Sema::TPL_TemplateTemplateArgumentMatch && - (isDependentOnOuter(OldNTTP) || isDependentOnOuter(NewNTTP))) + (OldNTTP->getType()->isDependentType() || + NewNTTP->getType()->isDependentType())) return true; if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { Modified: cfe/trunk/test/Modules/cxx-templates.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-templates.cpp?rev=300262&r1=300261&r2=300262&view=diff ============================================================================== --- cfe/trunk/test/Modules/cxx-templates.cpp (original) +++ cfe/trunk/test/Modules/cxx-templates.cpp Thu Apr 13 16:37:24 2017 @@ -49,8 +49,14 @@ void g() { // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}} - template_param_kinds_3<Tmpl_T_T_A>(); - template_param_kinds_3<Tmpl_T_T_B>(); + // FIXME: This should be valid, but we incorrectly match the template template + // argument against both template template parameters. + template_param_kinds_3<Tmpl_T_T_A>(); // expected-error {{ambiguous}} + // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}} + template_param_kinds_3<Tmpl_T_T_B>(); // expected-error {{ambiguous}} + // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}} // Trigger the instantiation of a template in 'a' that uses a type defined in // 'common'. That type is not visible here. Modified: cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp?rev=300262&r1=300261&r2=300262&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp Thu Apr 13 16:37:24 2017 @@ -179,9 +179,9 @@ namespace default_args_from_ctor { namespace transform_params { template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]> - struct A { // expected-note 2{{candidate}} + struct A { template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W> - A(U<X>, W<Y>); // expected-note {{[with V = int, M = 12, Y = &transform_params::n]}} + A(U<X>, W<Y>); static constexpr T v = N; }; @@ -189,9 +189,7 @@ namespace transform_params { int n[12]; template<int (*)[12]> struct Q {}; Q<&n> qn; - // FIXME: The class template argument deduction result here is correct, but - // we incorrectly fail to deduce arguments for the constructor! - A a(qn, qn); // expected-error {{no matching constructor for initialization of 'transform_params::A<int, 12, Q, &transform_params::n>'}} + A a(qn, qn); static_assert(a.v == 12); template<typename ...T> struct B { @@ -203,16 +201,12 @@ namespace transform_params { }; B b({1, 2, 3}, "foo", {'x', 'y', 'z', 'w'}); // ok - // This should be accepted once -std=c++1z implies - // -frelaxed-template-template-args. Without that, a template template - // parameter 'template<int, int, int> typename' cannot bind to a template - // template argument 'template<int...> typename'. - template<typename ...T> struct C { // expected-note {{candidate}} + template<typename ...T> struct C { template<T ...V, template<T...> typename X> - C(X<V...>); // expected-note {{substitution failure [with T = <int, int, int>, V = <0, 1, 2>]}} + C(X<V...>); }; template<int...> struct Y {}; - C c(Y<0, 1, 2>{}); // expected-error {{no viable constructor or deduction guide}} + C c(Y<0, 1, 2>{}); template<typename ...T> struct D { template<T ...V> D(Y<V...>); Modified: cfe/trunk/test/SemaTemplate/deduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/deduction.cpp?rev=300262&r1=300261&r2=300262&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/deduction.cpp (original) +++ cfe/trunk/test/SemaTemplate/deduction.cpp Thu Apr 13 16:37:24 2017 @@ -483,16 +483,15 @@ namespace check_extended_pack { } namespace dependent_template_template_param_non_type_param_type { - template<int N> struct A { // expected-note 2{{candidate}} + template<int N> struct A { template<typename V = int, V M = 12, V (*Y)[M], template<V (*v)[M]> class W> - A(W<Y>); // expected-note {{[with V = int, M = 12, Y = &dependent_template_template_param_non_type_param_type::n]}} + A(W<Y>); }; int n[12]; template<int (*)[12]> struct Q {}; Q<&n> qn; - // FIXME: This should be accepted, but we somehow fail to deduce W. - A<0> a(qn); // expected-error {{no matching constructor for initialization}} + A<0> a(qn); } namespace dependent_list_deduction { Modified: cfe/trunk/test/SemaTemplate/temp_arg_template.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_template.cpp?rev=300262&r1=300261&r2=300262&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_template.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_template.cpp Thu Apr 13 16:37:24 2017 @@ -102,7 +102,42 @@ void foo() { } namespace CheckDependentNonTypeParamTypes { - template<template<typename T, typename U, T v> class> struct A {}; // expected-note {{previous}} - template<typename T, typename U, U v> struct B {}; // expected-note {{different type}} - A<B> ab; // expected-error {{different template parameters}} + template<template<typename T, typename U, T v> class X> struct A { + void f() { + X<int, void*, 3> x; // expected-error {{does not refer to any declaration}} + } + void g() { + X<int, long, 3> x; + } + void h() { + // FIXME: If we accept A<B> at all, it's not obvious what should happen + // here. While parsing the template, we form + // X<unsigned char, int, (unsigned char)1234> + // but in the final instantiation do we get + // B<unsigned char, int, (int)1234> + // or + // B<unsigned char, int, (int)(unsigned char)1234> + // ? + X<unsigned char, int, 1234> x; + int check[x.value == 1234 ? 1 : -1]; + } + }; + + template<typename T, typename U, U v> struct B { // expected-note {{parameter}} + static const U value = v; + }; + + // FIXME: This should probably be rejected, but the rules are at best unclear. + A<B> ab; + + void use() { + ab.f(); // expected-note {{instantiation of}} + ab.g(); + ab.h(); + } +} + +namespace PR32185 { + template<template<typename T, T> class U> struct A {}; + template<template<typename T, T> class U> struct B : A<U> {}; } Modified: cfe/trunk/test/SemaTemplate/temp_arg_template_cxx1z.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_template_cxx1z.cpp?rev=300262&r1=300261&r2=300262&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg_template_cxx1z.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg_template_cxx1z.cpp Thu Apr 13 16:37:24 2017 @@ -78,7 +78,7 @@ namespace Auto { template<int*> struct IntPtr; TInt<Auto> ia; - TInt<AutoPtr> iap; // expected-error {{different template parameters}} + TInt<AutoPtr> iap; // FIXME: ill-formed (?) TInt<DecltypeAuto> ida; TInt<Int> ii; TInt<IntPtr> iip; // expected-error {{different template parameters}} @@ -90,18 +90,18 @@ namespace Auto { TIntPtr<IntPtr> ipip; TAuto<Auto> aa; - TAuto<AutoPtr> aap; // expected-error {{different template parameters}} - TAuto<Int> ai; // expected-error {{different template parameters}} - TAuto<IntPtr> aip; // expected-error {{different template parameters}} + TAuto<AutoPtr> aap; // FIXME: ill-formed (?) + TAuto<Int> ai; // FIXME: ill-formed (?) + TAuto<IntPtr> aip; // FIXME: ill-formed (?) TAutoPtr<Auto> apa; TAutoPtr<AutoPtr> apap; - TAutoPtr<Int> api; // expected-error {{different template parameters}} - TAutoPtr<IntPtr> apip; // expected-error {{different template parameters}} + TAutoPtr<Int> api; // FIXME: ill-formed (?) + TAutoPtr<IntPtr> apip; // FIXME: ill-formed (?) TDecltypeAuto<DecltypeAuto> dada; - TDecltypeAuto<Int> dai; // expected-error {{different template parameters}} - TDecltypeAuto<IntPtr> daip; // expected-error {{different template parameters}} + TDecltypeAuto<Int> dai; // FIXME: ill-formed (?) + TDecltypeAuto<IntPtr> daip; // FIXME: ill-formed (?) // FIXME: It's completely unclear what should happen here, but these results // seem at least plausible: @@ -111,7 +111,7 @@ namespace Auto { // parameters (such as 'user-defined-type &') that are not valid 'auto' // parameters. TDecltypeAuto<Auto> daa; - TDecltypeAuto<AutoPtr> daa; // expected-error {{different template parameters}} + TDecltypeAuto<AutoPtr> daap; // FIXME: should probably be ill-formed int n; template<auto A, decltype(A) B = &n> struct SubstFailure; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits