This makes tsubst_arg_types substitute into a function's parameter types in left-to-right order instead of right-to-left order, in accordance with DR 1227.
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? [ diff generated with -w to hide noisy whitespace changes ] gcc/cp/ChangeLog: DR 1227 PR c++/96560 * pt.c (tsubst_arg_types): Rearrange so that we substitute into TYPE_ARG_TYPES in forward order while short circuiting appropriately. gcc/testsuite/ChangeLog: DR 1227 PR c++/96560 * g++.dg/template/sfinae-dr1227.C: New test. --- gcc/cp/pt.c | 40 +++++++++++-------- gcc/testsuite/g++.dg/template/sfinae-dr1227.C | 23 +++++++++++ 2 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/sfinae-dr1227.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index eaf46659f85..d79fecd4949 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15068,20 +15068,14 @@ 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 @@ -15092,7 +15086,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 @@ -15101,14 +15095,15 @@ 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); - else if (!type) - type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl); if (type == error_mark_node) return error_mark_node; @@ -15122,6 +15117,17 @@ tsubst_arg_types (tree arg_types, } return error_mark_node; } + } + + 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; + + 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. */ @@ -15145,14 +15151,14 @@ tsubst_arg_types (tree arg_types, 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); + 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); + 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 00000000000..6d57d59dae7 --- /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" } error -- 2.31.1.362.g311531c9de