On Tue, Jun 11, 2019 at 08:37:27AM -0400, Jason Merrill wrote:
> On 6/11/19 7:47 AM, Jakub Jelinek wrote:
> > On Mon, Jun 10, 2019 at 09:59:46PM -0400, Marek Polacek wrote:
> > > This test segvs since r269078, this hunk in particular:
> > > 
> > > @@ -4581,8 +4713,9 @@ cxx_eval_constant_expression (const constexpr_ctx 
> > > *ctx, tree t,
> > >         break;
> > > 
> > >       case SIZEOF_EXPR:
> > > -      r = fold_sizeof_expr (t);
> > > -      VERIFY_CONSTANT (r);
> > > +      r = cxx_eval_constant_expression (ctx, fold_sizeof_expr (t), lval,
> > > +                   non_constant_p, overflow_p,
> > > +                   jump_target);
> > >         break;
> > > 
> > > In a template, fold_sizeof_expr will just create a new SIZEOF_EXPR, that 
> > > is the
> > > same, but not identical; see cxx_sizeof_expr.  Then 
> > > cxx_eval_constant_expression
> > 
> > Not always, if it calls cxx_sizeof_expr, it will, but if it calls
> > cxx_sizeof_or_alignof_type it will only if the type is dependent or VLA.
> > 
> > So, I'd think you should call cxx_eval_constant_expression if TREE_CODE (r)
> > != SIZEOF_EXPR, otherwise probably *non_constant_p = true; is in order,
> > maybe together with gcc_assert (ctx->quiet); ?  I'd hope that if we really
> > require a constant expression we evaluate it in !processing_template_decl
> > contexts.

Ok, I had been meaning to add the *non_constant_p bit but never did.  :(

> Makes sense.  Also, cxx_sizeof_expr should probably only return a
> SIZEOF_EXPR if the operand is instantiation-dependent.

That results in

  FAIL: g++.dg/template/incomplete6.C  -std=c++98 (internal compiler error)
  FAIL: g++.dg/template/incomplete6.C  -std=c++98 (test for excess errors)
  FAIL: g++.dg/template/overload13.C  -std=c++98 (internal compiler error)
  FAIL: g++.dg/template/overload13.C  -std=c++98 (test for excess errors)

because we trigger an assert in value_dependent_expression_p:

            /* If there are no operands, it must be an expression such
               as "int()". This should not happen for aggregate types
               because it would form non-constant expressions.  */
            gcc_assert (cxx_dialect >= cxx11
                        || INTEGRAL_OR_ENUMERATION_TYPE_P (type));

            return false;

and in this case we have T() where T is a class, and it's in C++98.

It's not needed to fix this PR so perhaps the following could go in,
but is there anything I should do about that?

Bootstrapped/regtested on x86_64-linux, ok for trunk and 9?

2019-06-11  Marek Polacek  <pola...@redhat.com>

        PR c++/90825 - endless recursion when evaluating sizeof.
        * constexpr.c (cxx_eval_constant_expression): Don't recurse on the
        result of fold_sizeof_expr if is returns a SIZEOF_EXPR.

        * g++.dg/cpp0x/constexpr-sizeof2.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index a2f29694462..443e1c7899f 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -4808,9 +4808,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
       break;
 
     case SIZEOF_EXPR:
-      r = cxx_eval_constant_expression (ctx, fold_sizeof_expr (t), lval,
-                                       non_constant_p, overflow_p,
-                                       jump_target);
+      r = fold_sizeof_expr (t);
+      /* In a template, fold_sizeof_expr may merely create a new SIZEOF_EXPR,
+        which could lead to an infinite recursion.  */
+      if (TREE_CODE (r) != SIZEOF_EXPR)
+       r = cxx_eval_constant_expression (ctx, r, lval,
+                                         non_constant_p, overflow_p,
+                                         jump_target);
+      else
+       *non_constant_p = true;
+
       break;
 
     case COMPOUND_EXPR:
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-sizeof2.C 
gcc/testsuite/g++.dg/cpp0x/constexpr-sizeof2.C
new file mode 100644
index 00000000000..8676ae40b61
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-sizeof2.C
@@ -0,0 +1,14 @@
+// PR c++/90825 - endless recursion when evaluating sizeof.
+// { dg-do compile { target c++11 } }
+
+class address {
+  char host_[63];
+public:
+  static constexpr unsigned buffer_size() noexcept { return sizeof(host_); }
+};
+
+template <class Archive>
+void load()
+{
+  char host[address::buffer_size()];
+}

Reply via email to