Bug 104568 - [10 Regression] ICE [c++20] caused by option "-std=c++20 -Wall" when operand of operator new has size equal to 0
Summary: [10 Regression] ICE [c++20] caused by option "-std=c++20 -Wall" when operand ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 12.0
: P2 normal
Target Milestone: 10.4
Assignee: Jakub Jelinek
URL:
Keywords: ice-on-invalid-code
Depends on:
Blocks:
 
Reported: 2022-02-16 16:02 UTC by qingzhe huang
Modified: 2022-05-10 10:23 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 10.1.0, 10.3.0, 11.2.0
Last reconfirmed: 2022-02-16 00:00:00


Attachments
gcc12-pr104568.patch (2.36 KB, patch)
2022-02-17 15:09 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description qingzhe huang 2022-02-16 16:02:42 UTC
See the following program causes ICE with flag ONLY of "-std=c++20 -Wall" which proves it to be a regression of c++20. 

The root cause is very simple that "std::default_delete" has a static_assert to require element size pointed by pointer to be bigger than 0. A empty array of "int[0]" violates this assertion, all other flag gives the correct root cause without crash. However, "-std=c++20 -Wall" option issues very confusing error message "Floating point exception" and crashes.



#include <memory>
using namespace std;

typedef int Ary0[0];
int main(){
	unique_ptr<Ary0> ptr;
	ptr.reset(new Ary0[0]);
	return 0;
}




tests/unique.cpp: In function ‘int main()’:
tests/unique.cpp:7:18: internal compiler error: Floating point exception
    7 |         ptr.reset(new Ary0[0]);
      |         ~~~~~~~~~^~~~~~~~~~~~~
0x1522a90 crash_signal
	/home/nick/Downloads/gcc-dev/gcc/gcc/toplev.cc:322
0xbd4829 build_new_constexpr_heap_type(tree_node*, tree_node*, tree_node*)
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/init.cc:2944
0xb2f837 cxx_eval_constant_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/constexpr.cc:7262
0xb2f1cf cxx_eval_constant_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/constexpr.cc:7147
0xb30dd1 cxx_eval_outermost_constant_expr
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/constexpr.cc:7700
0xb319d2 maybe_constant_value(tree_node*, tree_node*, bool)
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/constexpr.cc:7990
0xbcbd84 fold_for_warn(tree_node*)
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/expr.cc:416
0xddaed6 check_function_restrict
	/home/nick/Downloads/gcc-dev/gcc/gcc/c-family/c-common.cc:5704
0xddc1d9 check_function_arguments(unsigned int, tree_node const*, tree_node const*, int, tree_node**, vec<unsigned int, va_heap, vl_ptr>*)
	/home/nick/Downloads/gcc-dev/gcc/gcc/c-family/c-common.cc:6091
0xaf16fe build_over_call
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/call.cc:9662
0xaf5a03 build_new_method_call(tree_node*, tree_node*, vec<tree_node*, va_gc, vl_embed>**, tree_node*, int, tree_node**, int)
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/call.cc:11146
0xc70cd6 cp_parser_postfix_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:7844
0xc73625 cp_parser_unary_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:9033
0xc74c64 cp_parser_cast_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:9937
0xc74d82 cp_parser_binary_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:10039
0xc75b61 cp_parser_assignment_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:10343
0xc75ec3 cp_parser_expression
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:10513
0xc7adb5 cp_parser_expression_statement
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:12709
0xc7a795 cp_parser_statement
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:12505
0xc7b23c cp_parser_statement_seq_opt
	/home/nick/Downloads/gcc-dev/gcc/gcc/cp/parser.cc:12854
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Comment 1 Drea Pinski 2022-02-16 17:51:05 UTC
The error-recovery issue (without -Wall) is gone in 11.2.0.
Comment 2 Drea Pinski 2022-02-16 17:53:06 UTC
I suspect the implementation of P0784R7 which was done as PR 91369 introduced this ICE.
Comment 3 Jakub Jelinek 2022-02-16 18:29:41 UTC
Make it
typedef int T[0];

constexpr bool
foo ()
{
  auto p = new T[0];
  delete p;
  return true;
}

constexpr bool a = foo ();
so that it is constant evaluated always, doesn't need -Wall then, just -std=c++20 or -std=c++23.
Comment 4 Jakub Jelinek 2022-02-16 19:26:37 UTC
The code tries to compute how many elements an array with such element type should have, and obviously when the element size is zero, that doesn't work.
Will need to figure out if the size can be derived from something else or is completely lost at that point, 0 * anything is 0 but even with zero element size we might need to know if p[0] or p[23] etc. is valid or not.
Comment 5 Jakub Jelinek 2022-02-17 15:09:25 UTC
Created attachment 52460 [details]
gcc12-pr104568.patch

Untested fix.
Comment 6 GCC Commits 2022-03-18 18:02:34 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:0a0c2c3f06227d46b5e9542dfdd4e0fd2d67d894

