-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Description
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.