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,9 @@ def warn_cxx98_compat_longlong : Warning< "'long long' is incompatible with C++98">, InGroup, DefaultIgnore; +def ext_cxx2b_size_t_suffix : Extension< + "size_t suffix for literals is a C++2b extension">, + InGroup; 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; // C++2b's z/uz size_t literals 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,10 @@ //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; @@ -616,13 +617,13 @@ if (!(LangOpts.Half || LangOpts.FixedPoint)) break; if (isIntegerLiteral()) break; // Error for integer constant. - if (isHalf || isFloat || isLong) break; // HH, FH, LH invalid. + if (isHalf || isFloat || isLong || isSizeT) break; // HH, FH, LH invalid. isHalf = true; continue; // Success. case 'f': // FP Suffix for "float" case 'F': if (!isFPConstant) break; // Error for integer constant. - if (isHalf || isFloat || isLong || isFloat128) + if (isHalf || isFloat || isLong || isSizeT || isFloat128) break; // HF, FF, LF, QF invalid. // CUDA host and device may have different _Float16 support, therefore @@ -640,7 +641,7 @@ case 'q': // FP Suffix for "__float128" case 'Q': if (!isFPConstant) break; // Error for integer constant. - if (isHalf || isFloat || isLong || isFloat128) + if (isHalf || isFloat || isLong || isSizeT || isFloat128) break; // HQ, FQ, LQ, QQ invalid. isFloat128 = true; continue; // Success. @@ -654,6 +655,7 @@ case 'L': if (isLong || isLongLong) break; // Cannot be repeated. if (isHalf || isFloat || isFloat128) break; // LH, LF, LQ invalid. + if (isSizeT) break; // LZ is invalid. // Check for long long. The L's need to be adjacent and the same case. if (s[1] == s[0]) { @@ -665,10 +667,19 @@ isLong = true; } continue; // Success. + case 'z': + case 'Z': + if (isSizeT) break; // Cannot be repeated. + if (isLong || isLongLong) break; // ZL and ZLL are invalid. + if (isHalf || isFloat || isFloat128) break; // ZH, ZF, ZQ are invalid. + if (isFPConstant) break; // invalid for floats. + if (MicrosoftInteger) break; // invalid for Microsoft integers. + isSizeT = true; + continue; case 'i': case 'I': if (LangOpts.MicrosoftExt) { - if (isLong || isLongLong || MicrosoftInteger) + if (isLong || isLongLong || isSizeT || MicrosoftInteger) break; if (!isFPConstant) { @@ -727,6 +738,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,11 @@ PP.Diag(PeekTok, diag::ext_c99_longlong); } + // 'z/uz' literals are a C++2b feature. + if (!PP.getLangOpts().CPlusPlus2b && Literal.isSizeT) { + PP.Diag(PeekTok, diag::ext_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,11 @@ Diag(Tok.getLocation(), diag::ext_c99_longlong); } + // 'z/uz' literals are a C++2b feature. + if (!getLangOpts().CPlusPlus2b && Literal.isSizeT) { + Diag(Tok.getLocation(), diag::ext_cxx2b_size_t_suffix); + } + // Get the value in the widest-possible width. unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth(); llvm::APInt ResultVal(MaxWidth, 0); @@ -3901,6 +3906,23 @@ } } + // Check C++2b size_t literals. + if (Literal.isSizeT) { + assert(Ty.isNull() && "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 a 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) { // Are int/unsigned possibilities? unsigned IntSize = Context.getTargetInfo().getIntWidth(); 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,154 @@ +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify -ferror-limit=0 %s + +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/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,80 @@ +// RUN: %clang_cc1 -std=c++2b -Werror=c++2b-extensions -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++20 -Werror=c++2b-extensions -fsyntax-only -verify %s + +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; }; + +#if __cplusplus >= 202101L +// expected-no-diagnostics +#endif + +void SSizeT() { + auto a1 = 1z; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a2 = 1Z; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); +} + +void SizeT() { + auto a1 = 1uz; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a2 = 1uZ; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a3 = 1Uz; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a4 = 1UZ; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a5 = 1zu; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a6 = 1Zu; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a7 = 1zU; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); + + auto a8 = 1ZU; +#if __cplusplus < 202101L + // expected-error@-2 {{size_t suffix for literals is a C++2b extension}} +#endif + static_assert(is_same::value); +}