Skip to content

Add arg splat experiment initial tuple impl#153697

Open
teor2345 wants to merge 11 commits intorust-lang:mainfrom
teor2345:fn-arg-splat-experiment
Open

Add arg splat experiment initial tuple impl#153697
teor2345 wants to merge 11 commits intorust-lang:mainfrom
teor2345:fn-arg-splat-experiment

Conversation

@teor2345
Copy link
Copy Markdown
Contributor

@teor2345 teor2345 commented Mar 11, 2026

View all comments

This PR is part of the argument splatting lang experiment, and FFI overloading / C++ interop project goals:

Example code using existing unstable features:

Discussion of implementation strategy:

The PR is the initial implementation of the feature:

  • splat incomplete feature gate
  • #[splat] attribute on function arguments
  • #[splat] function parameter check at THIR level
  • splatted MIR lowering (as tupled arguments)
  • feature gate and UI tests for item type filtering, non-splattable arguments, splattable tuples, generics, and the "overloading at home" example
    • about half the diff (1100 lines) is tests and test output

Once this PR merges, we can add further functionality, then test it out in interop tools.

Further Work

Out of Scope for this PR

  • Change codegen to de-tuple caller and callee
  • Better diagnostics
  • Full support for splatted function pointer arguments

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Mar 11, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Mar 11, 2026

r? @JohnTitor

rustbot has assigned @JohnTitor.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 69 candidates
  • Random selection from 16 candidates

@rust-log-analyzer

This comment has been minimized.

Comment thread compiler/rustc_builtin_macros/src/splat.rs Outdated
@JohnTitor
Copy link
Copy Markdown
Member

It should be better for someone on https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/On.20overloading/with/573924937 to review this, @oli-obk could you take over?

@oli-obk oli-obk assigned oli-obk and unassigned JohnTitor Mar 11, 2026
@oli-obk oli-obk added the S-blocked Status: Blocked on something else such as an RFC or other implementation work. label Mar 12, 2026
@oli-obk
Copy link
Copy Markdown
Contributor

oli-obk commented Mar 12, 2026

Let's wait for the ongoing discussion on Zulip to figure out whether we need to have a proc macro, an AST manipulating attribute (like define_opaque), or just a normal attribute

@teor2345 teor2345 marked this pull request as draft March 13, 2026 06:49
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 13, 2026
@teor2345 teor2345 force-pushed the fn-arg-splat-experiment branch from 89102bf to c784a57 Compare March 16, 2026 07:35
@rustbot rustbot added the A-attributes Area: Attributes (`#[…]`, `#![…]`) label Mar 16, 2026
Comment thread compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs Outdated
Comment thread compiler/rustc_hir/src/target.rs
Comment thread tests/ui/splat/splat-non-function.rs Outdated
@teor2345 teor2345 force-pushed the fn-arg-splat-experiment branch from c784a57 to 2d9e563 Compare March 20, 2026 01:37
@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) labels Mar 20, 2026
@teor2345

This comment was marked as outdated.

@rust-log-analyzer

This comment has been minimized.

teor2345

This comment was marked as resolved.

@rust-log-analyzer

This comment has been minimized.

@rustbot rustbot added the T-clippy Relevant to the Clippy team. label Mar 20, 2026
@teor2345 teor2345 force-pushed the fn-arg-splat-experiment branch from d83e6d9 to d4229d6 Compare April 26, 2026 22:36
@rust-log-analyzer

This comment has been minimized.

@teor2345
Copy link
Copy Markdown
Contributor Author

The perf issues above are resolved by a minor refactor, but I'd like to merge them as separate PRs/commits, just in case we need to go back to the original code for testing (or further refactors).

See the perf analysis here, overall this PR plus the refactor in #155852 results in an 0.24% primary benchmark improvement, with no primary regressions:
#155852 (comment)

Comment thread .gitignore Outdated
@teor2345 teor2345 force-pushed the fn-arg-splat-experiment branch from 482f842 to 84cab65 Compare April 28, 2026 01:19
@teor2345

This comment was marked as outdated.

Comment thread compiler/rustc_attr_parsing/src/attributes/splat.rs Outdated

