From: Richard Smith Date: Thu, 13 Apr 2017 21:37:24 +0000 (+0000) Subject: PR32185: Revert r291512 and add a testcase for PR32185. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=24a137ec645bd77f10353247a0a63e0a082a11ec;p=clang 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 --- diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 73a6854161..f522e76b06 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2109,7 +2109,6 @@ struct DependencyChecker : RecursiveASTVisitor { typedef RecursiveASTVisitor 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 { 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(ND)) { + Depth = PD->getDepth(); + } else if (NonTypeTemplateParmDecl *PD = + dyn_cast(ND)) { + Depth = PD->getDepth(); + } else { + Depth = cast(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 59e9136bd1..401b770490 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(); - template_param_kinds_3(); + // FIXME: This should be valid, but we incorrectly match the template template + // argument against both template template parameters. + template_param_kinds_3(); // 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(); // 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 5eee34e809..d6374e4ce9 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 U, T (*X)[N]> - struct A { // expected-note 2{{candidate}} + struct A { template typename W> - A(U, W); // expected-note {{[with V = int, M = 12, Y = &transform_params::n]}} + A(U, W); static constexpr T v = N; }; @@ -189,9 +189,7 @@ namespace transform_params { int n[12]; template 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'}} + A a(qn, qn); static_assert(a.v == 12); template 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 typename' cannot bind to a template - // template argument 'template typename'. - template struct C { // expected-note {{candidate}} + template struct C { template typename X> - C(X); // expected-note {{substitution failure [with T = , V = <0, 1, 2>]}} + C(X); }; template struct Y {}; - C c(Y<0, 1, 2>{}); // expected-error {{no viable constructor or deduction guide}} + C c(Y<0, 1, 2>{}); template struct D { template D(Y); diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp index 8ac65aacd5..74eb5a6ee5 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 struct A { // expected-note 2{{candidate}} + template struct A { template class W> - A(W); // expected-note {{[with V = int, M = 12, Y = &dependent_template_template_param_non_type_param_type::n]}} + A(W); }; int n[12]; template 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 b0df9149c6..8f59dd724c 100644 --- a/test/SemaTemplate/temp_arg_template.cpp +++ b/test/SemaTemplate/temp_arg_template.cpp @@ -102,7 +102,42 @@ void foo() { } namespace CheckDependentNonTypeParamTypes { - template class> struct A {}; // expected-note {{previous}} - template struct B {}; // expected-note {{different type}} - A ab; // expected-error {{different template parameters}} + template class X> struct A { + void f() { + X x; // expected-error {{does not refer to any declaration}} + } + void g() { + X x; + } + void h() { + // FIXME: If we accept A at all, it's not obvious what should happen + // here. While parsing the template, we form + // X + // but in the final instantiation do we get + // B + // or + // B + // ? + X x; + int check[x.value == 1234 ? 1 : -1]; + } + }; + + template struct B { // expected-note {{parameter}} + static const U value = v; + }; + + // FIXME: This should probably be rejected, but the rules are at best unclear. + A ab; + + void use() { + ab.f(); // expected-note {{instantiation of}} + ab.g(); + ab.h(); + } +} + +namespace PR32185 { + template class U> struct A {}; + template class U> struct B : A {}; } diff --git a/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/test/SemaTemplate/temp_arg_template_cxx1z.cpp index e3f228e7ef..03ef78f8cf 100644 --- a/test/SemaTemplate/temp_arg_template_cxx1z.cpp +++ b/test/SemaTemplate/temp_arg_template_cxx1z.cpp @@ -78,7 +78,7 @@ namespace Auto { template struct IntPtr; TInt ia; - TInt iap; // expected-error {{different template parameters}} + TInt iap; // FIXME: ill-formed (?) TInt ida; TInt ii; TInt iip; // expected-error {{different template parameters}} @@ -90,18 +90,18 @@ namespace Auto { TIntPtr ipip; TAuto aa; - TAuto aap; // expected-error {{different template parameters}} - TAuto ai; // expected-error {{different template parameters}} - TAuto aip; // expected-error {{different template parameters}} + TAuto aap; // FIXME: ill-formed (?) + TAuto ai; // FIXME: ill-formed (?) + TAuto aip; // FIXME: ill-formed (?) TAutoPtr apa; TAutoPtr apap; - TAutoPtr api; // expected-error {{different template parameters}} - TAutoPtr apip; // expected-error {{different template parameters}} + TAutoPtr api; // FIXME: ill-formed (?) + TAutoPtr apip; // FIXME: ill-formed (?) TDecltypeAuto dada; - TDecltypeAuto dai; // expected-error {{different template parameters}} - TDecltypeAuto daip; // expected-error {{different template parameters}} + TDecltypeAuto dai; // FIXME: ill-formed (?) + TDecltypeAuto 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 daa; - TDecltypeAuto daa; // expected-error {{different template parameters}} + TDecltypeAuto daap; // FIXME: should probably be ill-formed int n; template struct SubstFailure;