Skip to content

Commit 2d16c47

Browse files
authored
Unrolled build for #157605
Rollup merge of #157605 - teor2345:fn-arg-splat-exp-syntax, r=JonathanBrouwer Arg splat experiment - syntax impl This PR is part of the argument splatting lang experiment, and FFI overloading / C++ interop project goals: - #153629 - https://rust-lang.github.io/rust-project-goals/2026/overloading-for-ffi.html - https://rust-lang.github.io/rust-project-goals/2025h2/interop-problem-map.html I've split it from #153697 to make reviewing easier, see that PR for more details. The PR is the initial implementation of the feature: - `splat` incomplete feature gate - `#[splat]` attribute on function arguments - feature gate and UI tests for item type filtering, non-splattable arguments Once this PR merges, I'll rebase #153697.
2 parents d56483a + 5a93925 commit 2d16c47

19 files changed

Lines changed: 385 additions & 2 deletions

File tree

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ impl<'a> AstValidator<'a> {
352352

353353
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
354354
self.check_decl_num_args(fn_decl);
355-
self.check_decl_cvariadic_pos(fn_decl);
355+
let c_variadic_span = self.check_decl_cvariadic_pos(fn_decl);
356+
self.check_decl_splatting(fn_decl, c_variadic_span);
356357
self.check_decl_attrs(fn_decl);
357358
self.check_decl_self_param(fn_decl, self_semantic);
358359
}
@@ -370,17 +371,59 @@ impl<'a> AstValidator<'a> {
370371
/// Emits an error if a function declaration has a variadic parameter in the
371372
/// beginning or middle of parameter list.
372373
/// Example: `fn foo(..., x: i32)` will emit an error.
373-
fn check_decl_cvariadic_pos(&self, fn_decl: &FnDecl) {
374+
/// If a C-variadic parameter is found, returns its span.
375+
fn check_decl_cvariadic_pos(&self, fn_decl: &FnDecl) -> Option<Span> {
376+
let mut c_variadic_span = None;
377+
374378
match &*fn_decl.inputs {
375379
[ps @ .., _] => {
376380
for Param { ty, span, .. } in ps {
377381
if let TyKind::CVarArgs = ty.kind {
382+
c_variadic_span = Some(*span);
378383
self.dcx().emit_err(diagnostics::FnParamCVarArgsNotLast { span: *span });
379384
}
380385
}
381386
}
382387
_ => {}
383388
}
389+
390+
if let Some(Param { ty, span, .. }) = &fn_decl.inputs.last()
391+
&& let TyKind::CVarArgs = ty.kind
392+
{
393+
c_variadic_span = Some(*span);
394+
}
395+
396+
c_variadic_span
397+
}
398+
399+
/// Emits an error if a function declaration has more than one splatted argument, with a
400+
/// C-variadic parameter, or a splat at an unsupported index (for performance).
401+
/// Example: `fn foo(#[splat] x: (), #[splat] y: ())` will emit an error.
402+
fn check_decl_splatting(&self, fn_decl: &FnDecl, c_variadic_span: Option<Span>) {
403+
let (splatted_arg_indexes, mut splatted_spans): (Vec<u16>, Vec<Span>) = fn_decl
404+
.inputs
405+
.iter()
406+
.enumerate()
407+
.filter_map(|(index, arg)| {
408+
arg.attrs
409+
.iter()
410+
.any(|attr| attr.has_name(sym::splat))
411+
.then_some((u16::try_from(index).unwrap(), arg.span))
412+
})
413+
.unzip();
414+
415+
// Multiple splatted arguments are invalid: we can't know which arguments go in each splat.
416+
if splatted_arg_indexes.len() > 1 {
417+
self.dcx()
418+
.emit_err(diagnostics::DuplicateSplattedArgs { spans: splatted_spans.clone() });
419+
}
420+
421+
if let Some(c_variadic_span) = c_variadic_span
422+
&& !splatted_spans.is_empty()
423+
{
424+
splatted_spans.push(c_variadic_span);
425+
self.dcx().emit_err(diagnostics::CVarArgsAndSplat { spans: splatted_spans });
426+
}
384427
}
385428

386429
fn check_decl_attrs(&self, fn_decl: &FnDecl) {
@@ -396,6 +439,7 @@ impl<'a> AstValidator<'a> {
396439
sym::deny,
397440
sym::expect,
398441
sym::forbid,
442+
sym::splat,
399443
sym::warn,
400444
];
401445
!attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)

compiler/rustc_ast_passes/src/diagnostics.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,22 @@ pub(crate) struct FnParamCVarArgsNotLast {
123123
pub span: Span,
124124
}
125125

126+
#[derive(Diagnostic)]
127+
#[diag("multiple `#[splat]`s are not allowed in the same function")]
128+
#[help("remove `#[splat]` from all but one argument")]
129+
pub(crate) struct DuplicateSplattedArgs {
130+
#[primary_span]
131+
pub spans: Vec<Span>,
132+
}
133+
134+
#[derive(Diagnostic)]
135+
#[diag("`...` and `#[splat]` are not allowed in the same function")]
136+
#[help("remove `#[splat]` or remove `...`")]
137+
pub(crate) struct CVarArgsAndSplat {
138+
#[primary_span]
139+
pub spans: Vec<Span>,
140+
}
141+
126142
#[derive(Diagnostic)]
127143
#[diag("documentation comments cannot be applied to function parameters")]
128144
pub(crate) struct FnParamDocComment {
@@ -131,6 +147,7 @@ pub(crate) struct FnParamDocComment {
131147
pub span: Span,
132148
}
133149

150+
// FIXME(splat): add splat to the allowed built-in attributes when it is complete/stabilized
134151
#[derive(Diagnostic)]
135152
#[diag(
136153
"allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters"

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
500500
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
501501
gate_all!(postfix_match, "postfix match is experimental");
502502
gate_all!(return_type_notation, "return type notation is experimental");
503+
gate_all!(splat, "`fn(#[splat] (a, ...))` is incomplete", "call as func((a, ...)) instead");
503504
gate_all!(super_let, "`super let` is experimental");
504505
gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental");
505506
gate_all!(unnamed_enum_variants, "unnamed enum variants are experimental");

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub(crate) mod rustc_allocator;
6969
pub(crate) mod rustc_dump;
7070
pub(crate) mod rustc_internal;
7171
pub(crate) mod semantics;
72+
pub(crate) mod splat;
7273
pub(crate) mod stability;
7374
pub(crate) mod test_attrs;
7475
pub(crate) mod traits;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//! Attribute parsing for the `#[splat]` function argument overloading attribute.
2+
//! This attribute modifies typecheck to support overload resolution, then modifies codegen for performance.
3+
4+
use rustc_feature::AttributeStability;
5+
6+
use super::prelude::*;
7+
8+
pub(crate) struct SplatParser;
9+
10+
impl NoArgsAttributeParser for SplatParser {
11+
const PATH: &[Symbol] = &[sym::splat];
12+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Param)]);
13+
const STABILITY: AttributeStability =
14+
unstable!(splat, "the `#[splat]` attribute is experimental");
15+
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Splat;
16+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use crate::attributes::rustc_allocator::*;
5757
use crate::attributes::rustc_dump::*;
5858
use crate::attributes::rustc_internal::*;
5959
use crate::attributes::semantics::{ComptimeParser, *};
60+
use crate::attributes::splat::*;
6061
use crate::attributes::stability::*;
6162
use crate::attributes::test_attrs::*;
6263
use crate::attributes::traits::*;
@@ -323,6 +324,7 @@ attribute_parsers!(
323324
Single<WithoutArgs<RustcStrictCoherenceParser>>,
324325
Single<WithoutArgs<RustcTrivialFieldReadsParser>>,
325326
Single<WithoutArgs<RustcUnsafeSpecializationMarkerParser>>,
327+
Single<WithoutArgs<SplatParser>>,
326328
Single<WithoutArgs<ThreadLocalParser>>,
327329
Single<WithoutArgs<TrackCallerParser>>,
328330
// tidy-alphabetical-end

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
208208
// - https://github.com/rust-lang/rust/issues/130494
209209
sym::pin_v2,
210210

211+
// The `#[splat]` attribute is part of the `splat` experiment
212+
// that improves the ergonomics of function overloading, tracked in:
213+
//
214+
// - https://github.com/rust-lang/rust/issues/153629
215+
sym::splat,
216+
211217
// ==========================================================================
212218
// Internal attributes: Stability, deprecation, and unsafe:
213219
// ==========================================================================

compiler/rustc_feature/src/unstable.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,9 @@ declare_features! (
721721
(unstable, sparc_target_feature, "1.84.0", Some(132783)),
722722
/// Allows specialization of implementations (RFC 1210).
723723
(incomplete, specialization, "1.7.0", Some(31844)),
724+
/// Experimental "splatting" of function call arguments at the call site.
725+
/// e.g. `foo(a, b, c)` calls `#[splat] fn foo((a: A, b: B, c: C))`.
726+
(incomplete, splat, "CURRENT_RUSTC_VERSION", Some(153629)),
724727
/// Allows using `#[rustc_align_static(...)]` on static items.
725728
(unstable, static_align, "1.91.0", Some(146177)),
726729
/// Allows attributes on expressions and non-item statements.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,9 @@ pub enum AttributeKind {
15891589
reason: Option<Symbol>,
15901590
},
15911591

1592+
/// Represents `#[splat]`
1593+
Splat(Span),
1594+
15921595
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
15931596
Stability {
15941597
stability: Stability,

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ impl AttributeKind {
192192
RustcUnsafeSpecializationMarker => No,
193193
Sanitize { .. } => No,
194194
ShouldPanic { .. } => No,
195+
Splat(..) => Yes,
195196
Stability { .. } => Yes,
196197
TargetFeature { .. } => No,
197198
TestRunner(..) => Yes,

0 commit comments

Comments
 (0)