diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 73a6854161af0f31910c0577129f7d6da1b02920..f522e76b0673ba298ae79beba0f9d314f8f55896 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2109,7 +2109,6 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { 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 : RecursiveASTVisitor<DependencyChecker> { 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::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, 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(Sema &S, NamedDecl *New, NamedDecl *Old, // 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())) { diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp index 59e9136bd142fc69d00e7c176c48a52200adc39a..401b7704900ba93d82dcaf5d7c3ff6cb4102e152 100644 --- a/test/Modules/cxx-templates.cpp +++ b/test/Modules/cxx-templates.cpp @@ -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. diff --git a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp index 5eee34e8097eecb94c3237adcf992c9ffb637968..d6374e4ce90754d175dc8c8a890b5f20780226e0 100644 --- a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -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...>); diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp index 8ac65aacd5b4e013633c42231f8c00c63e6780b4..74eb5a6ee58192d4a3bf7fec5770cd4414a4b1a7 100644 --- a/test/SemaTemplate/deduction.cpp +++ b/test/SemaTemplate/deduction.cpp @@ -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 { diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp index b0df9149c6e017cae8c900d5826f4fec48da7f2c..8f59dd724cc212e58637edae460722f8dc0b56fe 100644 --- a/test/SemaTemplate/temp_arg_template.cpp +++ b/test/SemaTemplate/temp_arg_template.cpp @@ -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> {}; } diff --git a/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/test/SemaTemplate/temp_arg_template_cxx1z.cpp index e3f228e7efb7493b7ef0f961380d5d40ee9b1a5a..03ef78f8cf14e1704d615196194d2eacda41a926 100644 --- a/test/SemaTemplate/temp_arg_template_cxx1z.cpp +++ b/test/SemaTemplate/temp_arg_template_cxx1z.cpp @@ -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;