PR c++/90098 - partial specialization and class non-type parms.
authorJason Merrill <jason@redhat.com>
Fri, 19 Jul 2019 06:52:47 +0000 (02:52 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 19 Jul 2019 06:52:47 +0000 (02:52 -0400)
A non-type template parameter of class type used in an expression has
const-qualified type; the pt.c hunks deal with this difference from the
unqualified type of the parameter declaration.  WAhen we use such a
parameter as an argument to another template, we don't want to confuse
things by copying it, we should pass it straight through.  And we might as
well skip copying other classes in constant evaluation context in a
template, too; we'll get the copy semantics at instantiation time.

PR c++/90099
PR c++/90101
* call.c (build_converted_constant_expr_internal): Don't copy.
* pt.c (process_partial_specialization): Allow VIEW_CONVERT_EXPR
around class non-type parameter.
(unify) [TEMPLATE_PARM_INDEX]: Ignore cv-quals.

From-SVN: r273591

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/nontype-class18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nontype-class19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nontype-class20.C [new file with mode: 0644]

index c9091f523c54b99d0810ece53b551239eafe2682..cef36b2d1b2ffe7bebb10aa5e5dcf73874675171 100644 (file)
@@ -1,3 +1,13 @@
+2019-07-18  Jason Merrill  <jason@redhat.com>
+
+       PR c++/90098 - partial specialization and class non-type parms.
+       PR c++/90099
+       PR c++/90101
+       * call.c (build_converted_constant_expr_internal): Don't copy.
+       * pt.c (process_partial_specialization): Allow VIEW_CONVERT_EXPR
+       around class non-type parameter.
+       (unify) [TEMPLATE_PARM_INDEX]: Ignore cv-quals.
+
 2019-07-16  Jason Merrill  <jason@redhat.com>
 
        * parser.c (make_location): Add overload taking cp_lexer* as last
index e597d7ac9196cc19cf59f0bfd247b682ea5251dc..38d229b1f3333eb7f442dfc9e18c9edf8dc29c46 100644 (file)
@@ -4278,6 +4278,11 @@ build_converted_constant_expr_internal (tree type, tree expr,
 
   if (conv)
     {
+      /* Don't copy a class in a template.  */
+      if (CLASS_TYPE_P (type) && conv->kind == ck_rvalue
+         && processing_template_decl)
+       conv = next_conversion (conv);
+
       conv->check_narrowing = true;
       conv->check_narrowing_const_only = true;
       expr = convert_like (conv, expr, complain);
index e23c0aaf325a53cb98c1b7b64bc7faec04e4da60..53aaad1800a6b8b3545cfc8a99fabfecfe8dcb16 100644 (file)
@@ -4954,7 +4954,8 @@ process_partial_specialization (tree decl)
                  simple identifier' condition and also the `specialized
                  non-type argument' bit.  */
               && TREE_CODE (arg) != TEMPLATE_PARM_INDEX
-             && !(REFERENCE_REF_P (arg)
+             && !((REFERENCE_REF_P (arg)
+                   || TREE_CODE (arg) == VIEW_CONVERT_EXPR)
                   && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_PARM_INDEX))
             {
               if ((!packed_args && tpd.arg_uses_template_parms[i])
@@ -22371,9 +22372,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
        /* Template-parameter dependent expression.  Just accept it for now.
           It will later be processed in convert_template_argument.  */
        ;
-      else if (same_type_p (non_reference (TREE_TYPE (arg)),
-                           non_reference (tparm)))
-       /* OK */;
+      else if (same_type_ignoring_top_level_qualifiers_p
+              (non_reference (TREE_TYPE (arg)),
+               non_reference (tparm)))
+       /* OK.  Ignore top-level quals here because a class-type template
+          parameter object is const.  */;
       else if ((strict & UNIFY_ALLOW_INTEGER)
               && CP_INTEGRAL_TYPE_P (tparm))
        /* Convert the ARG to the type of PARM; the deduced non-type
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class18.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class18.C
new file mode 100644 (file)
index 0000000..22f4788
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/90101
+// { dg-do compile { target c++2a } }
+
+template<typename List>
+struct A;
+
+template<template<auto...> typename List>
+struct A<List<>> {};
+
+template<template<auto...> typename List, auto V>
+struct A<List<V>> {};
+
+template<auto>
+struct B {};
+
+struct X { int value; };
+A<B<X{1}>> a2;
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class19.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class19.C
new file mode 100644 (file)
index 0000000..91267ac
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/90099
+// { dg-do compile { target c++2a } }
+
+struct Unit {
+  int value;
+  // auto operator<=>(const Unit&) = default;
+};
+
+template<Unit U, typename... Ts>
+struct X {};
+
+template<Unit U, typename T, typename... Rest>
+struct X<U, T, Rest...> {};
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class20.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class20.C
new file mode 100644 (file)
index 0000000..5d3479c
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/90098
+// { dg-do compile { target c++2a } }
+
+struct A {
+  int value;
+  // auto operator<=>(const A&) = default;
+};
+
+template<A... Us>
+struct Z {};
+
+template<A V, A... Rest>
+struct Z<V, Rest...> {};