Re: [PATCH] c++: unnecessary instantiation of constexpr var [PR99130]
On 9/7/22 16:40, Patrick Palka wrote: On Wed, 7 Sep 2022, Jason Merrill wrote: On 9/7/22 15:41, Patrick Palka wrote: Here the use of the constexpr member/variable specialization 'value' from within an unevaluated context causes us to overeagerly instantiate it, via maybe_instantiate_decl called from mark_used, despite only its declaration not its definition being needed. If the issue is with unevaluated context, maybe maybe_instantiate_decl should guard the call to decl_maybe_constant_var_p with !cp_unevaluated_operand? Hmm, that seems to work too. But IIUC this would mean in an evaluated (but non-constexpr) context we'd continue to instantiate constexpr variables _immediately_ rather than ideally allowing mark_used to postpone their instantiation until the end of TU processing (which is what happens with the below approach). Another benefit of the below approach is that from within a template definition we we now avoid instantiation altogether e.g. for template constexpr int value = /* blah */; template int f() { return value; } we no longer instantiate value which IIUC is consistent with how we handle other kinds of specializations used within a template definition. So making mark_used no longer instantiate constexpr variables immediately (in both evaluated and unevaluated contexts) seems to yield the most benefits. Makes sense. The patch is OK. We used to have the same issue for constexpr function specializations until r6-1309-g81371eff9bc7ef made us delay their instantiation until necessary during constexpr evaluation. So this patch makes us avoid unnecessarily instantiating constexpr variable template specializations from mark_used as well. To that end this patch pulls out the test in maybe_instantiate_decl (decl_maybe_constant_var_p (decl) || (TREE_CODE (decl) == FUNCTION_DECL && DECL_OMP_DECLARE_REDUCTION_P (decl)) || undeduced_auto_decl (decl)) into each of its three callers (including mark_used) and refines the test appropriately. The net result is that only mark_used is changed, because the other two callers, resolve_address_of_overloaded_function and decl_constant_var_p, already guard the call appropriately. And presumably decl_constant_var_p will take care of instantiation when needed for e.g. constexpr evaluation. Bootstrapped and regteste on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/99130 gcc/cp/ChangeLog: * decl2.cc (maybe_instantiate_decl): Adjust function comment. >>> Check VAR_OR_FUNCTION_DECL_P. Pull out the disjunction into ... (mark_used): ... here, removing the decl_maybe_constant_var_p part of it. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/var-templ70.C: New test. --- gcc/cp/decl2.cc | 33 gcc/testsuite/g++.dg/cpp1y/var-templ70.C | 19 ++ 2 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ70.C diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 89ab2545d64..cd188813bee 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5381,24 +5381,15 @@ possibly_inlined_p (tree decl) return true; } -/* Normally, we can wait until instantiation-time to synthesize DECL. - However, if DECL is a static data member initialized with a constant - or a constexpr function, we need it right now because a reference to - such a data member or a call to such function is not value-dependent. - For a function that uses auto in the return type, we need to instantiate - it to find out its type. For OpenMP user defined reductions, we need - them instantiated for reduction clauses which inline them by hand - directly. */ +/* If DECL is a function or variable template specialization, instantiate + its definition now. */ void maybe_instantiate_decl (tree decl) { - if (DECL_LANG_SPECIFIC (decl) + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) - && (decl_maybe_constant_var_p (decl) - || (TREE_CODE (decl) == FUNCTION_DECL - && DECL_OMP_DECLARE_REDUCTION_P (decl)) - || undeduced_auto_decl (decl)) && !DECL_DECLARED_CONCEPT_P (decl) && !uses_template_parms (DECL_TI_ARGS (decl))) { @@ -5700,15 +5691,13 @@ mark_used (tree decl, tsubst_flags_t complain) return false; } - /* Normally, we can wait until instantiation-time to synthesize DECL. - However, if DECL is a static data member initialized with a constant - or a constexpr function, we need it right now because a reference to - such a data member or a call to such function is not value-dependent. - For a function that uses auto in the return type, we need to instantiate - it to find out its type. For OpenMP user defined reductions, we need - them instantiated for reduction clauses which inline them by hand - directly.
Re: [PATCH] c++: unnecessary instantiation of constexpr var [PR99130]
On Wed, 7 Sep 2022, Jason Merrill wrote: > On 9/7/22 15:41, Patrick Palka wrote: > > Here the use of the constexpr member/variable specialization 'value' > > from within an unevaluated context causes us to overeagerly instantiate > > it, via maybe_instantiate_decl called from mark_used, despite only its > > declaration not its definition being needed. > > If the issue is with unevaluated context, maybe maybe_instantiate_decl should > guard the call to decl_maybe_constant_var_p with !cp_unevaluated_operand? Hmm, that seems to work too. But IIUC this would mean in an evaluated (but non-constexpr) context we'd continue to instantiate constexpr variables _immediately_ rather than ideally allowing mark_used to postpone their instantiation until the end of TU processing (which is what happens with the below approach). Another benefit of the below approach is that from within a template definition we we now avoid instantiation altogether e.g. for template constexpr int value = /* blah */; template int f() { return value; } we no longer instantiate value which IIUC is consistent with how we handle other kinds of specializations used within a template definition. So making mark_used no longer instantiate constexpr variables immediately (in both evaluated and unevaluated contexts) seems to yield the most benefits. > > > We used to have the same issue for constexpr function specializations > > until r6-1309-g81371eff9bc7ef made us delay their instantiation until > > necessary during constexpr evaluation. > > > > So this patch makes us avoid unnecessarily instantiating constexpr > > variable template specializations from mark_used as well. To that end > > this patch pulls out the test in maybe_instantiate_decl > > > >(decl_maybe_constant_var_p (decl) > > || (TREE_CODE (decl) == FUNCTION_DECL > > && DECL_OMP_DECLARE_REDUCTION_P (decl)) > > || undeduced_auto_decl (decl)) > > > > into each of its three callers (including mark_used) and refines the > > test appropriately. The net result is that only mark_used is changed, > > because the other two callers, resolve_address_of_overloaded_function > > and decl_constant_var_p, already guard the call appropriately. And > > presumably decl_constant_var_p will take care of instantiation when > > needed for e.g. constexpr evaluation. > > > > Bootstrapped and regteste on x86_64-pc-linux-gnu, does this look OK for > > trunk? > > > > PR c++/99130 > > > > gcc/cp/ChangeLog: > > > > * decl2.cc (maybe_instantiate_decl): Adjust function comment. > > Check VAR_OR_FUNCTION_DECL_P. Pull out the disjunction into ... > > (mark_used): ... here, removing the decl_maybe_constant_var_p > > part of it. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp1y/var-templ70.C: New test. > > --- > > gcc/cp/decl2.cc | 33 > > gcc/testsuite/g++.dg/cpp1y/var-templ70.C | 19 ++ > > 2 files changed, 30 insertions(+), 22 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ70.C > > > > diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc > > index 89ab2545d64..cd188813bee 100644 > > --- a/gcc/cp/decl2.cc > > +++ b/gcc/cp/decl2.cc > > @@ -5381,24 +5381,15 @@ possibly_inlined_p (tree decl) > > return true; > > } > > -/* Normally, we can wait until instantiation-time to synthesize DECL. > > - However, if DECL is a static data member initialized with a constant > > - or a constexpr function, we need it right now because a reference to > > - such a data member or a call to such function is not value-dependent. > > - For a function that uses auto in the return type, we need to instantiate > > - it to find out its type. For OpenMP user defined reductions, we need > > - them instantiated for reduction clauses which inline them by hand > > - directly. */ > > +/* If DECL is a function or variable template specialization, instantiate > > + its definition now. */ > > void > > maybe_instantiate_decl (tree decl) > > { > > - if (DECL_LANG_SPECIFIC (decl) > > + if (VAR_OR_FUNCTION_DECL_P (decl) > > + && DECL_LANG_SPECIFIC (decl) > > && DECL_TEMPLATE_INFO (decl) > > - && (decl_maybe_constant_var_p (decl) > > - || (TREE_CODE (decl) == FUNCTION_DECL > > - && DECL_OMP_DECLARE_REDUCTION_P (decl)) > > - || undeduced_auto_decl (decl)) > > && !DECL_DECLARED_CONCEPT_P (decl) > > && !uses_template_parms (DECL_TI_ARGS (decl))) > > { > > @@ -5700,15 +5691,13 @@ mark_used (tree decl, tsubst_flags_t complain) > > return false; > > } > > - /* Normally, we can wait until instantiation-time to synthesize DECL. > > - However, if DECL is a static data member initialized with a constant > > - or a constexpr function, we need it right now because a reference to > > - such a data member or a call to such function is not value-dependent. > > - For a function that uses auto
Re: [PATCH] c++: unnecessary instantiation of constexpr var [PR99130]
On 9/7/22 15:41, Patrick Palka wrote: Here the use of the constexpr member/variable specialization 'value' from within an unevaluated context causes us to overeagerly instantiate it, via maybe_instantiate_decl called from mark_used, despite only its declaration not its definition being needed. If the issue is with unevaluated context, maybe maybe_instantiate_decl should guard the call to decl_maybe_constant_var_p with !cp_unevaluated_operand? We used to have the same issue for constexpr function specializations until r6-1309-g81371eff9bc7ef made us delay their instantiation until necessary during constexpr evaluation. So this patch makes us avoid unnecessarily instantiating constexpr variable template specializations from mark_used as well. To that end this patch pulls out the test in maybe_instantiate_decl (decl_maybe_constant_var_p (decl) || (TREE_CODE (decl) == FUNCTION_DECL && DECL_OMP_DECLARE_REDUCTION_P (decl)) || undeduced_auto_decl (decl)) into each of its three callers (including mark_used) and refines the test appropriately. The net result is that only mark_used is changed, because the other two callers, resolve_address_of_overloaded_function and decl_constant_var_p, already guard the call appropriately. And presumably decl_constant_var_p will take care of instantiation when needed for e.g. constexpr evaluation. Bootstrapped and regteste on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/99130 gcc/cp/ChangeLog: * decl2.cc (maybe_instantiate_decl): Adjust function comment. Check VAR_OR_FUNCTION_DECL_P. Pull out the disjunction into ... (mark_used): ... here, removing the decl_maybe_constant_var_p part of it. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/var-templ70.C: New test. --- gcc/cp/decl2.cc | 33 gcc/testsuite/g++.dg/cpp1y/var-templ70.C | 19 ++ 2 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ70.C diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 89ab2545d64..cd188813bee 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5381,24 +5381,15 @@ possibly_inlined_p (tree decl) return true; } -/* Normally, we can wait until instantiation-time to synthesize DECL. - However, if DECL is a static data member initialized with a constant - or a constexpr function, we need it right now because a reference to - such a data member or a call to such function is not value-dependent. - For a function that uses auto in the return type, we need to instantiate - it to find out its type. For OpenMP user defined reductions, we need - them instantiated for reduction clauses which inline them by hand - directly. */ +/* If DECL is a function or variable template specialization, instantiate + its definition now. */ void maybe_instantiate_decl (tree decl) { - if (DECL_LANG_SPECIFIC (decl) + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) - && (decl_maybe_constant_var_p (decl) - || (TREE_CODE (decl) == FUNCTION_DECL - && DECL_OMP_DECLARE_REDUCTION_P (decl)) - || undeduced_auto_decl (decl)) && !DECL_DECLARED_CONCEPT_P (decl) && !uses_template_parms (DECL_TI_ARGS (decl))) { @@ -5700,15 +5691,13 @@ mark_used (tree decl, tsubst_flags_t complain) return false; } - /* Normally, we can wait until instantiation-time to synthesize DECL. - However, if DECL is a static data member initialized with a constant - or a constexpr function, we need it right now because a reference to - such a data member or a call to such function is not value-dependent. - For a function that uses auto in the return type, we need to instantiate - it to find out its type. For OpenMP user defined reductions, we need - them instantiated for reduction clauses which inline them by hand - directly. */ - maybe_instantiate_decl (decl); + /* If DECL has a deduced return type, we need to instantiate it now to + find out its type. For OpenMP user defined reductions, we need them + instantiated for reduction clauses which inline them by hand directly. */ + if (undeduced_auto_decl (decl) + || (TREE_CODE (decl) == FUNCTION_DECL + && DECL_OMP_DECLARE_REDUCTION_P (decl))) +maybe_instantiate_decl (decl); if (processing_template_decl || in_template_function ()) return true; diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ70.C b/gcc/testsuite/g++.dg/cpp1y/var-templ70.C new file mode 100644 index 000..80965657c32 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ70.C @@ -0,0 +1,19 @@ +// PR c++/99130 +// { dg-do compile { target c++14 } } + +template +struct A { + static constexpr int value = T::value; +}; + +struct B { + template + static constexpr int value = T::value; +}; + +template