On Tue, Jun 11, 2019 at 03:05:26PM -0400, Jason Merrill wrote: > On 6/11/19 2:28 PM, Marek Polacek wrote: > > 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? > > instantiation_dependent_uneval_expression_p shouldn't have that problem.
Ah, nice. > > 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; > > Let's also add the assert Jakub suggested. Done. Luckily, this also fixed c++/90832 so I'm adding a test for that, too. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-06-11 Marek Polacek <pola...@redhat.com> PR c++/90825 - endless recursion when evaluating sizeof. PR c++/90832 - 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. * typeck.c (cxx_sizeof_expr): Only return a SIZEOF_EXPR if the operand is instantiation-dependent. * g++.dg/cpp0x/constexpr-sizeof2.C: New test. * g++.dg/cpp0x/constexpr-sizeof3.C: New test. diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index a2f29694462..80eaffdb33f 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -4808,9 +4808,19 @@ 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; + gcc_assert (ctx->quiet); + } + break; case COMPOUND_EXPR: diff --git gcc/cp/typeck.c gcc/cp/typeck.c index 154da59627b..a8fb1624b48 100644 --- gcc/cp/typeck.c +++ gcc/cp/typeck.c @@ -1690,7 +1690,7 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain) if (e == error_mark_node) return error_mark_node; - if (processing_template_decl) + if (instantiation_dependent_uneval_expression_p (e)) { e = build_min (SIZEOF_EXPR, size_type_node, e); TREE_SIDE_EFFECTS (e) = 0; 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()]; +} diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-sizeof3.C gcc/testsuite/g++.dg/cpp0x/constexpr-sizeof3.C new file mode 100644 index 00000000000..05f07c38796 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/constexpr-sizeof3.C @@ -0,0 +1,22 @@ +// PR c++/90832 - endless recursion when evaluating sizeof. +// { dg-do compile { target c++11 } } + +class B +{ + template <typename T> friend struct A; + B() {} +}; + +template <typename T> +struct A +{ + A() noexcept(sizeof(B{})) { } +}; + +struct C +{ + C() + { + static_assert( sizeof(A<int>{}), "" ); + } +};