diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -187,6 +187,17 @@ def warn_cxx98_compat_longlong : Warning< "'long long' is incompatible with C++98">, InGroup, DefaultIgnore; +def ext_cxx2b_size_t_suffix : ExtWarn< + "'size_t' suffix for literals is a C++2b extension">, + InGroup; +def warn_cxx20_compat_size_t_suffix : Warning< + "'size_t' suffix for literals is incompatible with C++ standards before " + "C++2b">, InGroup, 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">; diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -63,6 +63,7 @@ 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 diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -589,6 +589,9 @@ //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"); diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -546,6 +546,7 @@ isLong = false; isUnsigned = false; isLongLong = false; + isSizeT = false; isHalf = false; isFloat = false; isImaginary = false; @@ -589,6 +590,7 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ isLong = false; isUnsigned = false; isLongLong = false; + isSizeT = false; isFloat = false; isFloat16 = false; isHalf = false; diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp --- a/clang/lib/Lex/PPExpressions.cpp +++ b/clang/lib/Lex/PPExpressions.cpp @@ -321,6 +321,14 @@ 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. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3867,6 +3867,14 @@ 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 @@ } } - 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) + Ty = Context.getSizeType(); + else if (ResultVal[SizeTSize - 1] == 0) + Ty = Context.getSignedSizeType(); + Width = SizeTSize; + } + } + + if (Ty.isNull() && !Literal.isLong && !Literal.isLongLong && + !Literal.isSizeT) { // Are int/unsigned possibilities? unsigned IntSize = Context.getTargetInfo().getIntWidth(); @@ -3917,7 +3944,7 @@ } // 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 @@ } // 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 @@ } } - // 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 literal that does not fit in a signed long + // long, but 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(); } diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp --- a/clang/test/Lexer/cxx-features.cpp +++ b/clang/test/Lexer/cxx-features.cpp @@ -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) diff --git a/clang/test/Lexer/size_t-literal.cpp b/clang/test/Lexer/size_t-literal.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Lexer/size_t-literal.cpp @@ -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}} + } +} diff --git a/clang/test/SemaCXX/cxx1y-user-defined-literals.cpp b/clang/test/SemaCXX/cxx1y-user-defined-literals.cpp --- a/clang/test/SemaCXX/cxx1y-user-defined-literals.cpp +++ b/clang/test/SemaCXX/cxx1y-user-defined-literals.cpp @@ -34,7 +34,7 @@ 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 cf1 = 1if, cf2 = 2.if, cf3 = 0x3if; diff --git a/clang/test/SemaCXX/size_t-literal.cpp b/clang/test/SemaCXX/size_t-literal.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/size_t-literal.cpp @@ -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 +struct is_same { static constexpr bool value = false; }; + +template +struct is_same { 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::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::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::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::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::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::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::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::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::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::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; //cxx2b-32-error {{signed 'size_t' literal is out of range of possible signed 'size_t' values}} + (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 diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1270,7 +1270,7 @@ Literal suffix uz, z for size_t, ssize_t P0330R8 - No + Clang 13