Commit 4a826ca6 by Jason Merrill Committed by Jason Merrill

Implement P0127R2, Declaring non-type parameters with auto.

gcc/cp/
	* cp-tree.h (enum auto_deduction_context): Add adc_unify.
	* decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type
	parameter types.
	* pt.c (do_auto_deduction): Add outer_targs parameter.
	(convert_template_argument): Call do_auto_deduction.  If adc_unify,
	don't give up on dependent init.
	(unify): Likewise.  In C++17, walk into the type of a
	TEMPLATE_PARM_INDEX.
	(for_each_template_parm): Add any_fn parameter.
	(struct pair_fn_data): Likewise.
	(for_each_template_parm_r): Call it for any tree.  In C++17, walk
	into the type of a TEMPLATE_PARM_INDEX.
	(zero_r, array_deduction_r, try_array_deduction): New.
	(type_unification_real): Call try_array_deduction.
	(get_partial_spec_bindings): Likewise.
gcc/c-family/
	* c-cppbuiltin.c (c_cpp_builtins): Define __cpp_template_auto.

From-SVN: r242017
parent ff1f317b
2016-11-09 Jason Merrill <jason@redhat.com>
* c-cppbuiltin.c (c_cpp_builtins): Define __cpp_template_auto.
2016-11-09 Jakub Jelinek <jakub@redhat.com> 2016-11-09 Jakub Jelinek <jakub@redhat.com>
* c-ubsan.c (ubsan_instrument_shift): Handle split * c-ubsan.c (ubsan_instrument_shift): Handle split
......
...@@ -942,6 +942,7 @@ c_cpp_builtins (cpp_reader *pfile) ...@@ -942,6 +942,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_aggregate_bases=201603"); cpp_define (pfile, "__cpp_aggregate_bases=201603");
cpp_define (pfile, "__cpp_deduction_guides=201606"); cpp_define (pfile, "__cpp_deduction_guides=201606");
cpp_define (pfile, "__cpp_noexcept_function_type=201510"); cpp_define (pfile, "__cpp_noexcept_function_type=201510");
cpp_define (pfile, "__cpp_template_auto=201606");
} }
if (flag_concepts) if (flag_concepts)
cpp_define (pfile, "__cpp_concepts=201507"); cpp_define (pfile, "__cpp_concepts=201507");
......
2016-11-09 Jason Merrill <jason@redhat.com>
Implement P0127R2, Declaring non-type parameters with auto.
* cp-tree.h (enum auto_deduction_context): Add adc_unify.
* decl.c (grokdeclarator): Allow 'auto' in C++17 template non-type
parameter types.
* pt.c (do_auto_deduction): Add outer_targs parameter.
(convert_template_argument): Call do_auto_deduction. If adc_unify,
don't give up on dependent init.
(unify): Likewise. In C++17, walk into the type of a
TEMPLATE_PARM_INDEX.
(for_each_template_parm): Add any_fn parameter.
(struct pair_fn_data): Likewise.
(for_each_template_parm_r): Call it for any tree. In C++17, walk
into the type of a TEMPLATE_PARM_INDEX.
(zero_r, array_deduction_r, try_array_deduction): New.
(type_unification_real): Call try_array_deduction.
(get_partial_spec_bindings): Likewise.
2016-11-07 Jason Merrill <jason@redhat.com> 2016-11-07 Jason Merrill <jason@redhat.com>
Implement P0012R1, Make exception specifications part of the type Implement P0012R1, Make exception specifications part of the type
......
...@@ -5163,6 +5163,7 @@ enum auto_deduction_context ...@@ -5163,6 +5163,7 @@ enum auto_deduction_context
adc_unspecified, /* Not given */ adc_unspecified, /* Not given */
adc_variable_type, /* Variable initializer deduction */ adc_variable_type, /* Variable initializer deduction */
adc_return_type, /* Return type deduction */ adc_return_type, /* Return type deduction */
adc_unify, /* Template argument deduction */
adc_requirement /* Argument dedution constraint */ adc_requirement /* Argument dedution constraint */
}; };
...@@ -6088,7 +6089,8 @@ extern tree make_template_placeholder (tree); ...@@ -6088,7 +6089,8 @@ extern tree make_template_placeholder (tree);
extern tree do_auto_deduction (tree, tree, tree); extern tree do_auto_deduction (tree, tree, tree);
extern tree do_auto_deduction (tree, tree, tree, extern tree do_auto_deduction (tree, tree, tree,
tsubst_flags_t, tsubst_flags_t,
auto_deduction_context); auto_deduction_context,
tree = NULL_TREE);
extern tree type_uses_auto (tree); extern tree type_uses_auto (tree);
extern tree type_uses_auto_or_concept (tree); extern tree type_uses_auto_or_concept (tree);
extern void append_type_to_template_for_access_check (tree, tree, tree, extern void append_type_to_template_for_access_check (tree, tree, tree,
......
...@@ -11135,7 +11135,8 @@ grokdeclarator (const cp_declarator *declarator, ...@@ -11135,7 +11135,8 @@ grokdeclarator (const cp_declarator *declarator,
if (ctype || in_namespace) if (ctype || in_namespace)
error ("cannot use %<::%> in parameter declaration"); error ("cannot use %<::%> in parameter declaration");
if (type_uses_auto (type)) if (type_uses_auto (type)
&& !(cxx_dialect >= cxx1z && template_parm_flag))
{ {
if (cxx_dialect >= cxx14) if (cxx_dialect >= cxx14)
error ("%<auto%> parameter not permitted in this context"); error ("%<auto%> parameter not permitted in this context");
......
...@@ -161,7 +161,7 @@ static tree convert_nontype_argument (tree, tree, tsubst_flags_t); ...@@ -161,7 +161,7 @@ static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
static tree convert_template_argument (tree, tree, tree, static tree convert_template_argument (tree, tree, tree,
tsubst_flags_t, int, tree); tsubst_flags_t, int, tree);
static tree for_each_template_parm (tree, tree_fn_t, void*, static tree for_each_template_parm (tree, tree_fn_t, void*,
hash_set<tree> *, bool); hash_set<tree> *, bool, tree_fn_t = NULL);
static tree expand_template_argument_pack (tree); static tree expand_template_argument_pack (tree);
static tree build_template_parm_index (int, int, int, tree, tree); static tree build_template_parm_index (int, int, int, tree, tree);
static bool inline_needs_template_parms (tree, bool); static bool inline_needs_template_parms (tree, bool);
...@@ -7299,6 +7299,13 @@ convert_template_argument (tree parm, ...@@ -7299,6 +7299,13 @@ convert_template_argument (tree parm,
{ {
tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl); tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl);
if (tree a = type_uses_auto (t))
{
t = do_auto_deduction (t, arg, a, complain, adc_unspecified);
if (t == error_mark_node)
return error_mark_node;
}
if (invalid_nontype_parm_type_p (t, complain)) if (invalid_nontype_parm_type_p (t, complain))
return error_mark_node; return error_mark_node;
...@@ -8789,6 +8796,7 @@ lookup_and_finish_template_variable (tree templ, tree targs, ...@@ -8789,6 +8796,7 @@ lookup_and_finish_template_variable (tree templ, tree targs,
struct pair_fn_data struct pair_fn_data
{ {
tree_fn_t fn; tree_fn_t fn;
tree_fn_t any_fn;
void *data; void *data;
/* True when we should also visit template parameters that occur in /* True when we should also visit template parameters that occur in
non-deduced contexts. */ non-deduced contexts. */
...@@ -8811,11 +8819,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) ...@@ -8811,11 +8819,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
do \ do \
{ \ { \
result = for_each_template_parm (NODE, fn, data, pfd->visited, \ result = for_each_template_parm (NODE, fn, data, pfd->visited, \
pfd->include_nondeduced_p); \ pfd->include_nondeduced_p, \
pfd->any_fn); \
if (result) goto out; \ if (result) goto out; \
} \ } \
while (0) while (0)
if (pfd->any_fn && (*pfd->any_fn)(t, data))
return t;
if (TYPE_P (t) if (TYPE_P (t)
&& (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE)) && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE))
WALK_SUBTREE (TYPE_CONTEXT (t)); WALK_SUBTREE (TYPE_CONTEXT (t));
...@@ -8880,7 +8892,8 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) ...@@ -8880,7 +8892,8 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
if (pfd->include_nondeduced_p if (pfd->include_nondeduced_p
&& for_each_template_parm (TYPE_VALUES_RAW (t), fn, data, && for_each_template_parm (TYPE_VALUES_RAW (t), fn, data,
pfd->visited, pfd->visited,
pfd->include_nondeduced_p)) pfd->include_nondeduced_p,
pfd->any_fn))
return error_mark_node; return error_mark_node;
break; break;
...@@ -8911,6 +8924,12 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) ...@@ -8911,6 +8924,12 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
return t; return t;
else if (!fn) else if (!fn)
return t; return t;
/* In C++17 we can deduce a type argument from the type of a non-type
argument. */
if (cxx_dialect >= cxx1z
&& TREE_CODE (t) == TEMPLATE_PARM_INDEX)
WALK_SUBTREE (TREE_TYPE (t));
break; break;
case TEMPLATE_DECL: case TEMPLATE_DECL:
...@@ -8984,13 +9003,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) ...@@ -8984,13 +9003,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
static tree static tree
for_each_template_parm (tree t, tree_fn_t fn, void* data, for_each_template_parm (tree t, tree_fn_t fn, void* data,
hash_set<tree> *visited, hash_set<tree> *visited,
bool include_nondeduced_p) bool include_nondeduced_p,
tree_fn_t any_fn)
{ {
struct pair_fn_data pfd; struct pair_fn_data pfd;
tree result; tree result;
/* Set up. */ /* Set up. */
pfd.fn = fn; pfd.fn = fn;
pfd.any_fn = any_fn;
pfd.data = data; pfd.data = data;
pfd.include_nondeduced_p = include_nondeduced_p; pfd.include_nondeduced_p = include_nondeduced_p;
...@@ -18559,6 +18580,53 @@ unify_one_argument (tree tparms, tree targs, tree parm, tree arg, ...@@ -18559,6 +18580,53 @@ unify_one_argument (tree tparms, tree targs, tree parm, tree arg,
return unify (tparms, targs, parm, arg, arg_strict, explain_p); return unify (tparms, targs, parm, arg, arg_strict, explain_p);
} }
/* for_each_template_parm callback that always returns 0. */
static int
zero_r (tree, void *)
{
return 0;
}
/* for_each_template_parm any_fn callback to handle deduction of a template
type argument from the type of an array bound. */
static int
array_deduction_r (tree t, void *data)
{
tree_pair_p d = (tree_pair_p)data;
tree &tparms = d->purpose;
tree &targs = d->value;
if (TREE_CODE (t) == ARRAY_TYPE)
if (tree dom = TYPE_DOMAIN (t))
if (tree max = TYPE_MAX_VALUE (dom))
{
if (TREE_CODE (max) == MINUS_EXPR)
max = TREE_OPERAND (max, 0);
if (TREE_CODE (max) == TEMPLATE_PARM_INDEX)
unify (tparms, targs, TREE_TYPE (max), size_type_node,
UNIFY_ALLOW_NONE, /*explain*/false);
}
/* Keep walking. */
return 0;
}
/* Try to deduce any not-yet-deduced template type arguments from the type of
an array bound. This is handled separately from unify because 14.8.2.5 says
"The type of a type parameter is only deduced from an array bound if it is
not otherwise deduced." */
static void
try_array_deduction (tree tparms, tree targs, tree parm)
{
tree_pair_s data = { tparms, targs };
hash_set<tree> visited;
for_each_template_parm (parm, zero_r, &data, &visited,
/*nondeduced*/false, array_deduction_r);
}
/* Most parms like fn_type_unification. /* Most parms like fn_type_unification.
If SUBR is 1, we're being called recursively (to unify the If SUBR is 1, we're being called recursively (to unify the
...@@ -18688,6 +18756,7 @@ type_unification_real (tree tparms, ...@@ -18688,6 +18756,7 @@ type_unification_real (tree tparms,
tsubst_flags_t complain = (explain_p tsubst_flags_t complain = (explain_p
? tf_warning_or_error ? tf_warning_or_error
: tf_none); : tf_none);
bool tried_array_deduction = (cxx_dialect < cxx1z);
for (i = 0; i < ntparms; i++) for (i = 0; i < ntparms; i++)
{ {
...@@ -18706,6 +18775,15 @@ type_unification_real (tree tparms, ...@@ -18706,6 +18775,15 @@ type_unification_real (tree tparms,
continue; continue;
tparm = TREE_VALUE (tparm); tparm = TREE_VALUE (tparm);
if (TREE_CODE (tparm) == TYPE_DECL
&& !tried_array_deduction)
{
try_array_deduction (tparms, targs, xparms);
tried_array_deduction = true;
if (TREE_VEC_ELT (targs, i))
continue;
}
/* If this is an undeduced nontype parameter that depends on /* If this is an undeduced nontype parameter that depends on
a type parameter, try another pass; its type may have been a type parameter, try another pass; its type may have been
deduced from a later argument than the one from which deduced from a later argument than the one from which
...@@ -19378,8 +19456,8 @@ template_parm_level_and_index (tree parm, int* level, int* index) ...@@ -19378,8 +19456,8 @@ template_parm_level_and_index (tree parm, int* level, int* index)
/* Unifies the remaining arguments in PACKED_ARGS with the pack /* Unifies the remaining arguments in PACKED_ARGS with the pack
expansion at the end of PACKED_PARMS. Returns 0 if the type expansion at the end of PACKED_PARMS. Returns 0 if the type
deduction succeeds, 1 otherwise. STRICT is the same as in deduction succeeds, 1 otherwise. STRICT is the same as in
unify. CALL_ARGS_P is true iff PACKED_ARGS is actually a function fn_type_unification. CALL_ARGS_P is true iff PACKED_ARGS is actually a
call argument list. We'll need to adjust the arguments to make them function call argument list. We'll need to adjust the arguments to make them
types. SUBR tells us if this is from a recursive call to types. SUBR tells us if this is from a recursive call to
type_unification_real, or for comparing two template argument type_unification_real, or for comparing two template argument
lists. */ lists. */
...@@ -19680,6 +19758,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, ...@@ -19680,6 +19758,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
tree targ; tree targ;
tree tparm; tree tparm;
int strict_in = strict; int strict_in = strict;
tsubst_flags_t complain = (explain_p
? tf_warning_or_error
: tf_none);
/* I don't think this will do the right thing with respect to types. /* I don't think this will do the right thing with respect to types.
But the only case I've seen it in so far has been array bounds, where But the only case I've seen it in so far has been array bounds, where
...@@ -19897,9 +19978,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, ...@@ -19897,9 +19978,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
if (coerce_template_parms (parm_parms, if (coerce_template_parms (parm_parms,
full_argvec, full_argvec,
TYPE_TI_TEMPLATE (parm), TYPE_TI_TEMPLATE (parm),
(explain_p complain,
? tf_warning_or_error
: tf_none),
/*require_all_args=*/true, /*require_all_args=*/true,
/*use_default_args=*/false) /*use_default_args=*/false)
== error_mark_node) == error_mark_node)
...@@ -20046,6 +20125,18 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, ...@@ -20046,6 +20125,18 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
return x; return x;
} }
if (cxx_dialect >= cxx1z
/* We deduce from array bounds in try_array_deduction. */
&& !(strict & UNIFY_ALLOW_INTEGER)
&& uses_template_parms (TREE_TYPE (parm))
&& !type_uses_auto (TREE_TYPE (parm)))
{
tree atype = TREE_TYPE (arg);
RECUR_AND_CHECK_FAILURE (tparms, targs,
TREE_TYPE (parm), atype,
UNIFY_ALLOW_NONE, explain_p);
}
/* [temp.deduct.type] If, in the declaration of a function template /* [temp.deduct.type] If, in the declaration of a function template
with a non-type template-parameter, the non-type with a non-type template-parameter, the non-type
template-parameter is used in an expression in the function template-parameter is used in an expression in the function
...@@ -20055,6 +20146,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, ...@@ -20055,6 +20146,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
deduced from an array bound may be of any integral type. deduced from an array bound may be of any integral type.
The non-type parameter might use already deduced type parameters. */ The non-type parameter might use already deduced type parameters. */
tparm = tsubst (TREE_TYPE (parm), targs, 0, NULL_TREE); tparm = tsubst (TREE_TYPE (parm), targs, 0, NULL_TREE);
if (tree a = type_uses_auto (tparm))
{
tparm = do_auto_deduction (tparm, arg, a, complain, adc_unify);
if (tparm == error_mark_node)
return 1;
}
if (!TREE_TYPE (arg)) if (!TREE_TYPE (arg))
/* Template-parameter dependent expression. Just accept it for now. /* Template-parameter dependent expression. Just accept it for now.
It will later be processed in convert_template_argument. */ It will later be processed in convert_template_argument. */
...@@ -21015,6 +21113,8 @@ get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args) ...@@ -21015,6 +21113,8 @@ get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args)
else else
deduced_args = innermost_deduced_args; deduced_args = innermost_deduced_args;
bool tried_array_deduction = (cxx_dialect < cxx1z);
again:
if (unify (tparms, deduced_args, if (unify (tparms, deduced_args,
INNERMOST_TEMPLATE_ARGS (spec_args), INNERMOST_TEMPLATE_ARGS (spec_args),
INNERMOST_TEMPLATE_ARGS (args), INNERMOST_TEMPLATE_ARGS (args),
...@@ -21023,7 +21123,17 @@ get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args) ...@@ -21023,7 +21123,17 @@ get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args)
for (i = 0; i < ntparms; ++i) for (i = 0; i < ntparms; ++i)
if (! TREE_VEC_ELT (innermost_deduced_args, i)) if (! TREE_VEC_ELT (innermost_deduced_args, i))
return NULL_TREE; {
if (!tried_array_deduction)
{
try_array_deduction (tparms, innermost_deduced_args,
INNERMOST_TEMPLATE_ARGS (spec_args));
tried_array_deduction = true;
if (TREE_VEC_ELT (innermost_deduced_args, i))
goto again;
}
return NULL_TREE;
}
tree tinst = build_tree_list (spec_tmpl, deduced_args); tree tinst = build_tree_list (spec_tmpl, deduced_args);
if (!push_tinst_level (tinst)) if (!push_tinst_level (tinst))
...@@ -24607,14 +24717,16 @@ do_auto_deduction (tree type, tree init, tree auto_node) ...@@ -24607,14 +24717,16 @@ do_auto_deduction (tree type, tree init, tree auto_node)
tree tree
do_auto_deduction (tree type, tree init, tree auto_node, do_auto_deduction (tree type, tree init, tree auto_node,
tsubst_flags_t complain, auto_deduction_context context) tsubst_flags_t complain, auto_deduction_context context,
tree outer_targs)
{ {
tree targs; tree targs;
if (init == error_mark_node) if (init == error_mark_node)
return error_mark_node; return error_mark_node;
if (type_dependent_expression_p (init)) if (type_dependent_expression_p (init)
&& context != adc_unify)
/* Defining a subset of type-dependent expressions that we can deduce /* Defining a subset of type-dependent expressions that we can deduce
from ahead of time isn't worth the trouble. */ from ahead of time isn't worth the trouble. */
return type; return type;
...@@ -24733,6 +24845,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, ...@@ -24733,6 +24845,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
switch (context) switch (context)
{ {
case adc_unspecified: case adc_unspecified:
case adc_unify:
error("placeholder constraints not satisfied"); error("placeholder constraints not satisfied");
break; break;
case adc_variable_type: case adc_variable_type:
...@@ -24754,8 +24867,9 @@ do_auto_deduction (tree type, tree init, tree auto_node, ...@@ -24754,8 +24867,9 @@ do_auto_deduction (tree type, tree init, tree auto_node,
} }
} }
if (processing_template_decl) if (processing_template_decl && context != adc_unify)
targs = add_to_template_args (current_template_args (), targs); outer_targs = current_template_args ();
targs = add_to_template_args (outer_targs, targs);
return tsubst (type, targs, complain, NULL_TREE); return tsubst (type, targs, complain, NULL_TREE);
} }
......
...@@ -111,7 +111,7 @@ badthrow2 () throw (auto &) // { dg-error "invalid use of|expected" } ...@@ -111,7 +111,7 @@ badthrow2 () throw (auto &) // { dg-error "invalid use of|expected" }
{ {
} }
template <auto V = 4> struct G {}; // { dg-error "auto" } template <auto V = 4> struct G {}; // { dg-error "auto" "" { target { ! c++1z } } }
template <typename T> struct H { H (); ~H (); }; template <typename T> struct H { H (); ~H (); };
H<auto> h; // { dg-error "invalid|initializer" } H<auto> h; // { dg-error "invalid|initializer" }
......
...@@ -368,6 +368,12 @@ ...@@ -368,6 +368,12 @@
# error "__cpp_aligned_new != 201606" # error "__cpp_aligned_new != 201606"
#endif #endif
#ifndef __cpp_template_auto
# error "__cpp_template_auto"
#elif __cpp_template_auto != 201606
# error "__cpp_template_auto != 201606"
#endif
#ifndef __cpp_inline_variables #ifndef __cpp_inline_variables
# error "__cpp_inline_variables" # error "__cpp_inline_variables"
#elif __cpp_inline_variables != 201606 #elif __cpp_inline_variables != 201606
......
// Testcase from P0127R2
// { dg-options -std=c++1z }
template <long n> struct A { };
template <class T> struct C;
template <class T, T n> struct C<A<n>>
{
using Q = T;
};
typedef long R;
typedef C<A<2>>::Q R; // OK; T was deduced to long from the template argument value in the type A<2>
// Testcase from P0127R2
// { dg-options -std=c++1z }
template <typename T> struct S;
template <typename T, T n> struct S<int[n]> {
using Q = T;
};
typedef S<int[42]>::Q V;
typedef decltype(sizeof 0) V; // OK; T was deduced to std::size_t from the type int[42]
// Testcase from P0127R2
// { dg-options -std=c++1z }
template<auto n> struct B { decltype(n) f = n; };
B<5> b1; // OK: template parameter type is int
B<'a'> b2; // OK: template parameter type is char
B<2.5> b3; // { dg-error "" } template parameter type cannot be double
template <auto n> void f(B<n>) { }
int main()
{
f(B<42>());
f(B<'a'>());
}
// { dg-options -std=c++1z }
template <class T, T n> void f(T, int (&)[n]);
template <class T, T n> void g(int (&)[n], T);
template <class T, T n> void h(int (&)[n]);
int main()
{
const int i = 42;
int ar[i];
h(ar);
f(i, ar);
g(ar, i);
}
// { dg-options -std=c++1z }
template <class T> struct A
{
template <auto v> struct Y;
template <auto* p> struct Y<p> { using type1 = decltype (p); };
template <auto** pp> struct Y<pp> { using type2 = decltype (pp); };
};
int i;
int *p;
A<void>::Y<&i>::type1 t1;
A<void>::Y<&p>::type2 t2;
// { dg-do compile { target c++11 } }
template <int N> struct A;
template <typename T, T N> int foo(A<N> *) = delete;
void foo(void *);
void bar(A<0> *p) {
foo(p); // { dg-error "" "" { target c++1z } }
}
...@@ -14,7 +14,7 @@ template<typename T, typename T::foo V> ...@@ -14,7 +14,7 @@ template<typename T, typename T::foo V>
struct Y { }; struct Y { };
template<typename T, typename U, U v> template<typename T, typename U, U v>
struct Y<T, v> { }; // { dg-error "not deducible|U" } struct Y<T, v> { }; // { dg-error "not deducible|U" "" { target { ! c++1z } } }
template<typename T, T V> template<typename T, T V>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment