aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2021-02-12 12:21:15 -0500
committerMarek Polacek <polacek@redhat.com>2021-03-03 09:52:37 -0500
commit1dabbfb0f4a9fbdc77e1ea4db7302586f00895e1 (patch)
tree98f220954fdc781fea26a10059280c9dfe9382bd /gcc/cp
parent15cf7fe3556d11aa895cee0f162f6678da9daca6 (diff)
downloadgcc-1dabbfb0f4a9fbdc77e1ea4db7302586f00895e1.zip
gcc-1dabbfb0f4a9fbdc77e1ea4db7302586f00895e1.tar.gz
gcc-1dabbfb0f4a9fbdc77e1ea4db7302586f00895e1.tar.bz2
c++: ICE with deduction guide in checking type-dep [PR99009, PR97034]
We represent deduction guides with FUNCTION_DECLs, but they are built without DECL_CONTEXT, leading to an ICE in type_dependent_expression_p on the assert that the type of a function template with no dependent (innermost!) template arguments must be non-dependent. Consider the attached class-deduction79.C: we create a deduction guide: template<class T> G(T)-> E<Z>::G<T> we deduce T and create a partial instantiation: G(T) -> E<Z>::G<T> [with T = int] And then do_class_deduction wants to create a CALL_EXPR from the above using build_new_function_call -> build_over_call which calls mark_used -> maybe_instantiate_noexcept -> type_dependent_expression_p. There, the innermost template arguments are non-dependent (<int>), but the fntype is dependent -- the return type is a TYPENAME_TYPE, and since we have no DECL_CONTEXT, this check holds: /* Otherwise, if the function decl isn't from a dependent scope, it can't be type-dependent. Checking this is important for functions with auto return type, which looks like a dependent type. */ if (TREE_CODE (expression) == FUNCTION_DECL && !(DECL_CLASS_SCOPE_P (expression) && dependent_type_p (DECL_CONTEXT (expression))) whereupon we ICE. This patch fixes it by deferring the class deduction until the enclosing scope is non-dependent. build_deduction_guide and maybe_aggr_guide needed a little tweaking to make the deduction work in a member template. Co-Authored-By: Jason Merrill <jason@redhat.com> gcc/cp/ChangeLog: PR c++/97034 PR c++/99009 * pt.c (build_deduction_guide): Use INNERMOST_TEMPLATE_ARGS. (maybe_aggr_guide): Use the original template type where needed. In a class member template, partially instantiate the result of collect_ctor_idx_types. (do_class_deduction): Defer the deduction until the enclosing scope is non-dependent. gcc/testsuite/ChangeLog: PR c++/97034 PR c++/99009 * g++.dg/cpp1z/class-deduction81.C: New test. * g++.dg/cpp1z/class-deduction82.C: New test. * g++.dg/cpp2a/class-deduction-aggr8.C: New test. * g++.dg/cpp2a/class-deduction-aggr9.C: New test. * g++.dg/cpp2a/class-deduction-aggr10.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/pt.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8d65a6e..a4686e0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -28643,7 +28643,7 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com
tree ctmpl = CLASSTYPE_TI_TEMPLATE (type);
tparms = DECL_TEMPLATE_PARMS (ctmpl);
- targs = CLASSTYPE_TI_ARGS (type);
+ targs = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type));
ci = NULL_TREE;
fargs = NULL_TREE;
loc = DECL_SOURCE_LOCATION (ctmpl);
@@ -28866,8 +28866,22 @@ maybe_aggr_guide (tree tmpl, tree init, vec<tree,va_gc> *args)
if (init == NULL_TREE)
return NULL_TREE;
+ /* We might be creating a guide for a class member template, e.g.,
+
+ template<typename U> struct A {
+ template<typename T> struct B { T t; };
+ };
+
+ At this point, A will have been instantiated. Below, we need to
+ use both A<U>::B<T> (TEMPLATE_TYPE) and A<int>::B<T> (TYPE) types. */
+ const bool member_template_p
+ = (DECL_TEMPLATE_INFO (tmpl)
+ && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (tmpl)));
tree type = TREE_TYPE (tmpl);
- if (!CP_AGGREGATE_TYPE_P (type))
+ tree template_type = (member_template_p
+ ? TREE_TYPE (DECL_TI_TEMPLATE (tmpl))
+ : type);
+ if (!CP_AGGREGATE_TYPE_P (template_type))
return NULL_TREE;
/* No aggregate candidate for copy-initialization. */
@@ -28884,10 +28898,21 @@ maybe_aggr_guide (tree tmpl, tree init, vec<tree,va_gc> *args)
tree parms = NULL_TREE;
if (BRACE_ENCLOSED_INITIALIZER_P (init))
{
- init = reshape_init (type, init, complain);
+ init = reshape_init (template_type, init, complain);
if (init == error_mark_node)
return NULL_TREE;
parms = collect_ctor_idx_types (init, parms);
+ /* If we're creating a deduction guide for a member class template,
+ we've used the original template pattern type for the reshape_init
+ above; this is done because we want PARMS to be a template parameter
+ type, something that can be deduced when used as a function template
+ parameter. At this point the outer class template has already been
+ partially instantiated (we deferred the deduction until the enclosing
+ scope is non-dependent). Therefore we have to partially instantiate
+ PARMS, so that its template level is properly reduced and we don't get
+ mismatches when deducing types using the guide with PARMS. */
+ if (member_template_p)
+ parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
}
else if (TREE_CODE (init) == TREE_LIST)
{
@@ -29225,6 +29250,11 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
return ptype;
+ /* Wait until the enclosing scope is non-dependent. */
+ if (DECL_CLASS_SCOPE_P (tmpl)
+ && dependent_type_p (DECL_CONTEXT (tmpl)))
+ return ptype;
+
/* Initializing one placeholder from another. */
if (init && TREE_CODE (init) == TEMPLATE_PARM_INDEX
&& is_auto (TREE_TYPE (init))