commit r12-7712-g0a0c2c3f06227d46b5e9542dfdd4e0fd2d67d894
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Mar 18 18:49:23 2022 +0100

    c++: Fix up constexpr evaluation of new with zero sized types [PR104568]
    
    The new expression constant expression evaluation right now tries to
    deduce how many elts the array it uses for the heap or heap [] vars
    should have (or how many elts should its trailing array have if it has
    cookie at the start).  As new is lowered at that point to
    (some_type *) ::operator new (size)
    or so, it computes it by subtracting cookie size if any from size, then
    divides the result by sizeof (some_type).
    This works fine for most types, except when sizeof (some_type) is 0,
    then we divide by zero; size is then equal to cookie_size (or if there
    is no cookie, to 0).
    The following patch special cases those cases so that we don't divide
    by zero and also recover the original outer_nelts from the expression
    by forcing the size not to be folded in that case but be explicit
    0 * outer_nelts or cookie_size + 0 * outer_nelts.
    
    Note, we have further issues, we accept-invalid various cases, for both
    zero sized elt_type and even non-zero sized elts, we aren't able to
    diagnose out of bounds POINTER_PLUS_EXPR like:
    constexpr bool
    foo ()
    {
      auto p = new int[2];
      auto q1 = &p[0];
      auto q2 = &p[1];
      auto q3 = &p[2];
      auto q4 = &p[3];
      delete[] p;
      return true;
    }
    constexpr bool a = foo ();
    That doesn't look like a regression so I think we should resolve that for
    GCC 13, but there are 2 problems.  Figure out why
    cxx_fold_pointer_plus_expression doesn't deal with the &heap []
    etc. cases, and for the zero sized arrays, I think we really need to preserve
    whether user wrote an array ref or pointer addition, because in the
    &p[3] case if sizeof(p[0]) == 0 we know that if it has 2 elements it is
    out of bounds, while if we see p p+ 0 the information if it was
    p + 2 or p + 3 in the source is lost.
    clang++ seems to handle it fine even in the zero sized cases or with
    new expressions.
    
    2022-03-18  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/104568
            * init.cc (build_new_constexpr_heap_type): Remove FULL_SIZE
            argument and its handling, instead add ITYPE2 argument.  Only
            support COOKIE_SIZE != NULL.
            (build_new_1): If size is 0, change it to 0 * outer_nelts if
            outer_nelts is non-NULL.  Pass type rather than elt_type to
            maybe_wrap_new_for_constexpr.
            * constexpr.cc (build_new_constexpr_heap_type): New function.
            (cxx_eval_constant_expression) <case CONVERT_EXPR>:
            If elt_size is zero sized type, try to recover outer_nelts from
            the size argument to operator new/new[] and pass that as
            arg_size to build_new_constexpr_heap_type.  Pass ctx,
            non_constant_p and overflow_p to that call too.
    
            * g++.dg/cpp2a/constexpr-new22.C: New test.
Comment 7 Jakub Jelinek 2022-03-18 18:03:56 UTC
Fixed on the trunk so far.
Comment 8 GCC Commits 2022-03-29 05:54:20 UTC
The releases/gcc-11 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:18f5bc87bc2eef70991b9c93d1265a7d0ebed58b

commit r11-9730-g18f5bc87bc2eef70991b9c93d1265a7d0ebed58b
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Mar 18 18:49:23 2022 +0100

    c++: Fix up constexpr evaluation of new with zero sized types [PR104568]
    
    The new expression constant expression evaluation right now tries to
    deduce how many elts the array it uses for the heap or heap [] vars
    should have (or how many elts should its trailing array have if it has
    cookie at the start).  As new is lowered at that point to
    (some_type *) ::operator new (size)
    or so, it computes it by subtracting cookie size if any from size, then
    divides the result by sizeof (some_type).
    This works fine for most types, except when sizeof (some_type) is 0,
    then we divide by zero; size is then equal to cookie_size (or if there
    is no cookie, to 0).
    The following patch special cases those cases so that we don't divide
    by zero and also recover the original outer_nelts from the expression
    by forcing the size not to be folded in that case but be explicit
    0 * outer_nelts or cookie_size + 0 * outer_nelts.
    
    Note, we have further issues, we accept-invalid various cases, for both
    zero sized elt_type and even non-zero sized elts, we aren't able to
    diagnose out of bounds POINTER_PLUS_EXPR like:
    constexpr bool
    foo ()
    {
      auto p = new int[2];
      auto q1 = &p[0];
      auto q2 = &p[1];
      auto q3 = &p[2];
      auto q4 = &p[3];
      delete[] p;
      return true;
    }
    constexpr bool a = foo ();
    That doesn't look like a regression so I think we should resolve that for
    GCC 13, but there are 2 problems.  Figure out why
    cxx_fold_pointer_plus_expression doesn't deal with the &heap []
    etc. cases, and for the zero sized arrays, I think we really need to preserve
    whether user wrote an array ref or pointer addition, because in the
    &p[3] case if sizeof(p[0]) == 0 we know that if it has 2 elements it is
    out of bounds, while if we see p p+ 0 the information if it was
    p + 2 or p + 3 in the source is lost.
    clang++ seems to handle it fine even in the zero sized cases or with
    new expressions.
    
    2022-03-18  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/104568
            * init.c (build_new_constexpr_heap_type): Remove FULL_SIZE
            argument and its handling, instead add ITYPE2 argument.  Only
            support COOKIE_SIZE != NULL.
            (build_new_1): If size is 0, change it to 0 * outer_nelts if
            outer_nelts is non-NULL.  Pass type rather than elt_type to
            maybe_wrap_new_for_constexpr.
            * constexpr.c (build_new_constexpr_heap_type): New function.
            (cxx_eval_constant_expression) <case CONVERT_EXPR>:
            If elt_size is zero sized type, try to recover outer_nelts from
            the size argument to operator new/new[] and pass that as
            arg_size to build_new_constexpr_heap_type.  Pass ctx,
            non_constant_p and overflow_p to that call too.
    
            * g++.dg/cpp2a/constexpr-new22.C: New test.
    
    (cherry picked from commit 0a0c2c3f06227d46b5e9542dfdd4e0fd2d67d894)
