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.
This commit is contained in:
parent
15cf7fe355
commit
1dabbfb0f4
36
gcc/cp/pt.c
36
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))
|
||||
|
||||
20
gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
Normal file
20
gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
Normal file
@ -0,0 +1,20 @@
|
||||
// PR c++/97034
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
template <typename Z>
|
||||
struct E {
|
||||
template <typename T>
|
||||
struct G {
|
||||
T t;
|
||||
G(T) { }
|
||||
};
|
||||
|
||||
void fn() { G{1}; }
|
||||
};
|
||||
|
||||
void
|
||||
g ()
|
||||
{
|
||||
E<int> e;
|
||||
e.fn ();
|
||||
}
|
||||
12
gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
Normal file
12
gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
Normal file
@ -0,0 +1,12 @@
|
||||
// PR c++/99009
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
template<typename> struct B {
|
||||
B(int = A()) {}
|
||||
template <typename ...> struct A;
|
||||
};
|
||||
|
||||
template<typename T> struct X {
|
||||
template <T...> struct Y;
|
||||
X() { Y y; };
|
||||
};
|
||||
21
gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
Normal file
21
gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
Normal file
@ -0,0 +1,21 @@
|
||||
// PR c++/97034
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
namespace N {
|
||||
template <typename, typename> struct S {
|
||||
template <typename T, typename U> S(T, U);
|
||||
};
|
||||
} // namespace N
|
||||
template <int I> struct E {
|
||||
template<typename U> struct M {
|
||||
template <typename T> struct G { T t; };
|
||||
void fn() { G{N::S<char, int>{'a', 1}}; }
|
||||
};
|
||||
};
|
||||
|
||||
void
|
||||
g ()
|
||||
{
|
||||
E<1>::M<int> m;
|
||||
m.fn ();
|
||||
}
|
||||
19
gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
Normal file
19
gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
Normal file
@ -0,0 +1,19 @@
|
||||
// PR c++/97034
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
namespace N {
|
||||
template <typename, typename> struct S {
|
||||
template <typename T, typename U> S(T, U);
|
||||
};
|
||||
} // namespace N
|
||||
template <int> struct E {
|
||||
template <typename T> struct G { T t; };
|
||||
void fn() { G{N::S<char, int>{'a', 1}}; }
|
||||
};
|
||||
|
||||
void
|
||||
g ()
|
||||
{
|
||||
E<1> e;
|
||||
e.fn ();
|
||||
}
|
||||
18
gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
Normal file
18
gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
Normal file
@ -0,0 +1,18 @@
|
||||
// PR c++/97034
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
template<typename>
|
||||
struct E {
|
||||
template <typename T>
|
||||
struct G {
|
||||
T t;
|
||||
};
|
||||
|
||||
void fn() { G{1}; }
|
||||
};
|
||||
|
||||
void
|
||||
g () {
|
||||
E<int> e;
|
||||
e.fn ();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user