Skip to content

Commit dcec224

Browse files
authored
Lex: add support for i128 and ui128 suffixes (#130993)
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 3b5842c commit dcec224

File tree

5 files changed

+43
-13
lines changed

5 files changed

+43
-13
lines changed

clang/docs/ReleaseNotes.rst

+4
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ Windows Support
363363
which makes ``offsetof`` provided by Microsoft's ``<stddef.h>`` to be defined
364364
correctly. (#GH59689)
365365

366+
- Clang now can process the `i128` and `ui128` integeral suffixes when MSVC
367+
extensions are enabled. This allows for properly processing ``intsafe.h`` in
368+
the Windows SDK.
369+
366370
LoongArch Support
367371
^^^^^^^^^^^^^^^^^
368372

clang/include/clang/Lex/LiteralSupport.h

+2-2
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

+9-5
Original file line numberDiff line numberDiff line change
@@ -1073,8 +1073,8 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
10731073
continue;
10741074
case 'i':
10751075
case 'I':
1076-
if (LangOpts.MicrosoftExt && !isFPConstant) {
1077-
// Allow i8, i16, i32, and i64. First, look ahead and check if
1076+
if (LangOpts.MicrosoftExt && s + 1 < ThisTokEnd && !isFPConstant) {
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;
@@ -1084,19 +1084,23 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
10841084
ToSkip = 2;
10851085
break;
10861086
case '1':
1087-
if (s[2] == '6') { // i16 suffix
1087+
if (s + 2 < ThisTokEnd && s[2] == '6') { // i16 suffix
10881088
Bits = 16;
10891089
ToSkip = 3;
1090+
} else if (s + 3 < ThisTokEnd && s[2] == '2' &&
1091+
s[3] == '8') { // i128 suffix
1092+
Bits = 128;
1093+
ToSkip = 4;
10901094
}
10911095
break;
10921096
case '3':
1093-
if (s[2] == '2') { // i32 suffix
1097+
if (s + 2 < ThisTokEnd && s[2] == '2') { // i32 suffix
10941098
Bits = 32;
10951099
ToSkip = 3;
10961100
}
10971101
break;
10981102
case '6':
1099-
if (s[2] == '4') { // i64 suffix
1103+
if (s + 2 < ThisTokEnd && s[2] == '4') { // i64 suffix
11001104
Bits = 64;
11011105
ToSkip = 3;
11021106
}

clang/lib/Sema/SemaExpr.cpp

+12-4
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

+16-2
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,30 @@ __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;
17-
__complex double c2 = 1.0i;
16+
__complex double c1 = 1i; // GNU extension
17+
__complex double c2 = 1.0i; // GNU extension
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

26+
#define INT128_MAX 170141183460469231731687303715884105727i128
27+
2528
void a(void) {
29+
#if __SIZEOF_INT128__
30+
__int128 j = UINT128_MAX;
31+
__int128 k = INT128_MAX;
32+
#else
33+
int j = UINT128_MAX;
34+
// expected-warning@-1{{implicit conversion from 'unsigned __int128' to 'int' changes value from 340282366920938463463374607431768211455 to -1}}
35+
// expected-error@-2{{integer literal is too large to be represented in any integer type}}
36+
int k = INT128_MAX;
37+
// expected-warning@-1{{implicit conversion from '__int128' to 'int' changes value from 170141183460469231731687303715884105727 to -1}}
38+
// expected-error@-2{{integer literal is too large to be represented in any signed integer type}}
39+
#endif
2640
unsigned long long m = ULLONG_MAX;
2741
unsigned int n = UINT;
2842
unsigned short s = USHORT;

0 commit comments

Comments
 (0)