diff options
author | Marek Polacek <polacek@redhat.com> | 2021-02-12 12:21:15 -0500 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2021-03-03 09:52:37 -0500 |
commit | 1dabbfb0f4a9fbdc77e1ea4db7302586f00895e1 (patch) | |
tree | 98f220954fdc781fea26a10059280c9dfe9382bd /gcc/cp | |
parent | 15cf7fe3556d11aa895cee0f162f6678da9daca6 (diff) | |
download | gcc-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.c | 36 |
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)) |