r300262 - PR32185: Revert r291512 and add a testcase for PR32185.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 13 14:37:24 PDT 2017


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 at Inputs/cxx-templates-a.h:11 {{candidate}}
   // expected-note at 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 at Inputs/cxx-templates-a.h:12 {{candidate}}
+  // expected-note at Inputs/cxx-templates-b.h:12 {{candidate}}
+  template_param_kinds_3<Tmpl_T_T_B>(); // expected-error {{ambiguous}}
+  // expected-note at Inputs/cxx-templates-a.h:12 {{candidate}}
+  // expected-note at 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;




More information about the cfe-commits mailing list