AntonBikineev created this revision.
AntonBikineev added a reviewer: rsmith.
AntonBikineev requested review of this revision.
Herald added a project: clang.

This adds support for C++2b z/uz suffixes for size_t literals (P0330).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D99456

Files:
  clang/include/clang/Basic/DiagnosticCommonKinds.td
  clang/include/clang/Lex/LiteralSupport.h
  clang/lib/Frontend/InitPreprocessor.cpp
  clang/lib/Lex/LiteralSupport.cpp
  clang/lib/Lex/PPExpressions.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/Lexer/cxx-features.cpp
  clang/test/Lexer/size_t-literal.cpp
  clang/test/SemaCXX/size_t-literal.cpp

Index: clang/test/SemaCXX/size_t-literal.cpp
===================================================================
--- /dev/null
+++ 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 <typename, typename>
+struct is_same { static constexpr bool value = false; };
+
+template <typename T>
+struct is_same<T, T> { 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<decltype(a1), ssize_t>::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<decltype(a2), ssize_t>::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<decltype(a1), size_t>::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<decltype(a2), size_t>::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<decltype(a3), size_t>::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<decltype(a4), size_t>::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<decltype(a5), size_t>::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<decltype(a6), size_t>::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<decltype(a7), size_t>::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<decltype(a8), size_t>::value);
+}
Index: clang/test/Lexer/size_t-literal.cpp
===================================================================
--- /dev/null
+++ 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}}
+  }
+}
Index: clang/test/Lexer/cxx-features.cpp
===================================================================
--- clang/test/Lexer/cxx-features.cpp
+++ 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)
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ 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();
Index: clang/lib/Lex/PPExpressions.cpp
===================================================================
--- clang/lib/Lex/PPExpressions.cpp
+++ 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.
Index: clang/lib/Lex/LiteralSupport.cpp
===================================================================
--- clang/lib/Lex/LiteralSupport.cpp
+++ 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;
Index: clang/lib/Frontend/InitPreprocessor.cpp
===================================================================
--- clang/lib/Frontend/InitPreprocessor.cpp
+++ 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");
Index: clang/include/clang/Lex/LiteralSupport.h
===================================================================
--- clang/include/clang/Lex/LiteralSupport.h
+++ 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
Index: clang/include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -187,6 +187,9 @@
 def warn_cxx98_compat_longlong : Warning<
   "'long long' is incompatible with C++98">,
   InGroup<CXX98CompatPedantic>, DefaultIgnore;
+def ext_cxx2b_size_t_suffix : Extension<
+  "size_t suffix for literals is a C++2b extension">,
+  InGroup<CXX2b>;
 def err_integer_literal_too_large : Error<
   "integer literal is too large to be represented in any %select{signed |}0"
   "integer type">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to