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<class T> constexpr int value = /* blah */;

   template<class T>
   int f() { return value<int>; }

we no longer instantiate value<int> 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.  */
-  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 00000000000..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<class T>
+struct A {
+  static constexpr int value = T::value;
+};
+
+struct B {
+  template<class T>
+  static constexpr int value = T::value;
+};
+
+template<class T>
+constexpr int value = T::value;
+
+using ty1 = decltype(A<int>::value);
+using ty2 = decltype(B::value<int>);
+using ty3 = decltype(value<int>);




Reply via email to