This adds support for C++2b's z/uz suffixes for size_t literals (P0330).
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">;
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
//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");
isLong = false;
isUnsigned = false;
isLongLong = false;
+ isSizeT = false;
isHalf = false;
isFloat = false;
isImaginary = false;
// 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.
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.
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':
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]) {
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;
}
isLong = false;
isUnsigned = false;
isLongLong = false;
+ isSizeT = false;
isFloat = false;
isFloat16 = false;
isHalf = false;
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.
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);
}
}
- 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();
}
// 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?
}
// 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?
}
}
- // 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();
}
#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)
--- /dev/null
+// 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}}
+ }
+}
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;
--- /dev/null
+// 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
<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>