c++ modules: partial variable template specializations [PR106826]
With partial variable template specializations, it looks like we
stream the VAR_DECL (i.e. the DECL_TEMPLATE_RESULT of the corresponding
TEMPLATE_DECL) since process_partial_specialization adds it to the
specializations table, but we end up never streaming the corresponding
TEMPLATE_DECL itself that's reachable only from the primary template's
DECL_TEMPLATE_SPECIALIZATIONS list, which leads to this list being
incomplete on stream-in.
The modules machinery already has special logic for streaming partial
specializations of class templates; this patch attempts to generalize
it to handle those of variable templates as well.
PR c++/106826
gcc/cp/ChangeLog:
* module.cc (trees_out::decl_value): Use get_template_info in
the MK_partial case to handle both VAR_DECL and TYPE_DECL.
(trees_out::key_mergeable): Likewise.
(trees_in::key_mergeable): Likewise.
(has_definition): Consider DECL_INITIAL of a partial variable
template specialization.
(depset:#️⃣:make_dependency): Handle partial variable template
specializations too.
gcc/testsuite/ChangeLog:
* g++.dg/modules/partial-2_a.C: New test.
* g++.dg/modules/partial-2_b.C: New test.
This commit is contained in:
parent
26607a63da
commit
32d8123cd6
3 changed files with 82 additions and 14 deletions
|
@ -7789,8 +7789,9 @@ trees_out::decl_value (tree decl, depset *dep)
|
|||
}
|
||||
else
|
||||
{
|
||||
tree_node (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (inner)));
|
||||
tree_node (CLASSTYPE_TI_ARGS (TREE_TYPE (inner)));
|
||||
tree ti = get_template_info (inner);
|
||||
tree_node (TI_TEMPLATE (ti));
|
||||
tree_node (TI_ARGS (ti));
|
||||
}
|
||||
}
|
||||
tree_node (get_constraints (decl));
|
||||
|
@ -10625,9 +10626,10 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
|
|||
|
||||
case MK_partial:
|
||||
{
|
||||
tree ti = get_template_info (inner);
|
||||
key.constraints = get_constraints (inner);
|
||||
key.ret = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (inner));
|
||||
key.args = CLASSTYPE_TI_ARGS (TREE_TYPE (inner));
|
||||
key.ret = TI_TEMPLATE (ti);
|
||||
key.args = TI_ARGS (ti);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -10866,8 +10868,8 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
|
|||
spec; spec = TREE_CHAIN (spec))
|
||||
{
|
||||
tree tmpl = TREE_VALUE (spec);
|
||||
if (template_args_equal (key.args,
|
||||
CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)))
|
||||
tree ti = get_template_info (tmpl);
|
||||
if (template_args_equal (key.args, TI_ARGS (ti))
|
||||
&& cp_tree_equal (key.constraints,
|
||||
get_constraints
|
||||
(DECL_TEMPLATE_RESULT (tmpl))))
|
||||
|
@ -11381,8 +11383,7 @@ has_definition (tree decl)
|
|||
|
||||
case VAR_DECL:
|
||||
if (DECL_LANG_SPECIFIC (decl)
|
||||
&& DECL_TEMPLATE_INFO (decl)
|
||||
&& DECL_USE_TEMPLATE (decl) < 2)
|
||||
&& DECL_TEMPLATE_INFO (decl))
|
||||
return DECL_INITIAL (decl);
|
||||
else
|
||||
{
|
||||
|
@ -12498,11 +12499,14 @@ depset::hash::make_dependency (tree decl, entity_kind ek)
|
|||
|
||||
if (!dep)
|
||||
{
|
||||
if (DECL_IMPLICIT_TYPEDEF_P (decl)
|
||||
/* ... not an enum, for instance. */
|
||||
&& RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
|
||||
&& TYPE_LANG_SPECIFIC (TREE_TYPE (decl))
|
||||
&& CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)) == 2)
|
||||
if ((DECL_IMPLICIT_TYPEDEF_P (decl)
|
||||
/* ... not an enum, for instance. */
|
||||
&& RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
|
||||
&& TYPE_LANG_SPECIFIC (TREE_TYPE (decl))
|
||||
&& CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl)) == 2)
|
||||
|| (VAR_P (decl)
|
||||
&& DECL_LANG_SPECIFIC (decl)
|
||||
&& DECL_USE_TEMPLATE (decl) == 2))
|
||||
{
|
||||
/* A partial or explicit specialization. Partial
|
||||
specializations might not be in the hash table, because
|
||||
|
@ -12515,7 +12519,7 @@ depset::hash::make_dependency (tree decl, entity_kind ek)
|
|||
dep_hash, and then convert the dep we just found into a
|
||||
redirect. */
|
||||
|
||||
tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (decl));
|
||||
tree ti = get_template_info (decl);
|
||||
tree tmpl = TI_TEMPLATE (ti);
|
||||
tree partial = NULL_TREE;
|
||||
for (tree spec = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
|
||||
|
|
43
gcc/testsuite/g++.dg/modules/partial-2_a.C
Normal file
43
gcc/testsuite/g++.dg/modules/partial-2_a.C
Normal file
|
@ -0,0 +1,43 @@
|
|||
// PR c++/106826
|
||||
// { dg-additional-options -fmodules-ts }
|
||||
// { dg-module-cmi pr106826 }
|
||||
export module pr106826;
|
||||
|
||||
template<class T> constexpr bool is_reference_v = false;
|
||||
template<class T> constexpr bool is_reference_v<T&> = true;
|
||||
template<class T> constexpr bool is_reference_v<T&&> = true;
|
||||
|
||||
struct A {
|
||||
template<class T> static constexpr bool is_reference_v = false;
|
||||
};
|
||||
|
||||
template<class T> constexpr bool A::is_reference_v<T&> = true;
|
||||
template<class T> constexpr bool A::is_reference_v<T&&> = true;
|
||||
|
||||
#if __cpp_concepts
|
||||
namespace concepts {
|
||||
template<class T> bool is_reference_v;
|
||||
|
||||
template<class T> requires __is_same(T, T&)
|
||||
constexpr bool is_reference_v<T> = true;
|
||||
|
||||
template<class T> requires __is_same(T, T&&) && (!__is_same(T, T&))
|
||||
constexpr bool is_reference_v<T> = true;
|
||||
|
||||
template<class T> requires (!__is_same(T, T&)) && (!__is_same(T, T&&))
|
||||
constexpr bool is_reference_v<T> = false;
|
||||
|
||||
struct A {
|
||||
template<class T> static bool is_reference_v;
|
||||
};
|
||||
|
||||
template<class T> requires __is_same(T, T&)
|
||||
constexpr bool A::is_reference_v<T> = true;
|
||||
|
||||
template<class T> requires __is_same(T, T&&) && (!__is_same(T, T&))
|
||||
constexpr bool A::is_reference_v<T> = true;
|
||||
|
||||
template<class T> requires (!__is_same(T, T&)) && (!__is_same(T, T&&))
|
||||
constexpr bool A::is_reference_v<T> = false;
|
||||
}
|
||||
#endif
|
21
gcc/testsuite/g++.dg/modules/partial-2_b.C
Normal file
21
gcc/testsuite/g++.dg/modules/partial-2_b.C
Normal file
|
@ -0,0 +1,21 @@
|
|||
// PR c++/106826
|
||||
// { dg-additional-options -fmodules-ts }
|
||||
module pr106826;
|
||||
|
||||
static_assert(is_reference_v<int&>);
|
||||
static_assert(is_reference_v<int&&>);
|
||||
static_assert(!is_reference_v<int>);
|
||||
|
||||
static_assert(A::is_reference_v<long&>);
|
||||
static_assert(A::is_reference_v<long&&>);
|
||||
static_assert(!A::is_reference_v<long>);
|
||||
|
||||
#if __cpp_concepts
|
||||
static_assert(concepts::is_reference_v<char&>);
|
||||
static_assert(concepts::is_reference_v<char&&>);
|
||||
static_assert(!concepts::is_reference_v<char>);
|
||||
|
||||
static_assert(concepts::A::is_reference_v<bool&>);
|
||||
static_assert(concepts::A::is_reference_v<bool&&>);
|
||||
static_assert(!concepts::A::is_reference_v<bool>);
|
||||
#endif
|
Loading…
Add table
Reference in a new issue