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()]; +}