Skip to content

Conditional operators that result in bit-fields do not correctly preserve the width #169197

@Halalaluyafail3

Description

@Halalaluyafail3

The following program demonstrates the issue:

#include<iostream>
int main(){
    struct{unsigned u:1;}u{};
    auto a=(0?throw 0:u.u)-1;
    std::cout<<(a<0)<<'\n';//should print 1, Clang prints 0
    unsigned char b{0?throw 0:u.u};//incorrectly considered narrowing
    auto c=(1?u.u:u.u)-1;
    std::cout<<(c<0)<<'\n';//should print 1, Clang prints 0
    unsigned char d{1?u.u:u.u};//incorrectly considered narrowing
}

The two expressions (0?throw 0:u.u) and (1?u.u:u.u) should intuitively both be equivalent to u.u, but Clang appears to forget about the widths of the bit-fields in these cases and assumes that they have the full range of unsigned. #14181 also still exists and makes it impossible to use any non-constant condition here.

GCC has the same issues with propagating the bit-field with in these two expressions https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122811. MSVC too, but because it fails to implement promotion and narrowing checks with bit-fields correctly. For example with MSVC +u.u has the type unsigned and unsigned char e{u.u}; is considered narrowing.

See also CWG3134. The standard doesn't clearly define the width in the cases where bit-field and non-bit-field expressions are used together, or two bit-field expressions of different widths are used together. The most reasonable behavior in these cases seems to be to take the maximum of the two widths, where the width of a non-bit-field is the width of its type. Though it may be worth waiting for the issue to be resolved before making a decision.

Metadata

Metadata

Assignees

No one assigned

    Labels

    c++clang:frontendLanguage frontend issues, e.g. anything involving "Sema"

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions