Message ID | 20220921161629.1738016-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++ modules: partial variable template specializations [PR106826] | expand |
On 9/21/22 12:16, Patrick Palka wrote: > 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 end up never streaming the corresponding > TEMPLATE_DECL itself that appears only in the primary template's > DECL_TEMPLATE_SPECIALIZATIONS list, which leads to the list being > incomplete on stream-in. > > The modules machinery already has special logic for streaming partial > specializations of class templates; this patch generalizes it to handle > those of variable templates as well. looks good, I didn't realize template vars had partial specializations. > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk? > > PR c++/106826 > > gcc/cp/ChangeLog: > > * module.cc (trees_out::decl_value): Use get_template_info in > the MK_partial case. > (trees_out::key_mergeable): Likewise. > (trees_in::key_mergeable): Likewise. > (has_definition): Consider DECL_INITIAL of a partial variable > template specialization. > (depset::hash::make_dependency): Introduce a dependency of > 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. > --- > gcc/cp/module.cc | 32 +++++++++------- > gcc/testsuite/g++.dg/modules/partial-2_a.C | 43 ++++++++++++++++++++++ > gcc/testsuite/g++.dg/modules/partial-2_b.C | 21 +++++++++++ > 3 files changed, 82 insertions(+), 14 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/modules/partial-2_a.C > create mode 100644 gcc/testsuite/g++.dg/modules/partial-2_b.C > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > index 9a9ef4e3332..334bde99b0f 100644 > --- a/gcc/cp/module.cc > +++ b/gcc/cp/module.cc > @@ -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)); > @@ -10626,8 +10627,9 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, > case MK_partial: > { > key.constraints = get_constraints (inner); > - key.ret = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (inner)); > - key.args = CLASSTYPE_TI_ARGS (TREE_TYPE (inner)); > + tree ti = get_template_info (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); > diff --git a/gcc/testsuite/g++.dg/modules/partial-2_a.C b/gcc/testsuite/g++.dg/modules/partial-2_a.C > new file mode 100644 > index 00000000000..2681bb59ce8 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/partial-2_a.C > @@ -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 > diff --git a/gcc/testsuite/g++.dg/modules/partial-2_b.C b/gcc/testsuite/g++.dg/modules/partial-2_b.C > new file mode 100644 > index 00000000000..0af41ef5e5e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/partial-2_b.C > @@ -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
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 9a9ef4e3332..334bde99b0f 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -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)); @@ -10626,8 +10627,9 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, case MK_partial: { key.constraints = get_constraints (inner); - key.ret = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (inner)); - key.args = CLASSTYPE_TI_ARGS (TREE_TYPE (inner)); + tree ti = get_template_info (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); diff --git a/gcc/testsuite/g++.dg/modules/partial-2_a.C b/gcc/testsuite/g++.dg/modules/partial-2_a.C new file mode 100644 index 00000000000..2681bb59ce8 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2_a.C @@ -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 diff --git a/gcc/testsuite/g++.dg/modules/partial-2_b.C b/gcc/testsuite/g++.dg/modules/partial-2_b.C new file mode 100644 index 00000000000..0af41ef5e5e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-2_b.C @@ -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