gcc/cp/
PR 64969
* cp-tree.h (tsubst_flags): Add tf_auto.
* pt.c (make_auto_1): Encode auto with a level of 0.
(tsubst): Change auto to its proper level. Ignore unless tf_auto.
(tsubst_pack_expansion): Add sanity check.
(reduce_template_parm_level): Ignore auto.
(listify_autos): Pass tf_auto.
(do_auto_deduction): Likewise.
(splice_late_return_type): Likewise.
gcc/testsuite/
PR 64969
* g++.dg/cpp1y/pr64969.C: New test.
@@ -4427,6 +4427,7 @@ enum tsubst_flags {
for calls in decltype (5.2.2/11). */
tf_partial = 1 << 8, /* Doing initial explicit argument
substitution in fn_type_unification. */
+ tf_auto = 1 << 9, /* Substitute auto. */
/* Convenient substitution flags combinations. */
tf_warning_or_error = tf_warning | tf_error
};
@@ -3699,8 +3699,10 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
DECL_ARTIFICIAL (decl) = 1;
SET_DECL_TEMPLATE_PARM_P (decl);
- t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
- TEMPLATE_PARM_LEVEL (index) - levels,
+ int level = TEMPLATE_PARM_LEVEL (index);
+ if (level)
+ level -= levels;
+ t = build_template_parm_index (TEMPLATE_PARM_IDX (index), level,
TEMPLATE_PARM_ORIG_LEVEL (index),
decl, type);
TEMPLATE_PARM_DESCENDANTS (index) = t;
@@ -10003,6 +10005,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
int idx;
template_parm_level_and_index (parm_pack, &level, &idx);
+ /* A pack can never be 'auto'. */
+ gcc_assert (level);
+
if (level <= levels)
arg_pack = TMPL_ARG (args, level, idx);
}
@@ -11968,8 +11973,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
gcc_assert (TREE_VEC_LENGTH (args) > 0);
template_parm_level_and_index (t, &level, &idx);
+ /* A level of zero represents 'auto'. If complain & tf_auto,
+ then the template arguments will contain a deduced or
+ specified type for auto at one level deeper than the current
+ template parameters. The value of processing_template_decl
+ is not meaningful here in other cases. */
+ if (complain & tf_auto && !level)
+ level = processing_template_decl + 1;
+
levels = TMPL_ARGS_DEPTH (args);
- if (level <= levels)
+ if (level && level <= levels)
{
arg = TMPL_ARG (args, level, idx);
@@ -22095,8 +22108,7 @@ make_args_non_dependent (vec<tree, va_gc> *args)
}
/* Returns a type which represents 'auto' or 'decltype(auto)'. We use a
- TEMPLATE_TYPE_PARM with a level one deeper than the actual template
- parms. */
+ TEMPLATE_TYPE_PARM with a level of 0. */
static tree
make_auto_1 (tree name)
@@ -22106,8 +22118,7 @@ make_auto_1 (tree name)
TYPE_DECL, name, au);
TYPE_STUB_DECL (au) = TYPE_NAME (au);
TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
- (0, processing_template_decl + 1, processing_template_decl + 1,
- TYPE_NAME (au), NULL_TREE);
+ (0, 0, 0, TYPE_NAME (au), NULL_TREE);
TYPE_CANONICAL (au) = canonical_type_parameter (au);
DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
SET_DECL_TEMPLATE_PARM_P (TYPE_NAME (au));
@@ -22157,7 +22168,7 @@ listify_autos (tree type, tree auto_node)
TREE_VEC_ELT (argvec, 0) = init_auto;
if (processing_template_decl)
argvec = add_to_template_args (current_template_args (), argvec);
- return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
+ return tsubst (type, argvec, tf_warning_or_error | tf_auto, NULL_TREE);
}
/* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
@@ -22264,7 +22275,7 @@ do_auto_deduction (tree type, tree init, tree auto_node)
if (processing_template_decl)
targs = add_to_template_args (current_template_args (), targs);
- return tsubst (type, targs, tf_warning_or_error, NULL_TREE);
+ return tsubst (type, targs, tf_warning_or_error | tf_auto, NULL_TREE);
}
/* Substitutes LATE_RETURN_TYPE for 'auto' in TYPE and returns the
@@ -22286,7 +22297,7 @@ splice_late_return_type (tree type, tree late_return_type)
(make_tree_vec (processing_template_parmlist), argvec);
if (current_template_parms)
argvec = add_to_template_args (current_template_args (), argvec);
- return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
+ return tsubst (type, argvec, tf_warning_or_error | tf_auto, NULL_TREE);
}
/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or
new file mode 100644
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+int f();
+
+auto t1(auto f)
+{ return f(); }
+
+decltype(auto) t2(auto f)
+{ return f(); }
+
+template <typename T>
+auto t3(auto f)
+{ return f(); }
+
+template <typename T>
+decltype(auto) t4(auto f)
+{ return f(); }
+
+int r1 = t1(f);
+int r2 = t2(f);
+int r3 = t3<void>(f) | t3<void, int()>(f);
+int r4 = t4<void>(f) | t4<void, int()>(f);