Bug 92431 - ICE with spaceship in constexpr evaluation
Summary: ICE with spaceship in constexpr evaluation
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: ice-on-valid-code
Depends on:
Blocks: constexpr
  Show dependency treegraph
Reported: 2019-11-09 11:19 UTC by Jonathan Wakely
Modified: 2020-08-07 16:47 UTC (History)
3 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2019-11-09 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2019-11-09 11:19:53 UTC
This crashes when compiled with -std=gnu++2a:

#include <compare>

template<typename _Tp, typename _Up>
  concept op_cmp = requires(_Tp&& __t, _Up&& __u)
    std::weak_ordering(static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u));

struct Weak_order
  template<typename _Tp, typename _Up>
    constexpr std::weak_ordering
    operator()(_Tp&& __e, _Up&& __f) const
      if constexpr (op_cmp<_Tp, _Up>)
        return static_cast<_Tp&&>(__e) <=> static_cast<_Up&&>(__f);

constexpr Weak_order weak_order{};

auto o = weak_order(1, 2);

wo.cc:22:25:   in 'constexpr' expansion of 'weak_order.Weak_order::operator()<int, int>(1, 2)'
wo.cc:22:25: internal compiler error: in cxx_eval_constant_expression, at cp/constexpr.c:5123
   22 | auto o = weak_order(1, 2);
      |                         ^
0x5d0fd7 cxx_eval_constant_expression
0x88f898 cxx_bind_parameters_in_call
0x88f898 cxx_eval_call_expression
0x892d5a cxx_eval_constant_expression
0x893cbd cxx_eval_constant_expression
0x89c27a cxx_eval_store_expression
0x893046 cxx_eval_constant_expression
0x8916d3 cxx_eval_constant_expression
0x892513 cxx_eval_constant_expression
0x893da0 cxx_eval_constant_expression
0x890adb cxx_eval_call_expression
0x892d5a cxx_eval_constant_expression
0x895d8e cxx_eval_outermost_constant_expr
0x89a24b maybe_constant_value(tree_node*, tree_node*, bool)
0xa55490 store_init_value(tree_node*, tree_node*, vec<tree_node*, va_gc, vl_embed>**, int)
0x8c952d check_initializer
0x8ebfdf cp_finish_decl(tree_node*, tree_node*, bool, tree_node*, int)
0x99660e cp_parser_init_declarator
0x9764b2 cp_parser_simple_declaration
0x99e997 cp_parser_declaration
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 Jonathan Wakely 2019-11-09 16:30:53 UTC

#include <compare>

template<typename T, typename U>
  constexpr std::weak_ordering
  cmp(T e, U f)
    return e <=> f;

auto o = cmp(1, 2);

wo.cc:10:18:   in 'constexpr' expansion of 'cmp<int, int>(1, 2)'
wo.cc:10:18: internal compiler error: in cxx_eval_constant_expression, at cp/constexpr.c:5123
   10 | auto o = cmp(1, 2);
      |                  ^

Related to converting the strong_ordering result of <=> to weak_ordering?
Comment 2 Jonathan Wakely 2019-11-09 16:31:57 UTC
Slightly further reduced:

#include <compare>

constexpr std::weak_ordering
cmp(int e, int f)
  return e <=> f;

auto o = cmp(1, 2);
Comment 3 Jakub Jelinek 2019-11-09 18:17:58 UTC
Further reduced:
namespace std {
enum E { e };
struct strong_ordering {
  int c;
  constexpr strong_ordering(E) : c () {}
  static const strong_ordering less;
  static strong_ordering equal;
  static strong_ordering greater;
  constexpr operator int() {}
strong_ordering constexpr strong_ordering::less(e);
constexpr int cmp (int d, int e) { return d <=> e; }
auto f = cmp (1, 2);

We have ADDR_EXPR of a SPACESHIP_EXPR originally, the SPACESHIP_EXPR is constexpr evaluated into a CONSTRUCTOR but the ADDR_EXPR handling code in in cxx_eval_constant_expression asserts that ADDR_EXPR operand doesn't evaluate into a CONSTRUCTOR when lval is true.
Comment 4 Jonathan Wakely 2019-11-13 16:26:50 UTC
Author: redi
Date: Wed Nov 13 16:26:18 2019
New Revision: 278149

URL: https://gcc.gnu.org/viewcvs?rev=278149&root=gcc&view=rev
libsupc++: Implement comparison algorithms for C++20

This is incomplete because std::strong_order doesn't support
floating-point types.

The partial_order and weak_order tests use VERIFY instead of
static_assert because of PR 92431.

	* libsupc++/compare (strong_order, weak_order, partial_order)
	(compare_strong_order_fallback, compare_weak_order_fallback)
	(compare_partial_order_fallback): Define customization point objects
	for C++20.
	* testsuite/18_support/comparisons/algorithms/partial_order.cc: New
	* testsuite/18_support/comparisons/algorithms/strong_order.cc: New
	* testsuite/18_support/comparisons/algorithms/weak_order.cc: New test.

Comment 5 Jonathan Wakely 2020-08-07 16:17:32 UTC
This was fixed by r10-6572-dfffecb802681fbdb56629d3bdd96491ac660be0

    c++: Fix static initialization from <=>.
    Constant evaluation of genericize_spaceship produced a CONSTRUCTOR, which we
    then wanted to bind to a reference, which we can't do.  So wrap the result
    in a TARGET_EXPR so we get something with an address.
    We also need to handle treating the result of cxx_eval_binary_expression as
    a glvalue for SPACESHIP_EXPR.
    My earlier change to add uid_sensitive to maybe_constant_value was wrong; we
    don't even look at the cache when manifestly_const_eval, and I failed to
    adjust the later call to cxx_eval_outermost_constant_expr.
    2020-02-11  Jason Merrill  <jason@redhat.com>
            PR c++/93650
            PR c++/90691
            * constexpr.c (maybe_constant_value): Correct earlier change.
            (cxx_eval_binary_expression) [SPACESHIP_EXPR]: Pass lval through.
            * method.c (genericize_spaceship): Wrap result in TARGET_EXPR.
Comment 6 Jonathan Wakely 2020-08-07 16:47:52 UTC
(In reply to Jonathan Wakely from comment #4)
> This is incomplete because std::strong_order doesn't support
> floating-point types.

See PR 96526 regarding that.

> The partial_order and weak_order tests use VERIFY instead of
> static_assert because of PR 92431.

Some of those VERIFYs have been changed to static_assert in r11-2609