Comment 9 Jakub Jelinek 2022-03-30 08:16:18 UTC
Fixed for 11.3 too.
Comment 10 GCC Commits 2022-05-10 08:25:21 UTC
The releases/gcc-10 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:d7b94c407a2720955927d501c5a67821c010aeed

commit r10-10696-gd7b94c407a2720955927d501c5a67821c010aeed
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Mar 18 18:49:23 2022 +0100

    c++: Fix up constexpr evaluation of new with zero sized types [PR104568]
    
    The new expression constant expression evaluation right now tries to
    deduce how many elts the array it uses for the heap or heap [] vars
    should have (or how many elts should its trailing array have if it has
    cookie at the start).  As new is lowered at that point to
    (some_type *) ::operator new (size)
    or so, it computes it by subtracting cookie size if any from size, then
    divides the result by sizeof (some_type).
    This works fine for most types, except when sizeof (some_type) is 0,
    then we divide by zero; size is then equal to cookie_size (or if there
    is no cookie, to 0).
    The following patch special cases those cases so that we don't divide
    by zero and also recover the original outer_nelts from the expression
    by forcing the size not to be folded in that case but be explicit
    0 * outer_nelts or cookie_size + 0 * outer_nelts.
    
    Note, we have further issues, we accept-invalid various cases, for both
    zero sized elt_type and even non-zero sized elts, we aren't able to
    diagnose out of bounds POINTER_PLUS_EXPR like:
    constexpr bool
    foo ()
    {
      auto p = new int[2];
      auto q1 = &p[0];
      auto q2 = &p[1];
      auto q3 = &p[2];
      auto q4 = &p[3];
      delete[] p;
      return true;
    }
    constexpr bool a = foo ();
    That doesn't look like a regression so I think we should resolve that for
    GCC 13, but there are 2 problems.  Figure out why
    cxx_fold_pointer_plus_expression doesn't deal with the &heap []
    etc. cases, and for the zero sized arrays, I think we really need to preserve
    whether user wrote an array ref or pointer addition, because in the
    &p[3] case if sizeof(p[0]) == 0 we know that if it has 2 elements it is
    out of bounds, while if we see p p+ 0 the information if it was
    p + 2 or p + 3 in the source is lost.
    clang++ seems to handle it fine even in the zero sized cases or with
    new expressions.
    
    2022-03-18  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/104568
            * init.c (build_new_constexpr_heap_type): Remove FULL_SIZE
            argument and its handling, instead add ITYPE2 argument.  Only
            support COOKIE_SIZE != NULL.
            (build_new_1): If size is 0, change it to 0 * outer_nelts if
            outer_nelts is non-NULL.  Pass type rather than elt_type to
            maybe_wrap_new_for_constexpr.
            * constexpr.c (build_new_constexpr_heap_type): New function.
            (cxx_eval_constant_expression) <case CONVERT_EXPR>:
            If elt_size is zero sized type, try to recover outer_nelts from
            the size argument to operator new/new[] and pass that as
            arg_size to build_new_constexpr_heap_type.  Pass ctx,
            non_constant_p and overflow_p to that call too.
    
            * g++.dg/cpp2a/constexpr-new22.C: New test.
    
    (cherry picked from commit 0a0c2c3f06227d46b5e9542dfdd4e0fd2d67d894)
Comment 11 Jakub Jelinek 2022-05-10 10:23:55 UTC
Fixed for 10.4 too.