* C++ PATCH for c++/90825 - endless recursion when evaluating sizeof
@ 2019-06-11 1:59 Marek Polacek
2019-06-11 11:48 ` Jakub Jelinek
0 siblings, 1 reply; 7+ messages in thread
From: Marek Polacek @ 2019-06-11 1:59 UTC (permalink / raw)
To: GCC Patches, Jason Merrill, Jakub Jelinek
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
calls itself on this new expr, then fold_sizeof_expr creates another SIZEOF_EXPR.
Then we call cxx_eval_constant_expression...
The call to cxx_eval_constant_expression is there to keep constexpr-vla1.C
working. But we can avoid calling it in a template and it'll still work, and
we avoid this nasty recursion.
Bootstrapped/regtested on x86_64-linux, ok for trunk and 9?
2019-06-10 Marek Polacek <polacek@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 in a template.
* g++.dg/cpp0x/constexpr-sizeof2.C: New test.
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index a2f29694462..a68aac3b531 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -4808,9 +4808,13 @@ 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);
+ /* Don't recurse in a template, because then fold_sizeof_expr merely
+ creates a new SIZEOF_EXPR, leading to an infinite recursion. */
+ if (!processing_template_decl)
+ r = cxx_eval_constant_expression (ctx, r, lval,
+ non_constant_p, overflow_p,
+ jump_target);
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..2d3a169d28c
--- /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()];
+}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: C++ PATCH for c++/90825 - endless recursion when evaluating sizeof
2019-06-11 1:59 C++ PATCH for c++/90825 - endless recursion when evaluating sizeof Marek Polacek
@ 2019-06-11 11:48 ` Jakub Jelinek
2019-06-11 12:37 ` Jason Merrill
0 siblings, 1 reply; 7+ messages in thread
From: Jakub Jelinek @ 2019-06-11 11:48 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches, Jason Merrill
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.
> 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);
> + /* Don't recurse in a template, because then fold_sizeof_expr merely
> + creates a new SIZEOF_EXPR, leading to an infinite recursion. */
> + if (!processing_template_decl)
> + r = cxx_eval_constant_expression (ctx, r, lval,
> + non_constant_p, overflow_p,
> + jump_target);
> break;
Jakub
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: C++ PATCH for c++/90825 - endless recursion when evaluating sizeof
2019-06-11 11:48 ` Jakub Jelinek
@ 2019-06-11 12:37 ` Jason Merrill
2019-06-11 18:28 ` Marek Polacek
0 siblings, 1 reply; 7+ messages in thread
From: Jason Merrill @ 2019-06-11 12:37 UTC (permalink / raw)
To: Jakub Jelinek, Marek Polacek; +Cc: GCC Patches
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.
Makes sense. Also, cxx_sizeof_expr should probably only return a
SIZEOF_EXPR if the operand is instantiation-dependent.
Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: C++ PATCH for c++/90825 - endless recursion when evaluating sizeof
2019-06-11 12:37 ` Jason Merrill
@ 2019-06-11 18:28 ` Marek Polacek
2019-06-11 19:05 ` Jason Merrill
0 siblings, 1 reply; 7+ messages in thread
From: Marek Polacek @ 2019-06-11 18:28 UTC (permalink / raw)
To: Jason Merrill; +Cc: Jakub Jelinek, GCC Patches
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 <polacek@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()];
+}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: C++ PATCH for c++/90825 - endless recursion when evaluating sizeof
2019-06-11 18:28 ` Marek Polacek
@ 2019-06-11 19:05 ` Jason Merrill
2019-06-11 19:59 ` Marek Polacek
0 siblings, 1 reply; 7+ messages in thread
From: Jason Merrill @ 2019-06-11 19:05 UTC (permalink / raw)
To: Marek Polacek; +Cc: Jakub Jelinek, GCC Patches
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.
> Bootstrapped/regtested on x86_64-linux, ok for trunk and 9?
>
> 2019-06-11 Marek Polacek <polacek@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;
Let's also add the assert Jakub suggested.
Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: C++ PATCH for c++/90825 - endless recursion when evaluating sizeof
2019-06-11 19:05 ` Jason Merrill
@ 2019-06-11 19:59 ` Marek Polacek
2019-06-12 21:35 ` Jason Merrill
0 siblings, 1 reply; 7+ messages in thread
From: Marek Polacek @ 2019-06-11 19:59 UTC (permalink / raw)
To: Jason Merrill; +Cc: Jakub Jelinek, GCC Patches
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 <polacek@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>{}), "" );
+ }
+};
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: C++ PATCH for c++/90825 - endless recursion when evaluating sizeof
2019-06-11 19:59 ` Marek Polacek
@ 2019-06-12 21:35 ` Jason Merrill
0 siblings, 0 replies; 7+ messages in thread
From: Jason Merrill @ 2019-06-12 21:35 UTC (permalink / raw)
To: Marek Polacek; +Cc: Jakub Jelinek, GCC Patches
On 6/11/19 3:59 PM, Marek Polacek wrote:
> 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?
OK.
Jason
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2019-06-12 21:35 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-11 1:59 C++ PATCH for c++/90825 - endless recursion when evaluating sizeof Marek Polacek
2019-06-11 11:48 ` Jakub Jelinek
2019-06-11 12:37 ` Jason Merrill
2019-06-11 18:28 ` Marek Polacek
2019-06-11 19:05 ` Jason Merrill
2019-06-11 19:59 ` Marek Polacek
2019-06-12 21:35 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).