https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99460
Bug ID: 99460 Summary: [C++20] Template with complex non-type argument re-uses different specialisation Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: gcc.mexon at spamgourmet dot com Target Milestone: --- See below example of a Builder class. It is templated with an array of two booleans, and includes member functions that return an instance of a different specialisation of the same template. However, the different specialisations appear to get mixed up. The intended behaviour is that both usages in main() result in a Builder with both booleans set. In fact the result is that the second usage only has one boolean set. However, removing the first usage resolves the problem, indicating that the problem is caused by unrelated specialisations interfering with each other. I checked this with gcc 9.3.0 and gcc 10.2.0. I also tried compiling from git, version 11.0.1 change a18ebd6c439. Command line was "g++ -Wall --std=c++2a builder.cpp". More discussion and examples [on StackOverflow](https://stackoverflow.com/questions/66520012/c-20-stdarray-as-non-type-template-argument-reshuffles-elements/66520217#66520217). It seems likely that this is a known problem, in which case this bug report can be closed as a duplicate. But I would like a tracking bug to attach to the StackOverflow question. ---- #include <array> #include <cassert> using Flags = std::array<bool, 2>; template<Flags flags = Flags{}> class Builder { public: Builder() { } auto SetFirst() { constexpr auto new_flags = SetFieldFlag<0>(); Builder<new_flags> new_builder; return new_builder; } auto SetSecond() { constexpr auto new_flags = SetFieldFlag<1>(); Builder<new_flags> new_builder; return new_builder; } Flags GetFlags() const { return flags; } private: template<int field> static constexpr auto SetFieldFlag() { auto new_flags = flags; std::get<field>(new_flags) = true; return new_flags; } }; int main() { auto flags1 = Builder().SetFirst().SetSecond().GetFlags(); assert(flags1[0]); assert(flags1[1]); auto flags2 = Builder().SetSecond().SetFirst().GetFlags(); assert(flags2[0]); assert(flags2[1]); return 0; }