Skip to content

Commit a70d729

Browse files
authored
[flang] Avoid left shifts of negative signed values (#84786)
Shifting left a signed, negative value is an undefined behavior in C++. This was detected by the undefined behavior sanitizer.
1 parent 42ee286 commit a70d729

File tree

1 file changed

+10
-2
lines changed

1 file changed

+10
-2
lines changed

flang/include/flang/Evaluate/integer.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ class Integer {
150150
}
151151
}
152152
} else {
153-
INT signExtension{-(n < 0)};
153+
// Avoid left shifts of negative signed values (that's an undefined
154+
// behavior in C++).
155+
auto signExtension{std::make_unsigned_t<INT>(n < 0)};
156+
signExtension = ~signExtension + 1;
154157
static_assert(nBits >= partBits);
155158
if constexpr (nBits > partBits) {
156159
signExtension <<= nBits - partBits;
@@ -474,7 +477,12 @@ class Integer {
474477
SINT n = ToUInt<UINT>();
475478
constexpr std::size_t maxBits{CHAR_BIT * sizeof n};
476479
if constexpr (bits < maxBits) {
477-
n |= -(n >> (bits - 1)) << bits;
480+
// Avoid left shifts of negative signed values (that's an undefined
481+
// behavior in C++).
482+
auto u{std::make_unsigned_t<SINT>(ToUInt())};
483+
u = (u >> (bits - 1)) << (bits - 1); // Get the sign bit only.
484+
u = ~u + 1; // Negate top bits if not 0.
485+
n |= static_cast<SINT>(u);
478486
}
479487
return n;
480488
}

0 commit comments

Comments
 (0)