// Multiple splatted arguments are invalid: we can't know which arguments go in each splat.
if splatted_arg_indexes.len() > 1 {
self.dcx().emit_err(errors::DuplicateSplattedArgs { spans: splatted_spans.clone() });
Copy link
Copy Markdown
Contributor

@oli-obk oli-obk Apr 28, 2026

Choose a reason for hiding this comment

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

I'm somewhat worried that due to these errors being non-blocking for the rest of the compiler, that it's possible to cause weird ICEs, but that's nothing new wrt most of the ast validation checks.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I did my best to provide sensible defaults/substitutions on error.

Specifically, c_variadic gets priority, then the first splatted argument. Every other splat generates an error, then gets ignored in later stages.

Comment thread compiler/rustc_ast_lowering/src/delegation.rs Outdated
/// Which function argument is splatted into multiple arguments in callers, if any?
/// Splatting functions with `u16::MAX` arguments is not supported, see `FnSigKind` for
/// details.
splatted: u16,
Copy link
Copy Markdown
Contributor

@oli-obk oli-obk Apr 28, 2026

Choose a reason for hiding this comment

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

far future possibility: make newtype_index allow for types other than u32 to be used for the storage. Then we could just encode a new ArgIdx type that inherently forbids u16::MAX (and maybe a few others at the upper limit to allow for more niche opts)

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

also 😭 why do we allow more than 250 arguments on functions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It might make the compiler faster to limit it to 256 arguments, I wonder if that would break any code.

At least we test for u16::MAX arguments. It used to panic, see #88577.

/// Create a new FnDeclKind with no implicit self, no lifetime elision, and no C-style variadic argument.
/// Marker index for "no splatted argument".
/// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`.
const NO_SPLATTED_ARG_INDEX: u16 = u16::MAX;
Copy link
Copy Markdown
Contributor

@oli-obk oli-obk Apr 28, 2026

Choose a reason for hiding this comment

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

can these all be linked somehow by depending on them in the argument? Or are there two of them who don't have the others' crate in their dependency list?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried, but there's no common dependency crate to put the constant in.

Some of these instances will disappear in #155852 as part of a perf refactor (if it still gives good perf after recent nearby changes).

Comment thread compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs Outdated
Comment thread compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs Outdated
Comment thread compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs Outdated
let ocx_error =
ocx.eq(&origin, self.param_env, calee_tuple_type, new_tupled_type);
if let Err(ocx_error) = ocx_error {
struct_span_code_err!(
Copy link
Copy Markdown
Contributor

@oli-obk oli-obk Apr 28, 2026

Choose a reason for hiding this comment

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

is this error reachable? if so, please add a test specifically for it

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if it's reachable, and I don't know how to create a test for this. It seems like other errors happen first, but there might be a way to trigger it. I left a FIXME in the code.

I made a bunch of related fixes and tests while trying to test this:

  • fixed some invalid method splatted self argument handling which resulted in an ICE (there's a test for it now)
  • cleaned up some unnecessary diagnostic function arguments
  • some error messages were outdated (splat is supported on any argument) so I updated them
  • use the argument span in some error messages, rather than using the argument number
  • add tests for generics that might be tuples, and for unresolvable/ambiguous types

Comment thread compiler/rustc_const_eval/src/const_eval/type_info.rs Outdated
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 28, 2026
@rust-bors

This comment has been minimized.

};

// Split the rust-call tupled arguments off.
// FIXME(splat): un-tuple splatted arguments in codegen, for performance
Copy link
Copy Markdown
Member

@RalfJung RalfJung Apr 28, 2026

Choose a reason for hiding this comment

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

Why "for performance"? If this follows the RustCall approach, the ABI requires untupling for correctness. I am confused by this comment.

View changes since the review

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.

Oh I see, I think I got confused by "splatted MIR lowering and tupling". This doesn't actually do anything on the ABI level yet, it passes things as structs.

zihan0822 pushed a commit to zihan0822/rust-clippy that referenced this pull request Apr 30, 2026
Refactor FnDecl and FnSig non-type fields into a new wrapper type





#### Why this Refactor?

This PR is part of an initial cleanup for the [arg splat experiment](rust-lang/rust#153629), but it's a useful refactor by itself.

It refactors the non-type fields of `FnDecl`, `FnSig`, and `FnHeader` into a new packed wrapper types, based on this comment in the `splat` experiment PR:
rust-lang/rust#153697 (comment)

It also refactors some common `FnSig` creation settings into their own methods. I did this instead of creating a struct with defaults.

#### Relationship to `splat` Experiment

I don't think we can use functional struct updates (`..default()`) to create `FnDecl` and `FnSig`, because we need the bit-packing for the `splat` experiment.

Bit-packing will avoid breaking "type is small" assertions for commonly used types when `splat` is added.
This PR packs these types:
- ExternAbi: enum + `unwind` variants (38) -> 6 bits
- ImplicitSelfKind: enum variants (5) -> 3 bits
- lifetime_elision_allowed, safety, c_variadic: bool -> 1 bit

#### Minor Changes

Fixes some typos, and applies rustfmt to clippy files that got skipped somehow.
@teor2345 teor2345 force-pushed the fn-arg-splat-experiment branch from 84cab65 to fdd4be9 Compare May 5, 2026 10:41
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 5, 2026

The reflection data structures are tied exactly to the implementation
in the compiler. Make sure to also adjust rustc_const_eval/src/const_eval/type_info.rs

cc @oli-obk

Copy link
Copy Markdown
Contributor Author

@teor2345 teor2345 left a comment

Choose a reason for hiding this comment

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

This should be ready for another review.

I've rebased this on the latest main, trying to minimise the number of rebase changes to earlier commits. The rebase was tricky, so there are some fixes which should be squashed into earlier commits, and some code might not quite be in the nicest/clearest commit.

The last 5 commits are revisions from the latest reviews, the detailed commit message says which commit they revise.

View changes since this review

/// Which function argument is splatted into multiple arguments in callers, if any?
/// Splatting functions with `u16::MAX` arguments is not supported, see `FnSigKind` for
/// details.
splatted: u16,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It might make the compiler faster to limit it to 256 arguments, I wonder if that would break any code.

At least we test for u16::MAX arguments. It used to panic, see #88577.

/// Create a new FnDeclKind with no implicit self, no lifetime elision, and no C-style variadic argument.
/// Marker index for "no splatted argument".
/// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`.
const NO_SPLATTED_ARG_INDEX: u16 = u16::MAX;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried, but there's no common dependency crate to put the constant in.

Some of these instances will disappear in #155852 as part of a perf refactor (if it still gives good perf after recent nearby changes).

splatted: Option<u16>,
args_len: usize,
) -> Result<Self, SplattedArgIndexError> {
if let Some(splatted_arg_index) = splatted {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I wasn't sure about this either.

I felt like having the option was clearer in callers, and tried to keep the sentinel value as an internal implementation detail which never appears outside the low-level bit-packing code. That way, providing u16::MAX as the splatted argument is easy to error on.

But I don't mind dropping the option, it's unlikely this case will be encountered in practice.
What do you think?

Comment thread compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs Outdated
let ocx_error =
ocx.eq(&origin, self.param_env, calee_tuple_type, new_tupled_type);
if let Err(ocx_error) = ocx_error {
struct_span_code_err!(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if it's reachable, and I don't know how to create a test for this. It seems like other errors happen first, but there might be a way to trigger it. I left a FIXME in the code.

I made a bunch of related fixes and tests while trying to test this:

  • fixed some invalid method splatted self argument handling which resulted in an ICE (there's a test for it now)
  • cleaned up some unnecessary diagnostic function arguments
  • some error messages were outdated (splat is supported on any argument) so I updated them
  • use the argument span in some error messages, rather than using the argument number
  • add tests for generics that might be tuples, and for unresolvable/ambiguous types


// Multiple splatted arguments are invalid: we can't know which arguments go in each splat.
if splatted_arg_indexes.len() > 1 {
self.dcx().emit_err(errors::DuplicateSplattedArgs { spans: splatted_spans.clone() });
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I did my best to provide sensible defaults/substitutions on error.

Specifically, c_variadic gets priority, then the first splatted argument. Every other splat generates an error, then gets ignored in later stages.

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 5, 2026

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.

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

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) perf-regression Performance regression. S-blocked Status: Blocked on something else such as an RFC or other implementation work. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. T-rust-analyzer Relevant to the rust-analyzer team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.