https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126185
Bug ID: 126185
Summary: [C++26] std::meta::exception not caught with template
for in dependent context
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: Eriksander5252Principal at hotmail dot com
Target Milestone: ---
Severity:
major
Description:
When using std::meta::members_of() with std::meta::access_context::current()
inside a template for loop, GCC throws an uncaught std::meta::exception instead
of either compiling successfully or producing a clear diagnostic.
The same issue occurs when using std::meta::enumerators_of() (the dedicated
function for enumerations) - in that case, the compiler reports that the
expression is not a constant expression because it refers to a result of
'operator new'.
Both failures occur only when the type is dependent (^^typePers inside a
template).
When using a concrete type (e.g., ^^ERRORCODE) outside a template, the code
works
as expected.
Environment:
- GCC 16.1.0 (x86-64)
- Flags: -std=c++26 -freflection
- Platform: Godbolt.org
Minimal Example:
#include <meta>
#include <type_traits>
#include <iostream>
#include <expected>
#include <string>
#include <cstdint>
enum class ERRORCODE : std::uint16_t {
SUCCESS = 0x00,
FAIL = 0x01,
WRONG_TYPE = 0x02
};
template<typename T1, typename T2>
constexpr std::expected<T1, ERRORCODE> SomarValores(const T1& value_1, const
T2& value_2) {
if constexpr ((std::is_integral_v<T1> || std::is_floating_point_v<T1>) &&
(std::is_integral_v<T2> || std::is_floating_point_v<T2>)) {
return value_1 + value_2;
} else {
return std::unexpected(ERRORCODE::FAIL);
}
}
template<typename TipoDesconhecido>
constexpr auto InterpretarErro(const TipoDesconhecido& err) {
auto error = err.error_or(ERRORCODE::SUCCESS);
using typePers = typename TipoDesconhecido::error_type;
// This loop triggers the uncaught exception
template for (constexpr auto member : std::meta::members_of(^^typePers,
std::meta::access_context::current())) {
if (error == [:member:])
return std::meta::identifier_of(member);
}
return "UNKNOWN_ERROR";
}
int main() {
std::cout << "ErroR: " << InterpretarErro(SomarValores(true, 1.0f)) <<
std::endl;
return 0;
}
Error Message:
With members_of:
error: uncaught exception of type 'std::meta::exception';
'what()': 'neither complete class type nor namespace'
With enumerators_of:
error: 'std::meta::enumerators_of(^^typePers)' is not a constant expression
because it refers to a result of 'operator new'
Full output (members_of):
<source>: In instantiation of 'constexpr auto InterpretarErro(const
TipoDesconhecido&) [with TipoDesconhecido = std::expected<bool, ERRORCODE>]':
<source>:40:46: required from here
40 | std::cout << "ErroR: " << InterpretarErro(SomarValores(true, 1.0f))
<< std::endl;
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:32:5: error: uncaught exception of type 'std::meta::exception';
'what()': 'neither complete class type nor namespace'
32 | template for (constexpr auto member :
std::meta::members_of(^^typePers, std::meta::access_context::current())) {
| ^~~~~~~~
Compiler returned: 1
Full output (enumerators_of):
<source>: In instantiation of 'constexpr auto InterpretarErro(const
TipoDesconhecido&) [with TipoDesconhecido = std::expected<bool, ERRORCODE>]':
<source>:40:163: required from here
40 | std::cout << "ErroR: " << InterpretarErro(SomarValores(true, 1.0f))
<< std::endl;
|
~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:32:90: error: 'std::meta::enumerators_of(^^typePers)' is not a
constant expression because it refers to a result of 'operator new'
32 | template for (constexpr auto member :
std::meta::enumerators_of(^^typePers)) {
|
^~~~~~~~
In file included from
/cefs/38/383ad2f84cbd57a52fd68bbe_consolidated/compilers_c++_x86_gcc_16.1.0/include/c++/16.1.0/string:46:
/cefs/38/383ad2f84cbd57a52fd68bbe_consolidated/compilers_c++_x86_gcc_16.1.0/include/c++/16.1.0/bits/allocator.h:203:52:
note: allocated here
203 | return static_cast<_Tp*>(::operator new(__n));
| ~~~~~~~~~~~~~~^~~~~
Compiler returned: 1
Expected Behavior:
1. The code should compile successfully (since the type is a complete
enumeration)
2. Alternatively, GCC should produce a clear diagnostic explaining why the
reflection operation is invalid
3. GCC should NOT throw an uncaught exception or produce misleading internal
errors
Actual Behavior:
GCC throws an uncaught std::meta::exception with a generic message when using
members_of,
or an internal "not a constant expression" error when using enumerators_of.
Additional Information:
- The function InterpretarErro is meant to iterate over all enumerators of the
enum type
ERRORCODE using reflection, compare each enumerator value to an error code,
and return
the enumerator's name as a string. This should be possible with
std::meta::members_of
or std::meta::enumerators_of, as proposed in P2996.
- The problem appears only when the type is dependent (^^typePers inside a
template).
- When using a concrete type (e.g., ^^ERRORCODE) outside a template, the
reflection works correctly.
- Both std::meta::members_of and std::meta::enumerators_of fail in this
context.
- This might be related to bugs 125519, 124215, or 125770, which also deal with
uncaught exceptions in the reflection implementation.
I searched for possible duplicates and found bugs 125519, 124215, and 125770,
which deal with similar uncaught exceptions in the reflection implementation,
but they do not cover the specific case of using members_of/enumerators_of in
a dependent context. I also checked bugs 125900 and others listed, but they
are unrelated to this issue.