[clang][reflection] Handle entity-proxy reflections in member metafunctions and NTTP mangling - #291
Open
Cfretz244 wants to merge 1 commit into
Open
Conversation
…ctions and NTTP mangling
With -fentity-proxy-reflection, members_of enumerates using-shadow
declarations as ReflectionKind::EntityProxy, so proxy reflections flow
directly into ordinary consteval member queries and, as info NTTPs, into
the Itanium mangler. Several consumers still treated that kind as
llvm_unreachable("proxies should already have been unwrapped"), turning
valid code into ICEs:
- Six metafunctions in ExprConstantMeta.cpp crashed when asked of a
proxy: is_constructor, is_destructor, is_special_member_function,
is_static_member, is_enumerable_type, has_complete_definition. Each
now answers false, consistent with how the surrounding kind
predicates already classify proxies (a shadow declaration is never
itself one of these; the underlying entity's properties are available
through underlying_entity_of). The remaining unreachable proxy arms
were probed NOT reachable from user code: identifier_of /
has_identifier / source_location_of pre-unwrap via MaybeUnproxy,
substitute's dispatcher unwraps template arguments before
TArgFromReflection, and reflect_invoke through a proxy fails
gracefully as not-a-constant-expression.
- mangleReflection's EntityProxy case encoded the proxy by mangling the
shadow declaration's NAME (mangleNameWithAbiTags), with two defects.
An operator-named shadow (e.g. `using OB::operator*;`, the shape
absl::StatusOr<T> hits via `using StatusOr::OperatorBase::operator*;`)
crashed outright: mangleUnqualifiedName casts the decl to FunctionDecl
to disambiguate the operator name, and a UsingShadowDecl is not one
(cast<> assertion). And one using-declarator over an overload set
introduces several same-named shadows whose proxies all mangled
identically -- "definition with same mangled name" at best, a silent
linkonce_odr fold at worst. The mangler now encodes the proxy's TARGET
declaration kind-aware (constructors/destructors via GlobalDecl,
functions/variables/fields via mangle(), enum constants as literals,
types via mangleCanonicalTypeName, else the source name), keeping the
'a' tag so a proxy-of-X reflection stays a distinct template argument
from a declaration-of-X reflection.
Test: entity-proxy-member-queries.pass.cpp covers all six metafunctions
on proxies of a member function, static member function, static data
member, field, type alias, and nested class (each call ICEd before),
plus the mangler shapes: an operator shadow and a four-overload value()
shadow set from a class template specialization as info NTTPs, asserting
every proxy instantiation is distinct from its siblings and from its
underlying declaration's instantiation.
Fixes llvm#290.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #290.
Problem
With
-fentity-proxy-reflection,members_ofenumerates using-shadow declarations asReflectionKind::EntityProxy, so proxy reflections flow directly into ordinary consteval member queries and, asstd::meta::infoNTTPs, into the Itanium mangler. Several consumers still treated that kind asllvm_unreachable("proxies should already have been unwrapped"), turning valid code into ICEs (see #290 for self-contained reproducers and crash signatures).Fix
clang/lib/AST/ExprConstantMeta.cpp— six metafunctions crashed when asked of a proxy:is_constructor,is_destructor,is_special_member_function,is_static_member,is_enumerable_type,has_complete_definition. Each now answersfalse, consistent with how the surrounding kind predicates already classify proxies (a shadow declaration is never itself one of these; the underlying entity's properties are available throughunderlying_entity_of). The remaining unreachable proxy arms were probed NOT reachable from user code (identifier_of/has_identifier/source_location_ofpre-unwrap viaMaybeUnproxy;substitute's dispatcher unwraps template arguments beforeTArgFromReflection;reflect_invokethrough a proxy fails gracefully as not-a-constant-expression) and are left as-is.clang/lib/AST/ItaniumMangle.cpp—mangleReflection'sEntityProxycase encoded the proxy by mangling the shadow declaration's NAME (mangleNameWithAbiTags), with two defects: an operator-named shadow (e.g.using OB::operator*;, the shapeabsl::StatusOr<T>hits viausing StatusOr::OperatorBase::operator*;) crashed outright (mangleUnqualifiedNamecasts the decl toFunctionDeclto disambiguate the operator name —cast<>assertion), and one using-declarator over an overload set introduced several same-named shadows whose proxies all mangled identically ("definition with same mangled name" at best, a silent linkonce_odr fold at worst). The mangler now encodes the proxy's TARGET declaration kind-aware (ctors/dtors viaGlobalDecl, functions/variables/fields viamangle(), enum constants as literals, types viamangleCanonicalTypeName, else the source name), keeping theatag so a proxy-of-X reflection stays a distinct template argument from a declaration-of-X reflection.Test
libcxx/test/std/experimental/reflection/entity-proxy-member-queries.pass.cpp(new): a consteval sweep of all six metafunctions over proxies of every member kind — member function, static member function, static data member, field, type alias, nested class (each call ICEd before the fix) — plus runtime distinctness assertions for proxy NTTPs: an operator shadow and a four-overloadvalue()shadow set from a class template specialization, asserting every proxy instantiation is distinct from its siblings and from its underlying declaration's instantiation (static_assertcannot catch a mangling fold).Validation
837da39eb88c(currentp2996tip; applies cleanly).ExprConstantMeta.cpp:5240/5391/5435/4563/4830/4789); the operator-shadow NTTP asserts inmangleUnqualifiedName; the overload-set NTTP errors withdefinition with same mangled name '_Z5probeIMaN1SIiE5valueE$EEiv'; the new test ICEs.clang/test/Reflection: 15/16 both at base and with the fix — identical results; the one failure (splice-exprs.cpp) is pre-existing at base and unrelated.absl::StatusOr(the field trigger: itsusing StatusOr::OperatorBase::value/operator*/operator->;re-exports) and nlohmann/json — all green.🤖 Generated with Claude Code