2019-07-19 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.
+ (invalid_nontype_parm_type_p): Check for dependent class type.
+
PR c++/85552 - wrong instantiation of dtor for DMI.
* typeck2.c (digest_nsdmi_init): Set tf_no_cleanup for direct-init.
if (conv)
{
+ /* Don't copy a class non-type template parameter. */
+ if (CLASS_TYPE_P (type) && conv->kind == ck_rvalue
+ && TREE_CODE (expr) == VIEW_CONVERT_EXPR
+ && TREE_CODE (TREE_OPERAND (expr, 0)) == TEMPLATE_PARM_INDEX)
+ conv = next_conversion (conv);
+
conv->check_narrowing = true;
conv->check_narrowing_const_only = true;
expr = convert_like (conv, expr, complain);
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])
/* 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
"with %<-std=c++2a%> or %<-std=gnu++2a%>");
return true;
}
+ if (dependent_type_p (type))
+ return false;
if (!complete_type_or_else (type, NULL_TREE))
return true;
if (!literal_type_p (type))
--- /dev/null
+// 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;
--- /dev/null
+// 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...> {};
--- /dev/null
+// 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...> {};
--- /dev/null
+// PR c++/90101
+// { dg-do compile { target c++2a } }
+
+template<int N>
+struct A{};
+
+template<int N, A<N>>
+struct B {};
+
+B<2,A<2>{}> b;
--- /dev/null
+// PR c++/90100
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+inline constexpr bool is_nontype_list = false;
+
+template<template<auto...> typename T, auto... NonTypes>
+inline constexpr bool is_nontype_list<T<NonTypes...>> = true;
+
+// works
+template<auto...>
+struct A {};
+
+static_assert(is_nontype_list<A<1, 2, 3>>);
+
+// fails
+struct X {
+ int v;
+};
+
+static_assert(is_nontype_list<A<X{1}, X{2}, X{3}>>);