Skip to content

Add arg splat experiment initial tuple impl#153697

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

Add arg splat experiment initial tuple impl#153697
teor2345 wants to merge 8 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 and tupling
  • 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 (900 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
rust-bors Bot pushed a commit that referenced this pull request Apr 24, 2026
Add arg splat experiment initial tuple impl
@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Apr 24, 2026

☀️ Try build successful (CI)
Build commit: a8930df (a8930df882af409d5db502c7a23b6523079a5cd9, parent: 36ba2c7712052d731a7082d0eba5ed3d9d56c133)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (a8930df): comparison URL.

Overall result: ❌ regressions - please read:

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

Next, please: If you can, justify the regressions found in this try perf run in writing along with @rustbot label: +perf-regression-triaged. If not, fix the regressions and do another perf run. Neutral or positive results will clear the label automatically.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
0.2% [0.2%, 0.2%] 3
Regressions ❌
(secondary)
0.4% [0.1%, 1.1%] 12
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.2% [0.2%, 0.2%] 3

Max RSS (memory usage)

Results (primary -0.7%, secondary -2.3%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
1.2% [1.2%, 1.2%] 1
Improvements ✅
(primary)
-0.7% [-0.7%, -0.7%] 1
Improvements ✅
(secondary)
-5.7% [-5.7%, -5.7%] 1
All ❌✅ (primary) -0.7% [-0.7%, -0.7%] 1

Cycles

Results (secondary -4.1%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-4.1% [-4.9%, -3.3%] 2
All ❌✅ (primary) - - 0

Binary size

Results (primary 0.1%, secondary 0.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.1% [0.0%, 0.2%] 84
Regressions ❌
(secondary)
0.2% [0.0%, 0.7%] 59
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.1% [0.0%, 0.2%] 84

Bootstrap: 490.512s -> 491.535s (0.21%)
Artifact size: 394.34 MiB -> 394.41 MiB (0.02%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Apr 24, 2026
@teor2345

This comment was marked as resolved.

@teor2345 teor2345 force-pushed the fn-arg-splat-experiment branch from 7e8fef2 to d83e6d9 Compare April 26, 2026 22:23
@rust-log-analyzer

This comment has been minimized.

@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
Copy link
Copy Markdown
Contributor Author

I've done a rough split of the code into separate commits, and dropped the unrelated changes.

Comment on lines +13 to +14
// FIXME(splat): only allow MacroCall if the macro creates an argument
Allow(Target::MacroCall),
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.

could also just not allow this for now, or add a test that excercises this code path

View changes since the review


// 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

// Function parameter count, including C variadic `...` if present.
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
// Function parameter count, including C variadic `...` and `#[splat]` if present.
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/, Option<u16> /*splatted*/) {
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.

This return type should be a struct I think 😆 it's getting a little out of hand, and usually is just passed along to another function anyway, so we could just keep passing these modifiers along together. Also the function name doesn't really represent the return value anymore... maybe param_info?

View changes since the 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

@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

/// 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

};

// If the arguments should be wrapped in a tuple (ex: closures, splats), unwrap them here
if let Some(first_tupled_arg_index) = first_tupled_arg_index {
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.

Pull this condition's body out into a separate function

View changes since the review


let type_errors = ocx.try_evaluate_obligations();
if type_errors.is_empty() {
assert_matches!(new_tupled_type.kind(), ty::Tuple(_));
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.

This assert seems odd since you just created the tuple with this kind a few lines above, did you mean to check calee_tuple_type?

View changes since the review


// Keep the type variable if the argument is splatted, so we can force it to be a tuple later.
let tuple_type = if fn_sig_kind.splatted().is_some() {
let calee_tuple_type = self.try_structurally_resolve_type(
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.

typo calee is missing an l

View changes since the review

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

sym::variadic => {
self.write_scalar(Scalar::from_bool(fn_sig_kind.c_variadic()), &field_place)?;
}
sym::splat => {
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.

Also add it to libcore in the same commit

View changes since the review

@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
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Apr 28, 2026

☔ The latest upstream changes (presumably #155329) made this pull request unmergeable. Please resolve the merge conflicts.

};

// 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.

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.