@@ -45,6 +45,39 @@ enum SelfSemantic {
4545 No ,
4646}
4747
48+ /// Is `#[splat]` allowed semantically in a function or closure?
49+ /// Only applies to the function kind and header, the parameters are checked elsewhere.
50+ enum SplatSemantic {
51+ Yes ,
52+ NoClosures ( Span ) ,
53+ NoRustCall ( Span ) ,
54+ }
55+
56+ impl SplatSemantic {
57+ /// Returns if splatting is semantically allowed for the given `FnKind`,
58+ /// Only checks the function kind and header, not the parameters.
59+ fn from_fn_kind ( fk : & FnKind < ' _ > ) -> Self {
60+ match fk {
61+ FnKind :: Fn ( _, _, f) => Self :: from_extern ( f. sig . header . ext ) ,
62+ // Splatting closures is banned, because closure arguments are already de-tupled.
63+ FnKind :: Closure ( _, _, _, expr) => SplatSemantic :: NoClosures ( expr. span ) ,
64+ }
65+ }
66+
67+ fn from_extern ( ext : Extern ) -> Self {
68+ match ext {
69+ Extern :: None => SplatSemantic :: Yes ,
70+ // FIXME(splat): should splatting extern "C" or other ABIs be allowed?
71+ Extern :: Implicit ( _) => SplatSemantic :: Yes ,
72+ // For now, splatting rust-call is banned, because it already de-tuples args.
73+ Extern :: Explicit ( abi_str, span) if abi_str. symbol_unescaped . as_str ( ) == "rust-call" => {
74+ SplatSemantic :: NoRustCall ( span)
75+ }
76+ Extern :: Explicit ( _abi_str, _span) => SplatSemantic :: Yes ,
77+ }
78+ }
79+ }
80+
4881enum TraitOrImpl {
4982 Trait { vis : Span , constness : Const } ,
5083 TraitImpl { constness : Const , polarity : ImplPolarity , trait_ref_span : Span } ,
@@ -350,10 +383,15 @@ impl<'a> AstValidator<'a> {
350383 } ) ;
351384 }
352385
353- fn check_fn_decl ( & self , fn_decl : & FnDecl , self_semantic : SelfSemantic ) {
386+ fn check_fn_decl (
387+ & self ,
388+ fn_decl : & FnDecl ,
389+ self_semantic : SelfSemantic ,
390+ splat_semantic : SplatSemantic ,
391+ ) {
354392 self . check_decl_num_args ( fn_decl) ;
355393 let c_variadic_span = self . check_decl_cvariadic_pos ( fn_decl) ;
356- self . check_decl_splatting ( fn_decl, c_variadic_span) ;
394+ self . check_decl_splatting ( fn_decl, c_variadic_span, splat_semantic ) ;
357395 self . check_decl_attrs ( fn_decl) ;
358396 self . check_decl_self_param ( fn_decl, self_semantic) ;
359397 }
@@ -399,8 +437,13 @@ impl<'a> AstValidator<'a> {
399437 /// Emits an error if a function declaration has more than one splatted argument, with a
400438 /// C-variadic parameter, or a splat at an unsupported index (for performance).
401439 /// 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
440+ fn check_decl_splatting (
441+ & self ,
442+ fn_decl : & FnDecl ,
443+ c_variadic_span : Option < Span > ,
444+ splat_semantic : SplatSemantic ,
445+ ) {
446+ let ( splatted_arg_indexes, splatted_spans) : ( Vec < u16 > , Vec < Span > ) = fn_decl
404447 . inputs
405448 . iter ( )
406449 . enumerate ( )
@@ -433,9 +476,28 @@ impl<'a> AstValidator<'a> {
433476 if let Some ( c_variadic_span) = c_variadic_span
434477 && !splatted_spans. is_empty ( )
435478 {
479+ let mut splatted_spans = splatted_spans. clone ( ) ;
436480 splatted_spans. push ( c_variadic_span) ;
437481 self . dcx ( ) . emit_err ( diagnostics:: CVarArgsAndSplat { spans : splatted_spans } ) ;
438482 }
483+
484+ if !splatted_arg_indexes. is_empty ( ) {
485+ match splat_semantic {
486+ SplatSemantic :: NoClosures ( closure_span) => {
487+ let mut splatted_spans = splatted_spans. clone ( ) ;
488+ splatted_spans. push ( closure_span) ;
489+ self . dcx ( )
490+ . emit_err ( diagnostics:: SplatNotAllowedOnClosures { spans : splatted_spans } ) ;
491+ }
492+ SplatSemantic :: NoRustCall ( abi_span) => {
493+ let mut splatted_spans = splatted_spans;
494+ splatted_spans. push ( abi_span) ;
495+ self . dcx ( )
496+ . emit_err ( diagnostics:: SplatNotAllowedOnRustCall { spans : splatted_spans } ) ;
497+ }
498+ SplatSemantic :: Yes => { }
499+ }
500+ }
439501 }
440502
441503 fn check_decl_attrs ( & self , fn_decl : & FnDecl ) {
@@ -1055,7 +1117,11 @@ impl<'a> AstValidator<'a> {
10551117 match & ty. kind {
10561118 TyKind :: FnPtr ( bfty) => {
10571119 self . check_fn_ptr_safety ( bfty. decl_span , bfty. safety ) ;
1058- self . check_fn_decl ( & bfty. decl , SelfSemantic :: No ) ;
1120+ self . check_fn_decl (
1121+ & bfty. decl ,
1122+ SelfSemantic :: No ,
1123+ SplatSemantic :: from_extern ( bfty. ext ) ,
1124+ ) ;
10591125 Self :: check_decl_no_pat ( & bfty. decl , |span, _, _| {
10601126 self . dcx ( ) . emit_err ( diagnostics:: PatternFnPointer { span } ) ;
10611127 } ) ;
@@ -1746,7 +1812,8 @@ impl Visitor<'_> for AstValidator<'_> {
17461812 Some ( FnCtxt :: Assoc ( _) ) => SelfSemantic :: Yes ,
17471813 _ => SelfSemantic :: No ,
17481814 } ;
1749- self . check_fn_decl ( fk. decl ( ) , self_semantic) ;
1815+ let splat_semantic = SplatSemantic :: from_fn_kind ( & fk) ;
1816+ self . check_fn_decl ( fk. decl ( ) , self_semantic, splat_semantic) ;
17501817
17511818 if let Some ( & FnHeader { safety, .. } ) = fk. header ( ) {
17521819 self . check_item_safety ( span, safety) ;
0 commit comments