aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2021-06-11 16:00:52 -0400
committerPatrick Palka <ppalka@redhat.com>2021-06-11 16:00:52 -0400
commitb0d73a66ae3962fa83309527d85613d72a6aa43d (patch)
treee0413db10b88d4d2e525bfa2960dfd6c819a99c9 /gcc
parent1e690757d30775ed340a368b9a9463b2ad68de01 (diff)
downloadgcc-b0d73a66ae3962fa83309527d85613d72a6aa43d.zip
gcc-b0d73a66ae3962fa83309527d85613d72a6aa43d.tar.gz
gcc-b0d73a66ae3962fa83309527d85613d72a6aa43d.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.c115
-rw-r--r--gcc/testsuite/g++.dg/template/sfinae-dr1227.C23
2 files changed, 83 insertions, 55 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b53df9e..141388a 100644
--- a/gcc/cp/pt.c
+++ b/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;
-
- if (expanded_args)
- type = TREE_VEC_ELT (expanded_args, i);
- else if (!type)
- type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
+ /* 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 (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;
}
diff --git a/gcc/testsuite/g++.dg/template/sfinae-dr1227.C b/gcc/testsuite/g++.dg/template/sfinae-dr1227.C
new file mode 100644
index 0000000..821ff03
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sfinae-dr1227.C
@@ -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