@@ -45,6 +45,13 @@ enum SelfSemantic {
4545 No ,
4646}
4747
48+ /// Is `#[splat]` allowed semantically on a parameter of a `FnDecl`?
49+ enum SplatSemantic {
50+ Yes ,
51+ NoClosures ( Span ) ,
52+ NoRustCall ( Span ) ,
53+ }
54+
4855enum TraitOrImpl {
4956 Trait { vis : Span , constness : Const } ,
5057 TraitImpl { constness : Const , polarity : ImplPolarity , trait_ref_span : Span } ,
@@ -350,10 +357,15 @@ impl<'a> AstValidator<'a> {
350357 } ) ;
351358 }
352359
353- fn check_fn_decl ( & self , fn_decl : & FnDecl , self_semantic : SelfSemantic ) {
360+ fn check_fn_decl (
361+ & self ,
362+ fn_decl : & FnDecl ,
363+ self_semantic : SelfSemantic ,
364+ splat_semantic : SplatSemantic ,
365+ ) {
354366 self . check_decl_num_args ( fn_decl) ;
355367 let c_variadic_span = self . check_decl_cvariadic_pos ( fn_decl) ;
356- self . check_decl_splatting ( fn_decl, c_variadic_span) ;
368+ self . check_decl_splatting ( fn_decl, c_variadic_span, splat_semantic ) ;
357369 self . check_decl_attrs ( fn_decl) ;
358370 self . check_decl_self_param ( fn_decl, self_semantic) ;
359371 }
@@ -399,8 +411,13 @@ impl<'a> AstValidator<'a> {
399411 /// Emits an error if a function declaration has more than one splatted argument, with a
400412 /// C-variadic parameter, or a splat at an unsupported index (for performance).
401413 /// 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
414+ fn check_decl_splatting (
415+ & self ,
416+ fn_decl : & FnDecl ,
417+ c_variadic_span : Option < Span > ,
418+ splat_semantic : SplatSemantic ,
419+ ) {
420+ let ( splatted_arg_indexes, splatted_spans) : ( Vec < u16 > , Vec < Span > ) = fn_decl
404421 . inputs
405422 . iter ( )
406423 . enumerate ( )
@@ -433,9 +450,28 @@ impl<'a> AstValidator<'a> {
433450 if let Some ( c_variadic_span) = c_variadic_span
434451 && !splatted_spans. is_empty ( )
435452 {
453+ let mut splatted_spans = splatted_spans. clone ( ) ;
436454 splatted_spans. push ( c_variadic_span) ;
437455 self . dcx ( ) . emit_err ( diagnostics:: CVarArgsAndSplat { spans : splatted_spans } ) ;
438456 }
457+
458+ if !splatted_arg_indexes. is_empty ( ) {
459+ match splat_semantic {
460+ SplatSemantic :: NoClosures ( closure_span) => {
461+ let mut splatted_spans = splatted_spans. clone ( ) ;
462+ splatted_spans. push ( closure_span) ;
463+ self . dcx ( )
464+ . emit_err ( diagnostics:: SplatNotAllowedOnClosures { spans : splatted_spans } ) ;
465+ }
466+ SplatSemantic :: NoRustCall ( abi_span) => {
467+ let mut splatted_spans = splatted_spans;
468+ splatted_spans. push ( abi_span) ;
469+ self . dcx ( )
470+ . emit_err ( diagnostics:: SplatNotAllowedOnRustCall { spans : splatted_spans } ) ;
471+ }
472+ SplatSemantic :: Yes => { }
473+ }
474+ }
439475 }
440476
441477 fn check_decl_attrs ( & self , fn_decl : & FnDecl ) {
@@ -1055,7 +1091,7 @@ impl<'a> AstValidator<'a> {
10551091 match & ty. kind {
10561092 TyKind :: FnPtr ( bfty) => {
10571093 self . check_fn_ptr_safety ( bfty. decl_span , bfty. safety ) ;
1058- self . check_fn_decl ( & bfty. decl , SelfSemantic :: No ) ;
1094+ self . check_fn_decl ( & bfty. decl , SelfSemantic :: No , SplatSemantic :: Yes ) ;
10591095 Self :: check_decl_no_pat ( & bfty. decl , |span, _, _| {
10601096 self . dcx ( ) . emit_err ( diagnostics:: PatternFnPointer { span } ) ;
10611097 } ) ;
@@ -1746,7 +1782,24 @@ impl Visitor<'_> for AstValidator<'_> {
17461782 Some ( FnCtxt :: Assoc ( _) ) => SelfSemantic :: Yes ,
17471783 _ => SelfSemantic :: No ,
17481784 } ;
1749- self . check_fn_decl ( fk. decl ( ) , self_semantic) ;
1785+ let splat_semantic = match fk {
1786+ FnKind :: Fn ( _, _, _) => match fk. header ( ) . unwrap ( ) . ext {
1787+ Extern :: None => SplatSemantic :: Yes ,
1788+ // FIXME(splat): should splatting extern "C" or other ABIs be allowed?
1789+ Extern :: Implicit ( _) => SplatSemantic :: Yes ,
1790+ // For now, splatting rust-call is banned, because it already de-tuples args.
1791+ Extern :: Explicit ( abi_str, span)
1792+ if abi_str. symbol_unescaped . as_str ( ) == "rust-call" =>
1793+ {
1794+ SplatSemantic :: NoRustCall ( span)
1795+ }
1796+ Extern :: Explicit ( _abi_str, _span) => SplatSemantic :: Yes ,
1797+ } ,
1798+ // Splatting closures is banned, because closure arguments are already de-tupled.
1799+ FnKind :: Closure ( _, _, _, expr) => SplatSemantic :: NoClosures ( expr. span ) ,
1800+ } ;
1801+
1802+ self . check_fn_decl ( fk. decl ( ) , self_semantic, splat_semantic) ;
17501803
17511804 if let Some ( & FnHeader { safety, .. } ) = fk. header ( ) {
17521805 self . check_item_safety ( span, safety) ;
0 commit comments