Bug 96497 - Compare std::variant with int using C++20 <=> is not a constant expression
Summary: Compare std::variant with int using C++20 <=> is not a constant expression
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: ---
Assignee: Jakub Jelinek
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2020-08-06 13:37 UTC by 康桓瑋
Modified: 2020-09-16 16:43 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-08-06 00:00:00


Attachments
gcc11-pr96497.patch (593 bytes, patch)
2020-08-07 11:50 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description 康桓瑋 2020-08-06 13:37:18 UTC
#include <compare>
#include <variant>

using variant = std::variant<int, double>;

constexpr auto operator<=>(const variant& v, const auto& u) {
  return std::visit([&u](const auto& t) -> std::partial_ordering { return t <=> u; }, v);
}

constexpr variant v{1};
static_assert(v < 2);

This fails on gcc 11.0 with:
<source>: In function 'int main()':
<source>:12:19: error: non-constant condition for static assertion
   12 |   static_assert(v < 2);
      |                 ~~^~~
<source>:12:19: error: '<anonymous>' is not a constant expression

but if I initialize the v with double, it can compile:

constexpr variant v{1.0};
static_assert(v < 2);

godbolt link:
https://godbolt.org/z/eE9c97
Comment 1 Barry Revzin 2020-08-06 13:58:30 UTC
Reduced (https://godbolt.org/z/1bY545):

#include <compare>

// this one is okay
static_assert(std::partial_ordering(std::strong_ordering::less) < 0);

// this one fails with non-constant condition
static_assert(std::partial_ordering(1 <=> 2) < 0);
Comment 2 Jakub Jelinek 2020-08-07 11:50:30 UTC
Created attachment 49019 [details]
gcc11-pr96497.patch

Untested fix.
Comment 3 GCC Commits 2020-08-10 15:54:45 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:5c64df80df274c753bfc8415bd902e1180e76f6a

commit r11-2635-g5c64df80df274c753bfc8415bd902e1180e76f6a
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Mon Aug 10 17:53:46 2020 +0200

    c++: Fix constexpr evaluation of SPACESHIP_EXPR [PR96497]
    
    The following valid testcase is rejected, because cxx_eval_binary_expression
    is called on the SPACESHIP_EXPR with lval = true, as the address of the
    spaceship needs to be passed to a method call.
    After recursing on the operands and calling genericize_spaceship which turns
    it into a TARGET_EXPR with initialization, we call cxx_eval_constant_expression
    on it which succeeds, but then we fall through into code that will
    VERIFY_CONSTANT (r) which FAILs because it is an address of a variable.  Rather
    than avoiding that for lval = true and SPACESHIP_EXPR, the patch just tail
    calls cxx_eval_constant_expression - I believe that call should perform all
    the needed verifications.
    
    2020-08-10  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/96497
            * constexpr.c (cxx_eval_binary_expression): For SPACESHIP_EXPR, tail
            call cxx_eval_constant_expression after genericize_spaceship to avoid
            undesirable further VERIFY_CONSTANT.
    
            * g++.dg/cpp2a/spaceship-constexpr3.C: New test.
Comment 4 Jakub Jelinek 2020-08-10 16:49:53 UTC
Should be fixed for 11, I think we should backport to 10.3 too eventually.
Comment 5 GCC Commits 2020-08-25 17:45:07 UTC
The releases/gcc-10 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

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

commit r10-8664-gaaac798d29acb61ab510c6106d10fc641becfcb7
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Mon Aug 10 17:53:46 2020 +0200

    c++: Fix constexpr evaluation of SPACESHIP_EXPR [PR96497]
    
    The following valid testcase is rejected, because cxx_eval_binary_expression
    is called on the SPACESHIP_EXPR with lval = true, as the address of the
    spaceship needs to be passed to a method call.
    After recursing on the operands and calling genericize_spaceship which turns
    it into a TARGET_EXPR with initialization, we call cxx_eval_constant_expression
    on it which succeeds, but then we fall through into code that will
    VERIFY_CONSTANT (r) which FAILs because it is an address of a variable.  Rather
    than avoiding that for lval = true and SPACESHIP_EXPR, the patch just tail
    calls cxx_eval_constant_expression - I believe that call should perform all
    the needed verifications.
    
    2020-08-10  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/96497
            * constexpr.c (cxx_eval_binary_expression): For SPACESHIP_EXPR, tail
            call cxx_eval_constant_expression after genericize_spaceship to avoid
            undesirable further VERIFY_CONSTANT.
    
            * g++.dg/cpp2a/spaceship-constexpr3.C: New test.
    
    (cherry picked from commit 5c64df80df274c753bfc8415bd902e1180e76f6a)
Comment 6 Jakub Jelinek 2020-09-16 16:43:15 UTC
Fixed.