Bug 114537 - bit_cast does not work NSDMI of bitfields
Summary: bit_cast does not work NSDMI of bitfields
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 14.0
: P3 normal
Target Milestone: 11.5
Assignee: Jakub Jelinek
URL:
Keywords: FIXME
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2024-03-31 19:33 UTC by Drea Pinski
Modified: 2024-06-20 13:39 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-04-03 00:00:00


Attachments
gcc14-pr114537.patch (633 bytes, patch)
2024-04-03 15:10 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Drea Pinski 2024-03-31 19:33:36 UTC
Take:
```
#include <bit>

struct A {  signed char b:1 = 0; signed char b1:7 = 0; };

struct B { unsigned char b; };

static_assert( std::bit_cast<B>(A{}).b == 0 );
```

This should work as the bitfields span all of the char space but currently we get a sorry:
```
<source>:9:40: error: non-constant condition for static assertion
    9 | static_assert( std::bit_cast<B>(A{}).b == 0 );
      |                ~~~~~~~~~~~~~~~~~~~~~~~~^~~~
In file included from <source>:2:
<source>:9:32:   in 'constexpr' expansion of 'std::bit_cast<B, A>(A{0, 0})'
/opt/compiler-explorer/gcc-trunk-20240331/include/c++/14.0.1/bit:94:33: sorry, unimplemented: '__builtin_bit_cast' cannot be constant evaluated because the argument cannot be encoded
   94 |       return __builtin_bit_cast(_To, __from);
      |                                 ^~~
```

I had been looking for a quick workaround for PR 114536 (for little-endian only) but it looked like NSDMI for bitfields is not implemented fully.
Comment 1 Fedor Chelnokov 2024-04-01 09:40:48 UTC
Probably related:
```
#include <bit>

struct A { int a: 7; };

static_assert( 1 == std::bit_cast<A>(std::bit_cast<int>(A{1})).a );
```
It looks valid and accepted by MSVC, but GCC prints:
error: '__builtin_bit_cast' accessing uninitialized byte at offset 0

Online demo: https://gcc.godbolt.org/z/3W5onY955
Comment 2 Drea Pinski 2024-04-01 13:54:21 UTC
(In reply to Fedor Chelnokov from comment #1)
> Probably related:
> ```
> #include <bit>
> 
> struct A { int a: 7; };
> 
> static_assert( 1 == std::bit_cast<A>(std::bit_cast<int>(A{1})).a );
> ```
> It looks valid and accepted by MSVC, but GCC prints:
> error: '__builtin_bit_cast' accessing uninitialized byte at offset 0
> 
> Online demo: https://gcc.godbolt.org/z/3W5onY955

That is unrelated and gcc is actually correct there see pr 99637.
Comment 3 Jakub Jelinek 2024-04-03 15:10:26 UTC
Created attachment 57863 [details]
gcc14-pr114537.patch

Untested fix.
Comment 4 GCC Commits 2024-04-04 08:48:20 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:1baec8deb014b8a7da58879a407a4c00cdeb5a09

commit r14-9784-g1baec8deb014b8a7da58879a407a4c00cdeb5a09
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Thu Apr 4 10:47:52 2024 +0200

    fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537]
    
    The following testcase is incorrectly rejected.  The problem is that
    for bit-fields native_encode_initializer expects the corresponding
    CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case
    here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location.
    We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for
    is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier.
    
    2024-04-04  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/114537
            * fold-const.cc (native_encode_initializer): Look through
            NON_LVALUE_EXPR if val is INTEGER_CST.
    
            * g++.dg/cpp2a/bit-cast16.C: New test.
Comment 5 Fedor Chelnokov 2024-04-05 18:44:06 UTC
Sorry, in above example I had to use `unsigned char` type:

```
#include <bit>

struct A { unsigned char a : 7; };

static_assert( std::bit_cast<A>(std::bit_cast<unsigned char>(A{1})).a == 1 );
```

This program even after the fix in trunk, prints the same error as in the original post:
<source>:5:32:   in 'constexpr' expansion of 'std::bit_cast<A, unsigned char>(std::bit_cast<unsigned char, A>(A{1}))'
/opt/compiler-explorer/gcc-trunk-20240405/include/c++/14.0.1/bit:94:33: sorry, unimplemented: '__builtin_bit_cast' cannot be constant evaluated because the argument cannot be encoded
   94 |       return __builtin_bit_cast(_To, __from);

Online demo: https://gcc.godbolt.org/z/eqrsfGEnT
Comment 6 GCC Commits 2024-04-21 04:08:48 UTC
The releases/gcc-13 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

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

commit r13-8626-ga297f9bbb9611414fe48f6d61a8829bf5808bd2c
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Thu Apr 4 10:47:52 2024 +0200

    fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537]
    
    The following testcase is incorrectly rejected.  The problem is that
    for bit-fields native_encode_initializer expects the corresponding
    CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case
    here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location.
    We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for
    is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier.
    
    2024-04-04  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/114537
            * fold-const.cc (native_encode_initializer): Look through
            NON_LVALUE_EXPR if val is INTEGER_CST.
    
            * g++.dg/cpp2a/bit-cast16.C: New test.
    
    (cherry picked from commit 1baec8deb014b8a7da58879a407a4c00cdeb5a09)
Comment 7 GCC Commits 2024-06-11 10:37:44 UTC
The releases/gcc-12 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:42afabb838d511f5feb150bfa4e68b5880aae1fa

commit r12-10518-g42afabb838d511f5feb150bfa4e68b5880aae1fa
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Thu Apr 4 10:47:52 2024 +0200

    fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537]
    
    The following testcase is incorrectly rejected.  The problem is that
    for bit-fields native_encode_initializer expects the corresponding
    CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case
    here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location.
    We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for
    is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier.
    
    2024-04-04  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/114537
            * fold-const.cc (native_encode_initializer): Look through
            NON_LVALUE_EXPR if val is INTEGER_CST.
    
            * g++.dg/cpp2a/bit-cast16.C: New test.
    
    (cherry picked from commit 1baec8deb014b8a7da58879a407a4c00cdeb5a09)
Comment 8 Jakub Jelinek 2024-06-11 10:57:00 UTC
Should be fixed for 12.4+ and 13.4+ too.
Comment 9 GCC Commits 2024-06-20 13:22:54 UTC
The releases/gcc-11 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

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

commit r11-11501-g5d6b1d8ffc4828874ecdb1cde1b794bc3b8d35af
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Thu Apr 4 10:47:52 2024 +0200

    fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537]
    
    The following testcase is incorrectly rejected.  The problem is that
    for bit-fields native_encode_initializer expects the corresponding
    CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case
    here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location.
    We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for
    is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier.
    
    2024-04-04  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/114537
            * fold-const.c (native_encode_initializer): Look through
            NON_LVALUE_EXPR if val is INTEGER_CST.
    
            * g++.dg/cpp2a/bit-cast16.C: New test.
    
    (cherry picked from commit 1baec8deb014b8a7da58879a407a4c00cdeb5a09)
Comment 10 Jakub Jelinek 2024-06-20 13:39:50 UTC
Fixed for 11.5 as well.