Skip to content

Disallow implicit composed-base upcasts; require explicit cast#1205

Merged
marcauberer merged 1 commit into
mainfrom
fix/explicit-upcast
Jun 14, 2026
Merged

Disallow implicit composed-base upcasts; require explicit cast#1205
marcauberer merged 1 commit into
mainfrom
fix/explicit-upcast

Conversation

@marcauberer

Copy link
Copy Markdown
Member

What changed

  • Disallow the implicit struct-to-composed-base upcast (a struct composing another struct as its first field is no longer implicitly convertible to that base in assignments/arguments/returns). Interface upcasts are unaffected.
  • Allow the explicit cast<Base*>(derived) / cast<Interface*>(struct) in a safe (non-unsafe) context, but only for the upcast direction. The IR generator advances the pointer to the embedded subobject via GEPs, following the first-field composition chain transitively and correctly skipping any vtable prefix added by an implemented interface. Down/sibling pointer casts still require unsafe.
  • Migrate the bootstrap compiler (parser, block allocator, generic type) to the explicit cast / explicit composed-field access.

Why

The implicit composed-base upcast was silent and layout-dependent. When a struct also implements an interface, a vtable pointer is placed in front of the composed base, so the base no longer sits at offset 0 — the implicitly emitted identity pointer copy then aliased the vtable region (garbage reads / segfault). Making the conversion explicit keeps pointer identity visible, and routing it through cast<> lets the compiler emit the correct, vtable-aware pointer adjustment.

How it was validated

  • spicetest --gtest_filter='TypeCheckerTests.*:IRGeneratorTests.*:BootstrapCompilerTests.*' — all pass except the pre-existing BootstrapCompilerTests.standaloneCommonUtilTest (local version/build-string golden mismatch, unrelated).
  • New success test irgenerator/structs/success-explicit-composed-base-cast (cout + IR snapshot) verifies the GEP adjustments: single-level cast skips the vtable (field index 1), two-level cast emits two GEPs (Leaf -> Derived -> Base), and an interface cast stays at offset 0.
  • New error test typechecker/structs/error-no-implicit-composed-base-upcast asserts the implicit upcast is rejected.
  • Manually confirmed a downcast still requires unsafe.

Follow-up / known limitations

  • Down/sibling struct-pointer casts remain unsafe by design (no runtime check).
  • The commonUtil bootstrap test failure is pre-existing and environmental.

🤖 Generated with Claude Code

A struct that composes another struct as its first field was implicitly
convertible to that base (and to implemented interfaces) in assignments,
arguments and returns. This conversion was silent and layout-dependent:
when the struct also implements an interface, a vtable pointer is placed
in front of the composed base, so the base no longer sits at offset 0 and
the implicitly emitted identity pointer copy was wrong.

Disallow the implicit struct-to-composed-base upcast entirely (interface
upcasts are unaffected). Instead, allow the explicit conversion
'cast<Base*>(derived)' / 'cast<Interface*>(struct)' in a safe (non-unsafe)
context for the upcast direction only. The IR generator advances the
pointer to the embedded subobject via GEPs, following the first-field
composition chain transitively and correctly skipping any vtable prefix.
Down/sibling pointer casts still require an unsafe block.

Migrate the bootstrap compiler (parser, block allocator, generic type) to
the explicit cast / explicit composed-field access accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@marcauberer marcauberer requested a review from a team as a code owner June 14, 2026 21:42
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions github-actions Bot added tests Contains changes to the test cases bootstrap Change regarding the bootstrap compiler labels Jun 14, 2026
@marcauberer marcauberer merged commit a8e3a2f into main Jun 14, 2026
8 checks passed
@marcauberer marcauberer deleted the fix/explicit-upcast branch June 14, 2026 21:57
@marcauberer marcauberer added this to the 0.27.0 milestone Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bootstrap Change regarding the bootstrap compiler size/L tests Contains changes to the test cases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant