https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126361

            Bug ID: 126361
           Summary: [C++26][reflection] std::meta::reflect_constant throws
                    meta::exception when target class has a copy
                    constructor that reads a member of the source object
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: painthingy at gmail dot com
  Target Milestone: ---

Version: g++ (Compiler-Explorer-Build-gcc--binutils-2.44) 16.1.0
Target: x86_64-linux-gnu
Command line: -std=c++26 -freflection -Wall -Wextra -O0

Description:
std::meta::reflect_constant on a class-type argument will invoke the class's
copy constructor as part of constant evaluation.
GCC throws std::meta::exception from reflect_constant if the copy constructor's
body reads a member of the source object being copied, even though the exact
same copy constructor works fine when GCC reaches it through a different path
(constant_of/substitute on a static-storage-duration variable template
specialization, Part 2 below).
*std::addressof(x) must be equivalent to x; whether this read is accepted
should not depend on which internal code path led to the copy constructor being
evaluated. Since Part 2 shows GCC can form a reflected constant of this exact
type using this exact copy constructor, the failure in Part 1 isn't a general
restriction on reflecting class types with this kind of constructor — it looks
like a bug specific to how GCC evaluates reads for objects local to the
currently-executing constant expression.
Clang's experimental P2996 branch accepts both programs unmodified:
clang version 21.0.0git (https://github.com/Bloomberg/clang-p2996
7220baffd57ea5b0f8cf59bee494dd5b7cc2b748)
flags: -std=c++26 -fparameter-reflection -freflection-latest -O0
Part 1 — minimal failing case ( https://godbolt.org/z/ddaeT1h66):
```cpp
#include <meta>
#include <memory>
struct Probe {
    int value = 42;
    constexpr Probe() = default;
    constexpr Probe(const Probe& other) {
        value = (std::addressof(other.value) == nullptr) + 42;
        [[maybe_unused]] auto unused = *std::addressof(other.value);  // remove
-> GCC accepts
    }
};
consteval {
    std::meta::reflect_constant(Probe{});
}
int main() {}
```
GCC rejects this with:
error: uncaught exception of type 'std::meta::exception'; 'what()':
'reflect_constant failed'
raised on the std::meta::reflect_constant(Probe{}); line. Deleting the marked
unused line (keeping the addressof(...) == nullptr comparison) makes GCC accept
the program.
Part 2 — same type, same copy constructor, Probe reached via
constant_of/substitute instead of directly — GCC accepts
(https://godbolt.org/z/EKhdvnEY7):
```cpp
#include <meta>
#include <memory>
struct Probe {
    int value;
    constexpr Probe() : value(42) {}
    constexpr Probe(int v) : value(v) {}
    constexpr Probe(const Probe& other) {
        value = (std::addressof(other.value) == nullptr) + 42;
        [[maybe_unused]] auto unused = *std::addressof(other.value);
    }
};
// A variable template whose specializations are Probe objects.
template<auto... Args>
constexpr auto storage = Probe{Args...};
// make a static-storage-duration variable then get the constant reflection
consteval std::meta::info reflect_probe(const Probe& p) {
    return constant_of(
        substitute(^^storage, {std::meta::reflect_constant(p.value)}));
}
template<Probe V>
    requires (V.value == 42)
struct sink {};
consteval {
    auto c = reflect_probe(Probe{42});
    [[maybe_unused]] auto h = substitute(^^sink, {c});  // fine on GCC
}
int main() {}
```
This compiles cleanly under the same flags, with the identical copy constructor
body (including the *std::addressof(...) read).
Expected result: Part 1 should be accepted, matching Clang and matching GCC's
own behavior in Part 2.
Actual result: Part 1 is rejected with the meta::exception shown above.

Other cases:
https://godbolt.org/z/fjbc4M9Tz
https://godbolt.org/z/6vzjj5znY

Reply via email to