Skip to content

Commit b390fb1

Browse files
authored
[NFC] Address compiler warnings: C4146 - Use two's complement instead of negation (microsoft#7562)
Replaces uses of the unary - operator on signed integers with the equivalent (sort of, see the details below) expression '~N + 1', assigning the result to an unsigned type. This avoids undefined behavior in edge cases and ensures correctness when certain conditions are met. Details: This transformation is valid when: The signed value N is guaranteed to be negative. The result is stored in an unsigned type that can represent the full range of the signed type (e.g., uint64_t for int64_t). The system uses two's complement representation (as is standard on modern platforms). While -N is undefined for the minimum representable value (e.g., INT64_MIN), the expression ~N + 1 remains well-defined and yields the correct bit pattern. Assigning this result to an appropriately sized unsigned type preserves the intended two's complement interpretation without triggering undefined behavior. Addresses microsoft#7561.
1 parent 23118b9 commit b390fb1

1 file changed

Lines changed: 20 additions & 7 deletions

File tree

lib/Support/raw_ostream.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,18 @@ raw_ostream &raw_ostream::operator<<(unsigned long N) {
134134
}
135135

136136
raw_ostream &raw_ostream::operator<<(long N) {
137+
// A positive signed long has the same value when casted to its unsigned
138+
// counterpart. If its negative, then we'll handle it in the below if block.
139+
unsigned long UN = static_cast<unsigned long>(N);
140+
137141
if (N < 0 && writeBase == 10) {
138142
*this << '-';
139-
// Avoid undefined behavior on LONG_MIN with a cast.
140-
N = -(unsigned long)N;
143+
// Since N is negative and we're storing the result in an unsigned Long,
144+
// we can use the equivalence of -N == ~N + 1 to get the positive value.
145+
UN = ~N + 1UL;
141146
}
142147

143-
return this->operator<<(static_cast<unsigned long>(N));
148+
return this->operator<<(UN);
144149
}
145150

146151
raw_ostream &raw_ostream::operator<<(unsigned long long N) {
@@ -169,13 +174,18 @@ raw_ostream &raw_ostream::operator<<(unsigned long long N) {
169174
}
170175

171176
raw_ostream &raw_ostream::operator<<(long long N) {
177+
// A positive signed long has the same value when casted to its unsigned
178+
// counterpart. If its negative, then we'll handle it in the below if block.
179+
unsigned long long UN = static_cast<unsigned long long>(N);
180+
172181
if (N < 0 && writeBase == 10) {
173182
*this << '-';
174-
// Avoid undefined behavior on INT64_MIN with a cast.
175-
N = -(unsigned long long)N;
183+
// Since N is negative and we're storing the result in an unsigned Long,
184+
// we can use the equivalence of -N == ~N + 1 to get the positive value.
185+
UN = ~N + 1ULL;
176186
}
177187

178-
return this->operator<<(static_cast<unsigned long long>(N));
188+
return this->operator<<(UN);
179189
}
180190

181191
// HLSL Change Starts - Generalize non-base10 printing.
@@ -470,7 +480,10 @@ raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
470480
char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
471481
char *CurPtr = EndPtr;
472482
bool Neg = (FN.DecValue < 0);
473-
uint64_t N = Neg ? -static_cast<uint64_t>(FN.DecValue) : FN.DecValue;
483+
// If the value is negative, and because we are storing the result of the ~
484+
// operation in an unsigned value, we can use the equivalence of
485+
// -N == ~N + 1 to get the positive value of the negative number
486+
uint64_t N = Neg ? (~FN.DecValue + 1UL) : FN.DecValue;
474487
while (N) {
475488
*--CurPtr = '0' + char(N % 10);
476489
N /= 10;

0 commit comments

Comments
 (0)