https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98288
Bug ID: 98288 Summary: Accidental equality of classes templated by pointer to local static constant of templated function Product: gcc Version: 7.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: matthieum.147192 at gmail dot com Target Milestone: --- Based on https://stackoverflow.com/q/65306562/147192. The behavior of GCC (and Clang) is inconsistent (between compile-time and run-time), however it is unclear to me whether the inconsistency is conforming with the C++17 standard or not. The following reduced program is expected to return 0 (invoking g++ with -std=c++17): template <typename, typename> struct is_same { static constexpr bool value = false; }; template <typename T> struct is_same<T, T> { static constexpr bool value = true; }; template <typename T, typename U> static constexpr bool is_same_v = is_same<T, U>::value; using uintptr_t = unsigned long long; template <int const* I> struct Parameterized { int const* member; }; template <typename T> auto create() { static constexpr int const I = 2; return Parameterized<&I>{ &I }; } int main() { auto one = create<short>(); auto two = create<int>(); if (is_same_v<decltype(one), decltype(two)>) { return reinterpret_cast<uintptr_t>(one.member) == reinterpret_cast<uintptr_t>(two.member) ? 1 : 2; } return 0; } Yet, on all versions of GCC where it compiles (from 7.2 onwards), and for all optimization levels (from -O0 to -O3), it returns 2, indicating: - That `one` and `two` have the same type -- which according to 17.4 [temp.type] should mean that they point to the same object. - Yet they point to different objects -- there are two instances of `create<T>()::I`, one for `T = short` and one for `T = int`. The assembly listing clearly contains 2 different instances of `create<T>()::I`. Notes: - If `I` is initialized with `= sizeof(T)`, instead, then the program returns 0 as expected. - Clang (up to 11.0) fails to compile the program with -O0 (the linker failing to find a `create()::I` variable), and otherwise produces the same result as GCC with -O1 to -O3.