Skip to content

Commit 52d71b6

Browse files
committed
c++: DR2627, Bit-fields and narrowing conversions [PR94058]
This DR (https://cplusplus.github.io/CWG/issues/2627.html) says that even if we are converting from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, it's not narrowing if "the source is a bit-field whose width w is less than that of its type (or, for an enumeration type, its underlying type) and the target type can represent all the values of a hypothetical extended integer type with width w and with the same signedness as the original type". DR 2627 PR c++/94058 PR c++/104392 gcc/cp/ChangeLog: * typeck2.cc (check_narrowing): Don't warn if the conversion isn't narrowing as per DR 2627. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2627.C: New test. * g++.dg/cpp0x/Wnarrowing22.C: New test. * g++.dg/cpp2a/spaceship-narrowing1.C: New test. * g++.dg/cpp2a/spaceship-narrowing2.C: New test.
1 parent 4d24159 commit 52d71b6

File tree

5 files changed

+134
-0
lines changed

5 files changed

+134
-0
lines changed

gcc/cp/typeck2.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,18 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain,
10121012
if (TREE_CODE (ftype) == ENUMERAL_TYPE)
10131013
/* Check for narrowing based on the values of the enumeration. */
10141014
ftype = ENUM_UNDERLYING_TYPE (ftype);
1015+
/* Undo convert_bitfield_to_declared_type (STRIP_NOPS isn't enough). */
1016+
tree op = init;
1017+
while (CONVERT_EXPR_P (op))
1018+
op = TREE_OPERAND (op, 0);
1019+
/* Core 2627 says that we shouldn't warn when "the source is a bit-field
1020+
whose width w is less than that of its type (or, for an enumeration
1021+
type, its underlying type) and the target type can represent all the
1022+
values of a hypothetical extended integer type with width w and with
1023+
the same signedness as the original type". */
1024+
if (is_bitfield_expr_with_lowered_type (op)
1025+
&& TYPE_PRECISION (TREE_TYPE (op)) < TYPE_PRECISION (ftype))
1026+
ftype = TREE_TYPE (op);
10151027
if ((tree_int_cst_lt (TYPE_MAX_VALUE (type),
10161028
TYPE_MAX_VALUE (ftype))
10171029
|| tree_int_cst_lt (TYPE_MIN_VALUE (ftype),

gcc/testsuite/g++.dg/DRs/dr2627.C

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// DR 2627 - Bit-fields and narrowing conversions
2+
// { dg-do compile { target c++20 } }
3+
4+
#include <compare>
5+
6+
struct C {
7+
long long i : 8;
8+
};
9+
10+
void f() {
11+
C x{1}, y{2};
12+
x.i <=> y.i;
13+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// DR 2627 - Bit-fields and narrowing conversions
2+
// PR c++/94058
3+
// { dg-do compile { target c++11 } }
4+
// { dg-options "-Wno-error=narrowing" }
5+
6+
using int64_t = __INT64_TYPE__;
7+
using int32_t = __INT32_TYPE__;
8+
9+
struct A {
10+
int64_t i1 : __CHAR_BIT__;
11+
int64_t i2 : sizeof (int32_t) * __CHAR_BIT__ - 1;
12+
int64_t i3 : sizeof (int32_t) * __CHAR_BIT__;
13+
int64_t i4 : sizeof (int32_t) * __CHAR_BIT__ + 1;
14+
int64_t i5 : sizeof (int64_t) * __CHAR_BIT__ - 1;
15+
int64_t i6 : sizeof (int64_t) * __CHAR_BIT__;
16+
} a;
17+
18+
int32_t i1{a.i1};
19+
int32_t i2{a.i2};
20+
int32_t i3{a.i3};
21+
int32_t i4{a.i4}; // { dg-warning "narrowing conversion" }
22+
int32_t i5{a.i5}; // { dg-warning "narrowing conversion" }
23+
int32_t i6{a.i6}; // { dg-warning "narrowing conversion" }
24+
25+
struct B {
26+
bool b1 : sizeof (bool) * __CHAR_BIT__;
27+
bool b2 : sizeof (bool);
28+
} b;
29+
30+
signed char b1{b.b1};
31+
signed char b2{b.b2};
32+
33+
enum E : int64_t { E1 };
34+
35+
struct C {
36+
E e1 : __CHAR_BIT__;
37+
E e2 : sizeof (int32_t) * __CHAR_BIT__ - 1;
38+
E e3 : sizeof (int32_t) * __CHAR_BIT__;
39+
E e4 : sizeof (int32_t) * __CHAR_BIT__ + 1;
40+
E e5 : sizeof (int64_t) * __CHAR_BIT__ - 1;
41+
E e6 : sizeof (int64_t) * __CHAR_BIT__;
42+
} c;
43+
44+
int32_t e1{c.e1};
45+
int32_t e2{c.e2};
46+
int32_t e3{c.e3};
47+
int32_t e4{c.e4}; // { dg-warning "narrowing conversion" }
48+
int32_t e5{c.e5}; // { dg-warning "narrowing conversion" }
49+
int32_t e6{c.e6}; // { dg-warning "narrowing conversion" }
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// PR c++/94058
2+
// { dg-do compile { target c++20 } }
3+
4+
namespace std {
5+
struct strong_ordering {
6+
int _v;
7+
constexpr strong_ordering (int v) :_v(v) {}
8+
constexpr operator int (void) const { return _v; }
9+
static const strong_ordering less;
10+
static const strong_ordering equal;
11+
static const strong_ordering greater;
12+
};
13+
constexpr strong_ordering strong_ordering::less = -1;
14+
constexpr strong_ordering strong_ordering::equal = 0;
15+
constexpr strong_ordering strong_ordering::greater = 1;
16+
}
17+
18+
struct A {
19+
long i : 48;
20+
auto operator <=> (const A&) const = default;
21+
};
22+
23+
struct B {
24+
long i : 8;
25+
auto operator <=> (const B&) const = default;
26+
};
27+
28+
void
29+
f (B b)
30+
{
31+
(void) int{b.i}; // Not narrowing anymore
32+
b.i <=> b.i; // Not narrowing anymore
33+
b <=> b; // Not deleted anymore
34+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// PR c++/104392
2+
// { dg-do compile { target c++20 } }
3+
4+
namespace std {
5+
struct strong_ordering {
6+
int _v;
7+
constexpr strong_ordering (int v) :_v(v) {}
8+
constexpr operator int (void) const { return _v; }
9+
static const strong_ordering less;
10+
static const strong_ordering equal;
11+
static const strong_ordering greater;
12+
};
13+
constexpr strong_ordering strong_ordering::less = -1;
14+
constexpr strong_ordering strong_ordering::equal = 0;
15+
constexpr strong_ordering strong_ordering::greater = 1;
16+
}
17+
18+
struct A {
19+
unsigned int a:5;
20+
};
21+
22+
constexpr std::strong_ordering
23+
operator<=>(const A & left, const A & right)
24+
{
25+
return left.a <=> right.a;
26+
}

0 commit comments

Comments
 (0)