Second take on https://reviews.llvm.org/rGfb1e90ef07fec0d64a05c0b6d41117a5ea3e8344, which was pulled out because it broke GCC-based builds. The offending code was:
constexpr uint64_t specifierBit(char C) { return 1 << (C - 0x40); }
The issue is that the shift expression has type int, but the shift value has range 0..<0x40. Shifting (int)1 by more than 30 is undefined behavior.
With GCC, this manifested with test failures, and when sanitizers were enabled, with sanitizer traps. However, because the function is constexpr, Clang chose to evaluate it at compile-time even when when its execution was undefined. (Both Clang and GCC reject calls to specifierBit and its specifierMask caller when using constinit.) Unfortunately, somehow, the result was good enough to pass all tests when built with clang; and since the undefined behavior was evaluated at build time, UBSan wouldn't catch it.
I have reproduced the problem with a GCC build of LLVM and verified that this change fixes it:
constexpr uint64_t specifierBit(char C) { return (uint64_t)1 << (C - 0x40); }
Can you add an explanation for what the number 0x40 means or why it was chosen?