]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Redefine __from_chars_alnum_to_val's table
authorPatrick Palka <ppalka@redhat.com>
Thu, 20 Oct 2022 14:30:31 +0000 (10:30 -0400)
committerPatrick Palka <ppalka@redhat.com>
Thu, 20 Oct 2022 14:30:31 +0000 (10:30 -0400)
After the C++23 constexpr <charconv> patch r13-3313-g378a0f1840e694 we
have some modules testsuite regressions:

  FAIL: g++.dg/modules/xtreme-header-4_b.C -std=c++2b (test for excess errors)
  FAIL: g++.dg/modules/xtreme-header_b.C -std=c++2b (test for excess errors)

Like with PR105297, the cause seems to be the deduced type of __table
resolving ahead of time to a local class type, which trips up modules.
And unfortunately that PR's minimal workaround of making __tables's
initializer value dependent doesn't help in this case.

So this patch works around this by avoiding using a local class for the
table type.  And I suppose we should use a static data member to define
the table once for all dialects (including C++14) instead of having to
define it twice in C++23 mode (once as a static local variable and again
as a variable template for sake of constexpr evaluation).

libstdc++-v3/ChangeLog:

* include/std/charconv (__detail::__from_chars_alnum_to_val_table):
Redefine as a class template containing the members type, value and
_S_make_table.  Don't use a local class as the table type.
(__detail::__table): Remove.
(__detail::__from_chars_alnum_to_val): Adjust after the above.

libstdc++-v3/include/std/charconv

index 7aefdd3298c3d85d47a4c931326b80b0c8c6aa89..a65fbedc21cbd22ab7302b7c0b6f4f1c015f0137 100644 (file)
@@ -413,30 +413,36 @@ namespace __detail
       return true;
     }
 
-  // Construct and return a lookup table that maps 0-9, A-Z and a-z to their
-  // corresponding base-36 value and maps all other characters to 127.
-  constexpr auto
-  __from_chars_alnum_to_val_table()
-  {
-    constexpr unsigned char __lower_letters[27] = "abcdefghijklmnopqrstuvwxyz";
-    constexpr unsigned char __upper_letters[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    struct { unsigned char __data[1u << __CHAR_BIT__] = {}; } __table;
-    for (auto& __entry : __table.__data)
-      __entry = 127;
-    for (int __i = 0; __i < 10; ++__i)
-      __table.__data['0' + __i] = __i;
-    for (int __i = 0; __i < 26; ++__i)
+  template<bool _DecOnly>
+    struct __from_chars_alnum_to_val_table
+    {
+      struct type { unsigned char __data[1u << __CHAR_BIT__] = {}; };
+
+      // Construct and return a lookup table that maps 0-9, A-Z and a-z to their
+      // corresponding base-36 value and maps all other characters to 127.
+      static constexpr type
+      _S_make_table()
       {
-       __table.__data[__lower_letters[__i]] = 10 + __i;
-       __table.__data[__upper_letters[__i]] = 10 + __i;
+       constexpr unsigned char __lower_letters[27] = "abcdefghijklmnopqrstuvwxyz";
+       constexpr unsigned char __upper_letters[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       type __table;
+       for (auto& __entry : __table.__data)
+         __entry = 127;
+       for (int __i = 0; __i < 10; ++__i)
+         __table.__data['0' + __i] = __i;
+       for (int __i = 0; __i < 26; ++__i)
+         {
+           __table.__data[__lower_letters[__i]] = 10 + __i;
+           __table.__data[__upper_letters[__i]] = 10 + __i;
+         }
+       return __table;
       }
-    return __table;
-  }
 
-#if __cpp_lib_constexpr_charconv
-  template<bool _DecOnly>
-    inline constexpr auto __table = __from_chars_alnum_to_val_table();
-#endif
+      // This initializer is made superficially dependent in order
+      // to prevent the compiler from wastefully constructing the
+      // table ahead of time when it's not needed.
+      static constexpr type value = (_DecOnly, _S_make_table());
+    };
 
   // If _DecOnly is true: if the character is a decimal digit, then
   // return its corresponding base-10 value, otherwise return a value >= 127.
@@ -449,16 +455,7 @@ namespace __detail
       if _GLIBCXX17_CONSTEXPR (_DecOnly)
        return static_cast<unsigned char>(__c - '0');
       else
-       {
-#if __cpp_lib_constexpr_charconv
-         if (std::__is_constant_evaluated())
-           return __table<_DecOnly>.__data[__c];
-#endif
-         // This initializer is deliberately made dependent in order to work
-         // around modules bug PR105322.
-         static constexpr auto __table = (_DecOnly, __from_chars_alnum_to_val_table());
-         return __table.__data[__c];
-       }
+       return __from_chars_alnum_to_val_table<_DecOnly>::value.__data[__c];
     }
 
   /// std::from_chars implementation for integers in a power-of-two base.