Skip to content

Fix PassMode::Cast ABI argument lowering - #1659

Open
1sgtpepper wants to merge 4 commits into
rust-lang:mainfrom
1sgtpepper:fix-cast-abi-padding
Open

1sgtpepper wants to merge 4 commits into
rust-lang:mainfrom
1sgtpepper:fix-cast-abi-padding

Conversation

@1sgtpepper

@1sgtpepper 1sgtpepper commented May 31, 2026 •

Copy link
Copy Markdown

Fixes #1477.

Updates PassMode::Cast lowering to pass rounded full ABI units for integer rest fields, matching CastTarget's rounded ABI layout. Casted arguments now use a zero-initialized ABI-sized scratch slot before loading ABI parameters, preventing padding from being read from the Rust-layout representation.

The previously waived SingleVariantUnion::conv_c::repr_c ABI-cafe case is now enabled on macOS AArch64.

Verification:

  • cargo fmt --check
  • cargo check --locked
  • full CI matrix (23 passed; release skipped)

Comment thread src/abi/pass_mode.rs Outdated
@bjorn3

bjorn3 commented May 31, 2026

Copy link
Copy Markdown
Member

It would be nice if we had a concrete test for a case that goes wrong without this change.

@rustbot

This comment was marked as outdated.

@rustbot

This comment has been minimized.

@rustbot

rustbot commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@1sgtpepper

Copy link
Copy Markdown
Author

@bjorn3 rebased, enabled the ABI-cafe regression, and CI is green. Could you re-review when convenient?

@bjorn3 bjorn3 left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the late review.

View changes since this review

Comment thread src/abi/pass_mode.rs
cast.rest.total.bytes() % cast.rest.unit.size.bytes(),
)
assert_ne!(cast.rest.unit.size, Size::ZERO);
if cast.rest.total.bytes() % cast.rest.unit.size.bytes() != 0 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if cast.rest.total.bytes() % cast.rest.unit.size.bytes() != 0 {
if !cast.rest.total.bytes().is_multiple_of(cast.rest.unit.size.bytes()) {

Comment thread src/abi/pass_mode.rs
let scratch =
fx.create_stack_slot(u32::try_from(slot_size).unwrap(), u32::try_from(slot_align).unwrap());
// A partial final integer is passed in a full register. Initialize every byte that can be
// loaded as an ABI parameter before copying the value bytes into the scratch slot.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? Cranelift doesn't have any concept of undef bytes. And I would expect the callee to just ignore the uninitialized part.

Comment thread src/abi/pass_mode.rs
true,
MemFlagsData::new(),
);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this extra copy? force_stack already writes to the stack if the argument isn't already on the stack. If this is for the case where the abi_param_size is larger than the argument type, I think a better option would be to special case the last load to use the smaller type and zero-extend it instead.

Comment thread src/abi/pass_mode.rs
let ptr = fx.create_stack_slot(
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
// It may also be smaller for example when the type is a wrapper around an integer with a
// larger alignment than the integer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you preserve this comment?

Comment thread src/abi/pass_mode.rs
Comment on lines +270 to +273
let abi_param_size = abi_params_size(&abi_params);
let cast_align = cast.align(fx).bytes();
let layout_size = layout.size.bytes();
let layout_align = layout.align.bytes();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these variables could be inlined without making things less readable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Apply fixes from "https://github.com/rust-lang/rust/pull/122619" to cg_clif

3 participants