[C++2b] Support size_t literals

This adds support for C++2b's z/uz suffixes for size_t literals (P0330).
This commit is contained in:
Anton Bikineev 2021-03-27 16:27:21 +00:00
parent 9f4022ffeb
commit dc7ebd2cb0
11 changed files with 394 additions and 46 deletions

View File

@ -187,6 +187,17 @@ def ext_cxx11_longlong : Extension<
def warn_cxx98_compat_longlong : Warning<
"'long long' is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def ext_cxx2b_size_t_suffix : ExtWarn<
"'size_t' suffix for literals is a C++2b extension">,
InGroup<CXX2b>;
def warn_cxx20_compat_size_t_suffix : Warning<
"'size_t' suffix for literals is incompatible with C++ standards before "
"C++2b">, InGroup<CXXPre2bCompat>, DefaultIgnore;
def err_cxx2b_size_t_suffix: Error<
"'size_t' suffix for literals is a C++2b feature">;
def err_size_t_literal_too_large: Error<
"%select{signed |}0'size_t' literal is out of range of possible "
"%select{signed |}0'size_t' values">;
def err_integer_literal_too_large : Error<
"integer literal is too large to be represented in any %select{signed |}0"
"integer type">;

View File

@ -63,6 +63,7 @@ public:
bool isUnsigned : 1;
bool isLong : 1; // This is *not* set for long long.
bool isLongLong : 1;
bool isSizeT : 1; // 1z, 1uz (C++2b)
bool isHalf : 1; // 1.0h
bool isFloat : 1; // 1.0f
bool isImaginary : 1; // 1.0i

View File

@ -589,6 +589,9 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
//Builder.defineMacro("__cpp_modules", "201907L");
//Builder.defineMacro("__cpp_using_enum", "201907L");
}
// C++2b features.
if (LangOpts.CPlusPlus2b)
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "201811L");
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");

View File

