@@ -34,6 +34,7 @@ use tracing::debug;
3434use crate :: attrs:: AttributeKind ;
3535use crate :: def:: { CtorKind , DefKind , MacroKinds , PerNS , Res } ;
3636use crate :: def_id:: { DefId , LocalDefIdMap } ;
37+ use crate :: find_attr;
3738pub ( crate ) use crate :: hir_id:: { HirId , ItemLocalId , ItemLocalMap , OwnerId } ;
3839use crate :: intravisit:: { FnKind , VisitorExt } ;
3940use crate :: lints:: DelayedLints ;
@@ -3937,7 +3938,8 @@ pub enum SplattedArgIndexError {
39373938#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
39383939#[ derive( Encodable , Decodable , HashStable_Generic ) ]
39393940pub struct FnDeclFlags {
3940- /// Holds the c_variadic and lifetime_elision_allowed bitflags, and 3 bits for the `ImplicitSelfKind`.
3941+ /// Holds the c_variadic, lifetime_elision_allowed, and has_splatted_arg bitflags, and 3 bits
3942+ /// for the `ImplicitSelfKind`.
39413943 flags : u8 ,
39423944
39433945 /// Which function argument is splatted into multiple arguments in callers, if any?
@@ -3961,8 +3963,8 @@ impl fmt::Debug for FnDeclFlags {
39613963 f. field ( & "CVariadic" ) ;
39623964 }
39633965
3964- if let Some ( index ) = self . splatted ( ) {
3965- f. field ( & format ! ( "Splatted({})" , index ) ) ;
3966+ if self . has_splatted_arg ( ) {
3967+ f. field ( & "HasSplattedArg" ) ;
39663968 }
39673969
39683970 f. finish ( )
@@ -3979,20 +3981,19 @@ impl FnDeclFlags {
39793981 /// Bitflag for lifetime elision.
39803982 const LIFETIME_ELISION_ALLOWED_FLAG : u8 = 1 << 4 ;
39813983
3982- /// Marker index for "no splatted argument".
3983- /// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`.
3984- const NO_SPLATTED_ARG_INDEX : u16 = u16:: MAX ;
3984+ /// Bitflag set if any argument is splatted (for performance).
3985+ const HAS_SPLATTED_ARG_FLAG : u8 = 1 << 5 ;
39853986
39863987 /// Create a new FnDeclKind with no implicit self, no lifetime elision, no C-style variadic
3987- /// argument, and no splatting .
3988+ /// argument, and no splatted argument .
39883989 /// To modify these flags, use the `set_*` methods, for readability.
39893990 // FIXME: use Default instead when that trait is const stable.
39903991 pub const fn default ( ) -> Self {
39913992 Self { flags : 0 , splatted : 0 }
39923993 . set_implicit_self ( ImplicitSelfKind :: None )
39933994 . set_lifetime_elision_allowed ( false )
39943995 . set_c_variadic ( false )
3995- . set_no_splatted_args ( )
3996+ . set_has_splatted_arg ( false )
39963997 }
39973998
39983999 /// Set the implicit self kind.
@@ -4035,38 +4036,15 @@ impl FnDeclFlags {
40354036 self
40364037 }
40374038
4038- /// Set the splatted argument index.
4039- /// The number of function arguments is used for error checking.
4039+ /// Set the splatted argument flag.
40404040 #[ must_use = "this method does not modify the receiver" ]
4041- pub const fn set_splatted (
4042- mut self ,
4043- splatted : Option < u16 > ,
4044- args_len : usize ,
4045- ) -> Result < Self , SplattedArgIndexError > {
4046- if let Some ( splatted_arg_index) = splatted {
4047- if splatted_arg_index == Self :: NO_SPLATTED_ARG_INDEX {
4048- // This index value is used as a marker for "no splatting", so it is unsupported.
4049- return Err ( SplattedArgIndexError :: InvalidIndex { splatted_arg_index } ) ;
4050- } else if splatted_arg_index as usize >= args_len {
4051- return Err ( SplattedArgIndexError :: OutOfBounds {
4052- splatted_arg_index,
4053- args_len : args_len as u16 ,
4054- } ) ;
4055- }
4056-
4057- self . splatted = splatted_arg_index;
4041+ pub const fn set_has_splatted_arg ( mut self , has_splatted_arg : bool ) -> Self {
4042+ if has_splatted_arg {
4043+ self . flags |= Self :: HAS_SPLATTED_ARG_FLAG ;
40584044 } else {
4059- self . splatted = Self :: NO_SPLATTED_ARG_INDEX ;
4045+ self . flags &= ! Self :: HAS_SPLATTED_ARG_FLAG ;
40604046 }
40614047
4062- Ok ( self )
4063- }
4064-
4065- /// Set "no splatted arguments" for the function declaration.
4066- #[ must_use = "this method does not modify the receiver" ]
4067- pub const fn set_no_splatted_args ( mut self ) -> Self {
4068- self . splatted = Self :: NO_SPLATTED_ARG_INDEX ;
4069-
40704048 self
40714049 }
40724050
@@ -4092,9 +4070,38 @@ impl FnDeclFlags {
40924070 self . flags & Self :: LIFETIME_ELISION_ALLOWED_FLAG != 0
40934071 }
40944072
4095- /// Get the splatted argument index, if any.
4096- pub const fn splatted ( self ) -> Option < u16 > {
4097- if self . splatted == Self :: NO_SPLATTED_ARG_INDEX { None } else { Some ( self . splatted ) }
4073+ /// Does this function have a splatted argument?
4074+ pub const fn has_splatted_arg ( self ) -> bool {
4075+ self . flags & Self :: HAS_SPLATTED_ARG_FLAG != 0
4076+ }
4077+
4078+ /// Returns `true` if the given input contains a `#[splat]` attribute in `attrs`.
4079+ pub fn is_splatted_arg < ' hir > (
4080+ & self ,
4081+ input : & ' hir Ty < ' hir > ,
4082+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4083+ ) -> bool {
4084+ self . has_splatted_arg ( ) && find_attr ! ( attrs( input. hir_id) , Splat ( _) )
4085+ }
4086+
4087+ /// Searches `inputs` and `attrs` for the index of the splatted argument. Returns `None` if
4088+ /// there is no splatted argument.
4089+ pub fn splatted_arg_index < ' hir > (
4090+ & self ,
4091+ inputs : & ' hir [ Ty < ' hir > ] ,
4092+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4093+ ) -> Option < u16 > {
4094+ if !self . has_splatted_arg ( ) {
4095+ return None ;
4096+ }
4097+
4098+ for ( index, input) in inputs. iter ( ) . enumerate ( ) {
4099+ if self . is_splatted_arg ( input, attrs) {
4100+ return Some ( u16:: try_from ( index) . unwrap ( ) ) ;
4101+ }
4102+ }
4103+
4104+ unreachable ! ( "no splatted argument found" ) ;
40984105 }
40994106}
41004107
@@ -4143,8 +4150,27 @@ impl<'hir> FnDecl<'hir> {
41434150 self . fn_decl_kind . lifetime_elision_allowed ( )
41444151 }
41454152
4146- pub fn splatted ( & self ) -> Option < u16 > {
4147- self . fn_decl_kind . splatted ( )
4153+ /// Returns `true` if the function has a splatted argument.
4154+ pub fn has_splatted_arg ( & self ) -> bool {
4155+ self . fn_decl_kind . has_splatted_arg ( )
4156+ }
4157+
4158+ /// Returns `true` if the given argument `index` contains a `#[splat]` attribute in `attrs`.
4159+ pub fn is_splatted_arg (
4160+ & self ,
4161+ index : usize ,
4162+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4163+ ) -> bool {
4164+ self . fn_decl_kind . is_splatted_arg ( & self . inputs [ index] , attrs)
4165+ }
4166+
4167+ /// Searches `self.inputs` and `attrs` for the index of the splatted argument. Returns `None`
4168+ /// if there is no splatted argument.
4169+ pub fn splatted_arg_index (
4170+ & self ,
4171+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4172+ ) -> Option < u16 > {
4173+ self . fn_decl_kind . splatted_arg_index ( self . inputs , attrs)
41484174 }
41494175
41504176 pub fn dummy ( span : Span ) -> Self {
0 commit comments