@@ -4018,13 +4018,29 @@ pub struct Param<'hir> {
40184018 pub span : Span ,
40194019}
40204020
4021+ /// Error type for splatted argument index errors.
4022+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
4023+ pub enum SplattedArgIndexError {
4024+ /// The splatted argument index is invalid.
4025+ /// Currently the only unsupported index is `u16::MAX`, which is used to indicate that no argument
4026+ /// is splatted.
4027+ InvalidIndex { splatted_arg_index : u16 } ,
4028+
4029+ /// The splatted argument index is outside the bounds of the function arguments.
4030+ OutOfBounds { splatted_arg_index : u16 , args_len : u16 } ,
4031+ }
4032+
40214033/// Contains the packed non-type fields of a function declaration.
4022- // FIXME(splat): add the splatted argument index as a u16
40234034#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
40244035#[ derive( Encodable , Decodable , StableHash ) ]
40254036pub struct FnDeclFlags {
40264037 /// Holds the c_variadic and lifetime_elision_allowed bitflags, and 3 bits for the `ImplicitSelfKind`.
40274038 flags : u8 ,
4039+
4040+ /// Which function argument is splatted into multiple arguments in callers, if any?
4041+ /// Splatting functions with `u16::MAX` arguments is not supported, see `FnSigKind` for
4042+ /// details.
4043+ splatted : u16 ,
40284044}
40294045
40304046impl fmt:: Debug for FnDeclFlags {
@@ -4036,11 +4052,15 @@ impl fmt::Debug for FnDeclFlags {
40364052 f. field ( & "LifetimeElisionAllowed" ) ;
40374053 } else {
40384054 f. field ( & "NoLifetimeElision" ) ;
4039- } ;
4055+ }
40404056
40414057 if self . c_variadic ( ) {
40424058 f. field ( & "CVariadic" ) ;
4043- } ;
4059+ }
4060+
4061+ if let Some ( index) = self . splatted ( ) {
4062+ f. field ( & format ! ( "Splatted({})" , index) ) ;
4063+ }
40444064
40454065 f. finish ( )
40464066 }
@@ -4056,14 +4076,20 @@ impl FnDeclFlags {
40564076 /// Bitflag for lifetime elision.
40574077 const LIFETIME_ELISION_ALLOWED_FLAG : u8 = 1 << 4 ;
40584078
4059- /// Create a new FnDeclKind with no implicit self, no lifetime elision, and no C-style variadic argument.
4079+ /// Marker index for "no splatted argument".
4080+ /// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`.
4081+ const NO_SPLATTED_ARG_INDEX : u16 = u16:: MAX ;
4082+
4083+ /// Create a new FnDeclKind with no implicit self, no lifetime elision, no C-style variadic
4084+ /// argument, and no splatting.
40604085 /// To modify these flags, use the `set_*` methods, for readability.
40614086 // FIXME: use Default instead when that trait is const stable.
40624087 pub const fn default ( ) -> Self {
4063- Self { flags : 0 }
4088+ Self { flags : 0 , splatted : 0 }
40644089 . set_implicit_self ( ImplicitSelfKind :: None )
40654090 . set_lifetime_elision_allowed ( false )
40664091 . set_c_variadic ( false )
4092+ . set_no_splatted_args ( )
40674093 }
40684094
40694095 /// Set the implicit self kind.
@@ -4106,6 +4132,41 @@ impl FnDeclFlags {
41064132 self
41074133 }
41084134
4135+ /// Set the splatted argument index.
4136+ /// The number of function arguments is used for error checking.
4137+ #[ must_use = "this method does not modify the receiver" ]
4138+ pub const fn set_splatted (
4139+ mut self ,
4140+ splatted : Option < u16 > ,
4141+ args_len : usize ,
4142+ ) -> Result < Self , SplattedArgIndexError > {
4143+ if let Some ( splatted_arg_index) = splatted {
4144+ if splatted_arg_index == Self :: NO_SPLATTED_ARG_INDEX {
4145+ // This index value is used as a marker for "no splatting", so it is unsupported.
4146+ return Err ( SplattedArgIndexError :: InvalidIndex { splatted_arg_index } ) ;
4147+ } else if splatted_arg_index as usize >= args_len {
4148+ return Err ( SplattedArgIndexError :: OutOfBounds {
4149+ splatted_arg_index,
4150+ args_len : args_len as u16 ,
4151+ } ) ;
4152+ }
4153+
4154+ self . splatted = splatted_arg_index;
4155+ } else {
4156+ self . splatted = Self :: NO_SPLATTED_ARG_INDEX ;
4157+ }
4158+
4159+ Ok ( self )
4160+ }
4161+
4162+ /// Set "no splatted arguments" for the function declaration.
4163+ #[ must_use = "this method does not modify the receiver" ]
4164+ pub const fn set_no_splatted_args ( mut self ) -> Self {
4165+ self . splatted = Self :: NO_SPLATTED_ARG_INDEX ;
4166+
4167+ self
4168+ }
4169+
41094170 /// Get the implicit self kind.
41104171 pub const fn implicit_self ( self ) -> ImplicitSelfKind {
41114172 match self . flags & Self :: IMPLICIT_SELF_MASK {
@@ -4127,6 +4188,11 @@ impl FnDeclFlags {
41274188 pub const fn lifetime_elision_allowed ( self ) -> bool {
41284189 self . flags & Self :: LIFETIME_ELISION_ALLOWED_FLAG != 0
41294190 }
4191+
4192+ /// Get the splatted argument index, if any.
4193+ pub const fn splatted ( self ) -> Option < u16 > {
4194+ if self . splatted == Self :: NO_SPLATTED_ARG_INDEX { None } else { Some ( self . splatted ) }
4195+ }
41304196}
41314197
41324198/// Represents the header (not the body) of a function declaration.
@@ -4174,6 +4240,10 @@ impl<'hir> FnDecl<'hir> {
41744240 self . fn_decl_kind . lifetime_elision_allowed ( )
41754241 }
41764242
4243+ pub fn splatted ( & self ) -> Option < u16 > {
4244+ self . fn_decl_kind . splatted ( )
4245+ }
4246+
41774247 pub fn dummy ( span : Span ) -> Self {
41784248 Self {
41794249 inputs : & [ ] ,
0 commit comments