Skip to content

Commit 79ad6e9

Browse files
committed
Lex: add support for i128 and ui128 suffixes
Microsoft's compiler supports an extension for 128-bit literals. This is referenced in `intsafe.h` which is included transitievly. When building with modules, the literal parsing causes a failure due to the missing support for the extension. To alleviate this issue, support parsing this literal, especially now that there is the BitInt extension. Take the opportunity to tighten up the code slightly by ensuring that we do not access out-of-bounds characters when lexing the token.
1 parent ab22f65 commit 79ad6e9

File tree

4 files changed

+33
-11
lines changed

4 files changed

+33
-11
lines changed

clang/include/clang/Lex/LiteralSupport.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ class NumericLiteralParser {
8282
bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk
8383
bool isBitInt : 1; // 1wb, 1uwb (C23) or 1__wb, 1__uwb (Clang extension in C++
8484
// mode)
85-
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
86-
85+
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, i64, or
86+
// i128.
8787

8888
bool isFixedPointLiteral() const {
8989
return (saw_period || saw_exponent) && saw_fixed_point_suffix;

clang/lib/Lex/LiteralSupport.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,29 +1074,35 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
10741074
case 'i':
10751075
case 'I':
10761076
if (LangOpts.MicrosoftExt && !isFPConstant) {
1077-
// Allow i8, i16, i32, and i64. First, look ahead and check if
1077+
// Allow i8, i16, i32, i64, and i128. First, look ahead and check if
10781078
// suffixes are Microsoft integers and not the imaginary unit.
10791079
uint8_t Bits = 0;
10801080
size_t ToSkip = 0;
1081+
if (s + 1 >= ThisTokEnd)
1082+
break;
10811083
switch (s[1]) {
10821084
case '8': // i8 suffix
10831085
Bits = 8;
10841086
ToSkip = 2;
10851087
break;
10861088
case '1':
1087-
if (s[2] == '6') { // i16 suffix
1089+
if (s + 2 < ThisTokEnd && s[2] == '6') { // i16 suffix
10881090
Bits = 16;
10891091
ToSkip = 3;
1092+
} else if (s + 3 < ThisTokEnd && s[2] == '2' &&
1093+
s[3] == '8') { // i128 suffix
1094+
Bits = 128;
1095+
ToSkip = 4;
10901096
}
10911097
break;
10921098
case '3':
1093-
if (s[2] == '2') { // i32 suffix
1099+
if (s + 2 < ThisTokEnd && s[2] == '2') { // i32 suffix
10941100
Bits = 32;
10951101
ToSkip = 3;
10961102
}
10971103
break;
10981104
case '6':
1099-
if (s[2] == '4') { // i64 suffix
1105+
if (s + 2 < ThisTokEnd && s[2] == '4') { // i64 suffix
11001106
Bits = 64;
11011107
ToSkip = 3;
11021108
}

clang/lib/Sema/SemaExpr.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3924,10 +3924,18 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
39243924
// to get the integer value from an overly-wide APInt is *extremely*
39253925
// expensive, so the naive approach of assuming
39263926
// llvm::IntegerType::MAX_INT_BITS is a big performance hit.
3927-
unsigned BitsNeeded =
3928-
Literal.isBitInt ? llvm::APInt::getSufficientBitsNeeded(
3929-
Literal.getLiteralDigits(), Literal.getRadix())
3930-
: Context.getTargetInfo().getIntMaxTWidth();
3927+
unsigned BitsNeeded = Context.getTargetInfo().getIntMaxTWidth();
3928+
if (Literal.isBitInt)
3929+
BitsNeeded = llvm::APInt::getSufficientBitsNeeded(
3930+
Literal.getLiteralDigits(), Literal.getRadix());
3931+
if (Literal.MicrosoftInteger) {
3932+
if (Literal.MicrosoftInteger == 128 &&
3933+
!Context.getTargetInfo().hasInt128Type())
3934+
PP.Diag(Tok.getLocation(), diag::err_integer_literal_too_large)
3935+
<< Literal.isUnsigned;
3936+
BitsNeeded = Literal.MicrosoftInteger;
3937+
}
3938+
39313939
llvm::APInt ResultVal(BitsNeeded, 0);
39323940

39333941
if (Literal.GetIntegerValue(ResultVal)) {

clang/test/Lexer/ms-extensions.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,24 @@ __int64 w = 0x43ui64;
1313
__int64 z = 9Li64; // expected-error {{invalid suffix}}
1414
__int64 q = 10lli64; // expected-error {{invalid suffix}}
1515

16-
__complex double c1 = 1i;
16+
__complex double c1 = 1i; // expected-error {{invalid suffix}}
1717
__complex double c2 = 1.0i;
1818
__complex float c3 = 1.0if;
1919

20+
#define UINT128_MAX 0xffffffffffffffffffffffffffffffffui128
2021
#define ULLONG_MAX 0xffffffffffffffffui64
2122
#define UINT 0xffffffffui32
2223
#define USHORT 0xffffui16
2324
#define UCHAR 0xffui8
2425

2526
void a(void) {
27+
#if __SIZEOF_INT128__
28+
__int128 j = UINT128_MAX;
29+
#else
30+
int j = UINT128_MAX;
31+
// expected-warning@-1{{implicit conversion from 'unsigned __int128' to 'int' changes value from 340282366920938463463374607431768211455 to -1}}
32+
// expected-error@-2{{integer literal is too large to be represented in any integer type}}
33+
#endif
2634
unsigned long long m = ULLONG_MAX;
2735
unsigned int n = UINT;
2836
unsigned short s = USHORT;

0 commit comments

Comments
 (0)