@ -546,6 +546,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isLong = false;
isUnsigned = false;
isLongLong = false;
isSizeT = false;
isHalf = false;
isFloat = false;
isImaginary = false;
@ -589,6 +590,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// integer constant.
bool isFixedPointConstant = isFixedPointLiteral();
bool isFPConstant = isFloatingLiteral();
bool HasSize = false;
// Loop over all of the characters of the suffix. If we see something bad,
// we break out of the loop.
@ -616,14 +618,17 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
if (!(LangOpts.Half || LangOpts.FixedPoint))
break;
if (isIntegerLiteral()) break; // Error for integer constant.
if (isHalf || isFloat || isLong) break; // HH, FH, LH invalid.
if (HasSize)
break;
HasSize = true;
isHalf = true;
continue; // Success.
case 'f': // FP Suffix for "float"
case 'F':
if (!isFPConstant) break; // Error for integer constant.
if (isHalf || isFloat || isLong || isFloat128)
break; // HF, FF, LF, QF invalid.
if (HasSize)
break;
HasSize = true;
// CUDA host and device may have different _Float16 support, therefore
// allows f16 literals to avoid false alarm.
@ -640,8 +645,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
case 'q': // FP Suffix for "__float128"
case 'Q':
if (!isFPConstant) break; // Error for integer constant.
if (isHalf || isFloat || isLong || isFloat128)
break; // HQ, FQ, LQ, QQ invalid.
if (HasSize)
break;
HasSize = true;
isFloat128 = true;
continue; // Success.
case 'u':
@ -652,8 +658,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
continue; // Success.
case 'l':
case 'L':
if (isLong || isLongLong) break; // Cannot be repeated.
if (isHalf || isFloat || isFloat128) break; // LH, LF, LQ invalid.
if (HasSize)
break;
HasSize = true;
// Check for long long. The L's need to be adjacent and the same case.
if (s[1] == s[0]) {
@ -665,42 +672,54 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isLong = true;
}
continue; // Success.
case 'z':
case 'Z':
if (isFPConstant)
break; // Invalid for floats.
if (HasSize)
break;
HasSize = true;
isSizeT = true;
continue;
case 'i':
case 'I':
if (LangOpts.MicrosoftExt) {
if (isLong || isLongLong || MicrosoftInteger)
if (LangOpts.MicrosoftExt && !isFPConstant) {
// Allow i8, i16, i32, and i64. First, look ahead and check if
// suffixes are Microsoft integers and not the imaginary unit.
uint8_t Bits = 0;
size_t ToSkip = 0;
switch (s[1]) {
case '8': // i8 suffix
Bits = 8;
ToSkip = 2;
break;
if (!isFPConstant) {
// Allow i8, i16, i32, and i64.
switch (s[1]) {
case '8':
s += 2; // i8 suffix
MicrosoftInteger = 8;
break;
case '1':
if (s[2] == '6') {
s += 3; // i16 suffix
MicrosoftInteger = 16;
}
break;
case '3':
if (s[2] == '2') {
s += 3; // i32 suffix
MicrosoftInteger = 32;
}
break;
case '6':
if (s[2] == '4') {
s += 3; // i64 suffix
MicrosoftInteger = 64;
}
break;
default:
break;
case '1':
if (s[2] == '6') { // i16 suffix
Bits = 16;
ToSkip = 3;
}
break;
case '3':
if (s[2] == '2') { // i32 suffix
Bits = 32;
ToSkip = 3;
}
break;
case '6':
if (s[2] == '4') { // i64 suffix
Bits = 64;
ToSkip = 3;
}
break;
default:
break;
}
if (MicrosoftInteger) {
if (Bits) {
if (HasSize)
break;
HasSize = true;
MicrosoftInteger = Bits;
s += ToSkip;
assert(s <= ThisTokEnd && "didn't maximally munch?");
break;
}
@ -727,6 +746,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isLong = false;
isUnsigned = false;
isLongLong = false;
isSizeT = false;
isFloat = false;
isFloat16 = false;
isHalf = false;

View File

@ -321,6 +321,14 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.Diag(PeekTok, diag::ext_c99_longlong);
}
// 'z/uz' literals are a C++2b feature.
if (Literal.isSizeT)
PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus
? PP.getLangOpts().CPlusPlus2b
? diag::warn_cxx20_compat_size_t_suffix
: diag::ext_cxx2b_size_t_suffix
: diag::err_cxx2b_size_t_suffix);
// Parse the integer literal into Result.
if (Literal.GetIntegerValue(Result.Val)) {
// Overflow parsing integer literal.

View File

@ -3867,6 +3867,14 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Diag(Tok.getLocation(), diag::ext_c99_longlong);
}
// 'z/uz' literals are a C++2b feature.
if (Literal.isSizeT)
Diag(Tok.getLocation(), getLangOpts().CPlusPlus
? getLangOpts().CPlusPlus2b
? diag::warn_cxx20_compat_size_t_suffix
: diag::ext_cxx2b_size_t_suffix
: diag::err_cxx2b_size_t_suffix);
// Get the value in the widest-possible width.
unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth();
llvm::APInt ResultVal(MaxWidth, 0);
@ -3901,7 +3909,26 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
}
if (Ty.isNull() && !Literal.isLong && !Literal.isLongLong) {
// Check C++2b size_t literals.
if (Literal.isSizeT) {
assert(!Literal.MicrosoftInteger &&
"size_t literals can't be Microsoft literals");
unsigned SizeTSize = Context.getTargetInfo().getTypeWidth(
Context.getTargetInfo().getSizeType());
// Does it fit in size_t?
if (ResultVal.isIntN(SizeTSize)) {
// Does it fit in ssize_t?
if (!Literal.isUnsigned && ResultVal[SizeTSize - 1] == 0)
Ty = Context.getSignedSizeType();
else if (AllowUnsigned)
Ty = Context.getSizeType();
Width = SizeTSize;
}
}
if (Ty.isNull() && !Literal.isLong && !Literal.isLongLong &&
!Literal.isSizeT) {
// Are int/unsigned possibilities?
unsigned IntSize = Context.getTargetInfo().getIntWidth();
@ -3917,7 +3944,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
// Are long/unsigned long possibilities?
if (Ty.isNull() && !Literal.isLongLong) {
if (Ty.isNull() && !Literal.isLongLong && !Literal.isSizeT) {
unsigned LongSize = Context.getTargetInfo().getLongWidth();
// Does it fit in a unsigned long?
@ -3948,7 +3975,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
// Check long long if needed.
if (Ty.isNull()) {
if (Ty.isNull() && !Literal.isSizeT) {
unsigned LongLongSize = Context.getTargetInfo().getLongLongWidth();
// Does it fit in a unsigned long long?
@ -3965,10 +3992,16 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
}
// If we still couldn't decide a type, we probably have something that
// does not fit in a signed long long, but has no U suffix.
// If we still couldn't decide a type, we either have 'size_t' literal
// that is out of range, or a decimal literal that does not fit in a
// signed long long and has no U suffix.
if (Ty.isNull()) {
Diag(Tok.getLocation(), diag::ext_integer_literal_too_large_for_signed);
if (Literal.isSizeT)
Diag(Tok.getLocation(), diag::err_size_t_literal_too_large)
<< Literal.isUnsigned;
else
Diag(Tok.getLocation(),
diag::ext_integer_literal_too_large_for_signed);
Ty = Context.UnsignedLongLongTy;
Width = Context.getTargetInfo().getLongLongWidth();
}

View File

@ -29,6 +29,12 @@
#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23) (cxx23 == 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx23)
#endif
// --- C++2b features ---
#if check(size_t_suffix, 0, 0, 0, 0, 0, 202011)
#error "wrong value for __cpp_size_t_suffix"
#endif
// --- C++20 features ---
#if check(aggregate_paren_init, 0, 0, 0, 0, 0, 0)

View File

@ -0,0 +1,167 @@
// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %s
#if 1z != 1
#error "z suffix must be recognized by preprocessor"
#endif
#if 1uz != 1
#error "uz suffix must be recognized by preprocessor"
#endif
#if !(-1z < 0)
#error "z suffix must be interpreted as signed"
#endif
#if !(-1uz > 0)
#error "uz suffix must be interpreted as unsigned"
#endif
void ValidSuffix() {
// Decimal literals.
{
auto a1 = 1z;
auto a2 = 1Z;
auto a3 = 1uz;
auto a4 = 1uZ;
auto a5 = 1Uz;
auto a6 = 1UZ;
auto a7 = 1zu;
auto a8 = 1Zu;
auto a9 = 1zU;
auto a10 = 1ZU;
auto a11 = 1'2z;
auto a12 = 1'2Z;
}
// Hexadecimal literals.
{
auto a1 = 0x1z;
auto a2 = 0x1Z;
auto a3 = 0x1uz;
auto a4 = 0x1uZ;
auto a5 = 0x1Uz;
auto a6 = 0x1UZ;
auto a7 = 0x1zu;
auto a8 = 0x1Zu;
auto a9 = 0x1zU;
auto a10 = 0x1ZU;
auto a11 = 0x1'2z;
auto a12 = 0x1'2Z;
}
// Binary literals.
{
auto a1 = 0b1z;
auto a2 = 0b1Z;
auto a3 = 0b1uz;
auto a4 = 0b1uZ;
auto a5 = 0b1Uz;
auto a6 = 0b1UZ;
auto a7 = 0b1zu;
auto a8 = 0b1Zu;
auto a9 = 0b1zU;
auto a10 = 0b1ZU;
auto a11 = 0b1'1z;
auto a12 = 0b1'1Z;
}
// Octal literals.
{
auto a1 = 01z;
auto a2 = 01Z;
auto a3 = 01uz;
auto a4 = 01uZ;
auto a5 = 01Uz;
auto a6 = 01UZ;
auto a7 = 01zu;
auto a8 = 01Zu;
auto a9 = 01zU;
auto a10 = 01ZU;
auto a11 = 0'1z;
auto a12 = 0'1Z;
}
}
void InvalidSuffix() {
// Long.
{
auto a1 = 1lz; // expected-error {{invalid suffix}}
auto a2 = 1lZ; // expected-error {{invalid suffix}}
auto a3 = 1Lz; // expected-error {{invalid suffix}}
auto a4 = 1LZ; // expected-error {{invalid suffix}}
auto a5 = 1zl; // expected-error {{invalid suffix}}
auto a6 = 1Zl; // expected-error {{invalid suffix}}
auto a7 = 1zL; // expected-error {{invalid suffix}}
auto a8 = 1ZL; // expected-error {{invalid suffix}}
auto a9 = 1ulz; // expected-error {{invalid suffix}}
auto a10 = 1ulZ; // expected-error {{invalid suffix}}
auto a11 = 1uLz; // expected-error {{invalid suffix}}
auto a12 = 1uLZ; // expected-error {{invalid suffix}}
auto a13 = 1uzl; // expected-error {{invalid suffix}}
auto a14 = 1uZl; // expected-error {{invalid suffix}}
auto a15 = 1uzL; // expected-error {{invalid suffix}}
auto a16 = 1uZL; // expected-error {{invalid suffix}}
}
// Long long.
{
auto a1 = 1llz; // expected-error {{invalid suffix}}
auto a2 = 1llZ; // expected-error {{invalid suffix}}
auto a3 = 1LLz; // expected-error {{invalid suffix}}
auto a4 = 1LLZ; // expected-error {{invalid suffix}}
auto a5 = 1zll; // expected-error {{invalid suffix}}
auto a6 = 1Zll; // expected-error {{invalid suffix}}
auto a7 = 1zLL; // expected-error {{invalid suffix}}
auto a8 = 1ZLL; // expected-error {{invalid suffix}}
auto a9 = 1ullz; // expected-error {{invalid suffix}}
auto a10 = 1ullZ; // expected-error {{invalid suffix}}
auto a11 = 1uLLz; // expected-error {{invalid suffix}}
auto a12 = 1uLLZ; // expected-error {{invalid suffix}}
auto a13 = 1uzll; // expected-error {{invalid suffix}}
auto a14 = 1uZll; // expected-error {{invalid suffix}}
auto a15 = 1uzLL; // expected-error {{invalid suffix}}
auto a16 = 1uZLL; // expected-error {{invalid suffix}}
}
// Floating point.
{
auto a1 = 0.1z; // expected-error {{invalid suffix}}
auto a2 = 0.1Z; // expected-error {{invalid suffix}}
auto a3 = 0.1uz; // expected-error {{invalid suffix}}
auto a4 = 0.1uZ; // expected-error {{invalid suffix}}
auto a5 = 0.1Uz; // expected-error {{invalid suffix}}
auto a6 = 0.1UZ; // expected-error {{invalid suffix}}
auto a7 = 0.1zu; // expected-error {{invalid suffix}}
auto a8 = 0.1Zu; // expected-error {{invalid suffix}}
auto a9 = 0.1zU; // expected-error {{invalid suffix}}
auto a10 = 0.1ZU; // expected-error {{invalid suffix}}
auto a11 = 0.1fz; // expected-error {{invalid suffix}}
auto a12 = 0.1fZ; // expected-error {{invalid suffix}}
auto a13 = 0.1fuz; // expected-error {{invalid suffix}}
auto a14 = 0.1fuZ; // expected-error {{invalid suffix}}
auto a15 = 0.1fUz; // expected-error {{invalid suffix}}
auto a16 = 0.1fUZ; // expected-error {{invalid suffix}}
auto a17 = 0.1fzu; // expected-error {{invalid suffix}}
auto a18 = 0.1fZu; // expected-error {{invalid suffix}}
auto a19 = 0.1fzU; // expected-error {{invalid suffix}}
auto a110 = 0.1fZU; // expected-error {{invalid suffix}}
}
// Repetitive suffix.
{
auto a1 = 1zz; // expected-error {{invalid suffix}}
auto a2 = 1zZ; // expected-error {{invalid suffix}}
auto a3 = 1Zz; // expected-error {{invalid suffix}}
auto a4 = 1ZZ; // expected-error {{invalid suffix}}
}
}

View File

@ -34,7 +34,7 @@ duration a = 1ns, b = 1us, c = 1ms, d = 1s, e = 1min, f = 1h;
string s = "foo"s;
char error = 'x's; // expected-error {{invalid suffix}} expected-error {{expected ';'}}
int _1z = 1z; // expected-error {{invalid suffix}}
int _1y = 1y; // expected-error {{invalid suffix}}
int _1b = 1b; // expected-error {{invalid digit}}
complex<float> cf1 = 1if, cf2 = 2.if, cf3 = 0x3if;

View File

@ -0,0 +1,99 @@
// RUN: %clang_cc1 -std=c++2b -triple x86_64-linux -Wpre-c++2b-compat -fsyntax-only -verify=cxx2b %s
// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux -fsyntax-only -verify=cxx20 %s
// RUN: %clang_cc1 -std=c++2b -triple i686-linux -fsyntax-only -verify=cxx2b-32 %s
// RUN: %clang_cc1 -x c -std=c11 -fsyntax-only -verify=c11 %s
#ifdef __cplusplus
typedef __SIZE_TYPE__ size_t;
// Assume ptrdiff_t is the signed integer type corresponding to size_t.
typedef __PTRDIFF_TYPE__ ssize_t;
template <typename, typename>
struct is_same { static constexpr bool value = false; };
template <typename T>
struct is_same<T, T> { static constexpr bool value = true; };
void SSizeT() {
auto a1 = 1z;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a1), ssize_t>::value);
auto a2 = 1Z;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a2), ssize_t>::value);
}
void SizeT() {
auto a1 = 1uz;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a1), size_t>::value);
auto a2 = 1uZ;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a2), size_t>::value);
auto a3 = 1Uz;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a3), size_t>::value);
auto a4 = 1UZ;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a4), size_t>::value);
auto a5 = 1zu;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a5), size_t>::value);
auto a6 = 1Zu;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a6), size_t>::value);
auto a7 = 1zU;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a7), size_t>::value);
auto a8 = 1ZU;
// cxx2b-warning@-1 {{'size_t' suffix for literals is incompatible with C++ standards before C++2b}}
// cxx20-warning@-2 {{'size_t' suffix for literals is a C++2b extension}}
static_assert(is_same<decltype(a8), size_t>::value);
}
void oor() {
#if __i386__
(void)3'000'000'000z; // cxx2b-32-error {{signed 'size_t' literal is out of range of possible signed 'size_t' values}}
(void)3'000'000'000uz;
(void)5'000'000'000uz; // cxx2b-32-error {{'size_t' literal is out of range of possible 'size_t' values}}
(void)0x80000000z;
(void)0x80000000uz;
(void)0x180000000uz; //cxx2b-32-error {{'size_t' literal is out of range of possible 'size_t' values}}
#endif
}
#else
void f() {
(void)1z; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1Z; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1uz; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1uZ; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1Uz; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1UZ; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1zu; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1Zu; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1zU; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
(void)1ZU; // c11-error {{'size_t' suffix for literals is a C++2b feature}}
}
#endif

View File

@ -1270,7 +1270,7 @@ C++20, informally referred to as C++2b.
<tr>
<td>Literal suffix <tt>uz</tt>, <tt>z</tt> for <tt>size_t</tt>, <tt>ssize_t</tt></td>
<td><a href="https://wg21.link/p0330r8">P0330R8</a></td>
<td class="none" align="center">No</td>
<td class="unreleased" align="center">Clang 13</td>
</tr>
<!-- Spring 2021 papers -->
<tr>