c++: Substitute into function parms in lexical order [PR96560]
This makes tsubst_arg_types substitute into a function's parameter types in left-to-right instead of right-to-left order, in accordance with DR 1227. DR 1227 PR c++/96560 gcc/cp/ChangeLog: * pt.c (tsubst_arg_types): Rearrange so that we substitute into TYPE_ARG_TYPES in forward order while short circuiting appropriately. Adjust formatting. gcc/testsuite/ChangeLog: * g++.dg/template/sfinae-dr1227.C: New test.
This commit is contained in:
parent
1e690757d3
commit
b0d73a66ae
2 changed files with 83 additions and 55 deletions
115
gcc/cp/pt.c
115
gcc/cp/pt.c
|
@ -14946,20 +14946,13 @@ tsubst_arg_types (tree arg_types,
|
|||
tsubst_flags_t complain,
|
||||
tree in_decl)
|
||||
{
|
||||
tree remaining_arg_types;
|
||||
tree type = NULL_TREE;
|
||||
int i = 1;
|
||||
int len = 1;
|
||||
tree expanded_args = NULL_TREE;
|
||||
tree default_arg;
|
||||
|
||||
if (!arg_types || arg_types == void_list_node || arg_types == end)
|
||||
return arg_types;
|
||||
|
||||
remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types),
|
||||
args, end, complain, in_decl);
|
||||
if (remaining_arg_types == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (PACK_EXPANSION_P (TREE_VALUE (arg_types)))
|
||||
{
|
||||
/* For a pack expansion, perform substitution on the
|
||||
|
@ -14970,7 +14963,7 @@ tsubst_arg_types (tree arg_types,
|
|||
|
||||
if (TREE_CODE (expanded_args) == TREE_VEC)
|
||||
/* So that we'll spin through the parameters, one by one. */
|
||||
i = TREE_VEC_LENGTH (expanded_args);
|
||||
len = TREE_VEC_LENGTH (expanded_args);
|
||||
else
|
||||
{
|
||||
/* We only partially substituted into the parameter
|
||||
|
@ -14979,59 +14972,71 @@ tsubst_arg_types (tree arg_types,
|
|||
expanded_args = NULL_TREE;
|
||||
}
|
||||
}
|
||||
else
|
||||
type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
|
||||
|
||||
while (i > 0) {
|
||||
--i;
|
||||
/* Check if a substituted type is erroneous before substituting into
|
||||
the rest of the chain. */
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (expanded_args)
|
||||
type = TREE_VEC_ELT (expanded_args, i);
|
||||
|
||||
if (expanded_args)
|
||||
type = TREE_VEC_ELT (expanded_args, i);
|
||||
else if (!type)
|
||||
type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
|
||||
|
||||
if (type == error_mark_node)
|
||||
return error_mark_node;
|
||||
if (VOID_TYPE_P (type))
|
||||
{
|
||||
if (complain & tf_error)
|
||||
{
|
||||
error ("invalid parameter type %qT", type);
|
||||
if (in_decl)
|
||||
error ("in declaration %q+D", in_decl);
|
||||
}
|
||||
return error_mark_node;
|
||||
if (type == error_mark_node)
|
||||
return error_mark_node;
|
||||
if (VOID_TYPE_P (type))
|
||||
{
|
||||
if (complain & tf_error)
|
||||
{
|
||||
error ("invalid parameter type %qT", type);
|
||||
if (in_decl)
|
||||
error ("in declaration %q+D", in_decl);
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do array-to-pointer, function-to-pointer conversion, and ignore
|
||||
top-level qualifiers as required. */
|
||||
type = cv_unqualified (type_decays_to (type));
|
||||
/* We do not substitute into default arguments here. The standard
|
||||
mandates that they be instantiated only when needed, which is
|
||||
done in build_over_call. */
|
||||
tree default_arg = TREE_PURPOSE (arg_types);
|
||||
|
||||
/* We do not substitute into default arguments here. The standard
|
||||
mandates that they be instantiated only when needed, which is
|
||||
done in build_over_call. */
|
||||
default_arg = TREE_PURPOSE (arg_types);
|
||||
/* Except that we do substitute default arguments under tsubst_lambda_expr,
|
||||
since the new op() won't have any associated template arguments for us
|
||||
to refer to later. */
|
||||
if (lambda_fn_in_template_p (in_decl))
|
||||
default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl,
|
||||
false/*fn*/, false/*constexpr*/);
|
||||
|
||||
/* Except that we do substitute default arguments under tsubst_lambda_expr,
|
||||
since the new op() won't have any associated template arguments for us
|
||||
to refer to later. */
|
||||
if (lambda_fn_in_template_p (in_decl))
|
||||
default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl,
|
||||
false/*fn*/, false/*constexpr*/);
|
||||
tree remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types),
|
||||
args, end, complain, in_decl);
|
||||
if (remaining_arg_types == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE)
|
||||
{
|
||||
/* We've instantiated a template before its default arguments
|
||||
have been parsed. This can happen for a nested template
|
||||
class, and is not an error unless we require the default
|
||||
argument in a call of this function. */
|
||||
remaining_arg_types =
|
||||
tree_cons (default_arg, type, remaining_arg_types);
|
||||
vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg),
|
||||
remaining_arg_types);
|
||||
}
|
||||
else
|
||||
remaining_arg_types =
|
||||
hash_tree_cons (default_arg, type, remaining_arg_types);
|
||||
}
|
||||
for (int i = len-1; i >= 0; i--)
|
||||
{
|
||||
if (expanded_args)
|
||||
type = TREE_VEC_ELT (expanded_args, i);
|
||||
|
||||
/* Do array-to-pointer, function-to-pointer conversion, and ignore
|
||||
top-level qualifiers as required. */
|
||||
type = cv_unqualified (type_decays_to (type));
|
||||
|
||||
if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE)
|
||||
{
|
||||
/* We've instantiated a template before its default arguments
|
||||
have been parsed. This can happen for a nested template
|
||||
class, and is not an error unless we require the default
|
||||
argument in a call of this function. */
|
||||
remaining_arg_types
|
||||
= tree_cons (default_arg, type, remaining_arg_types);
|
||||
vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg),
|
||||
remaining_arg_types);
|
||||
}
|
||||
else
|
||||
remaining_arg_types
|
||||
= hash_tree_cons (default_arg, type, remaining_arg_types);
|
||||
}
|
||||
|
||||
return remaining_arg_types;
|
||||
}
|
||||
|
|
23
gcc/testsuite/g++.dg/template/sfinae-dr1227.C
Normal file
23
gcc/testsuite/g++.dg/template/sfinae-dr1227.C
Normal file
|
@ -0,0 +1,23 @@
|
|||
// PR c++/96560
|
||||
// DR 1227
|
||||
// Test that we substitute function parameter types in lexical order.
|
||||
|
||||
template <class T>
|
||||
struct A { typedef typename T::type type; }; // { dg-error "void" }
|
||||
|
||||
template <class T> void f(typename T::type, typename A<T>::type);
|
||||
template <class T> long f(...);
|
||||
|
||||
long x = f<int>(0, 0); // { dg-bogus "" } OK
|
||||
|
||||
|
||||
template <class T> void g(T, typename A<T>::type);
|
||||
template <class T> long g(...);
|
||||
|
||||
long y = g<void>(0, 0); // { dg-bogus "" } OK
|
||||
|
||||
|
||||
template <class T> void h(typename A<T>::type, T);
|
||||
template <class T> long h(...);
|
||||
|
||||
long z = h<void>(0, 0); // { dg-message "required from here" } hard error
|
Loading…
Add table
Reference in a new issue