@@ -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)
0 commit comments