@@ -36,6 +36,7 @@ use tracing::debug;
3636use crate :: attrs:: AttributeKind ;
3737use crate :: def:: { CtorKind , DefKind , MacroKinds , PerNS , Res } ;
3838use crate :: def_id:: { DefId , LocalDefIdMap } ;
39+ use crate :: find_attr;
3940pub ( crate ) use crate :: hir_id:: { HirId , ItemLocalId , ItemLocalMap , OwnerId } ;
4041use crate :: intravisit:: { FnKind , VisitorExt } ;
4142use crate :: lints:: DelayedLints ;
@@ -4034,7 +4035,8 @@ pub enum SplattedArgIndexError {
40344035#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
40354036#[ derive( Encodable , Decodable , StableHash ) ]
40364037pub struct FnDeclFlags {
4037- /// Holds the c_variadic and lifetime_elision_allowed bitflags, and 3 bits for the `ImplicitSelfKind`.
4038+ /// Holds the c_variadic, lifetime_elision_allowed, and has_splatted_arg bitflags, and 3 bits
4039+ /// for the `ImplicitSelfKind`.
40384040 flags : u8 ,
40394041
40404042 /// Which function argument is splatted into multiple arguments in callers, if any?
@@ -4058,8 +4060,8 @@ impl fmt::Debug for FnDeclFlags {
40584060 f. field ( & "CVariadic" ) ;
40594061 }
40604062
4061- if let Some ( index ) = self . splatted ( ) {
4062- f. field ( & format ! ( "Splatted({})" , index ) ) ;
4063+ if self . has_splatted_arg ( ) {
4064+ f. field ( & "HasSplattedArg" ) ;
40634065 }
40644066
40654067 f. finish ( )
@@ -4076,20 +4078,19 @@ impl FnDeclFlags {
40764078 /// Bitflag for lifetime elision.
40774079 const LIFETIME_ELISION_ALLOWED_FLAG : u8 = 1 << 4 ;
40784080
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 ;
4081+ /// Bitflag set if any argument is splatted (for performance).
4082+ const HAS_SPLATTED_ARG_FLAG : u8 = 1 << 5 ;
40824083
40834084 /// Create a new FnDeclKind with no implicit self, no lifetime elision, no C-style variadic
4084- /// argument, and no splatting .
4085+ /// argument, and no splatted argument .
40854086 /// To modify these flags, use the `set_*` methods, for readability.
40864087 // FIXME: use Default instead when that trait is const stable.
40874088 pub const fn default ( ) -> Self {
40884089 Self { flags : 0 , splatted : 0 }
40894090 . set_implicit_self ( ImplicitSelfKind :: None )
40904091 . set_lifetime_elision_allowed ( false )
40914092 . set_c_variadic ( false )
4092- . set_no_splatted_args ( )
4093+ . set_has_splatted_arg ( false )
40934094 }
40944095
40954096 /// Set the implicit self kind.
@@ -4132,38 +4133,15 @@ impl FnDeclFlags {
41324133 self
41334134 }
41344135
4135- /// Set the splatted argument index.
4136- /// The number of function arguments is used for error checking.
4136+ /// Set the splatted argument flag.
41374137 #[ 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;
4138+ pub const fn set_has_splatted_arg ( mut self , has_splatted_arg : bool ) -> Self {
4139+ if has_splatted_arg {
4140+ self . flags |= Self :: HAS_SPLATTED_ARG_FLAG ;
41554141 } else {
4156- self . splatted = Self :: NO_SPLATTED_ARG_INDEX ;
4142+ self . flags &= ! Self :: HAS_SPLATTED_ARG_FLAG ;
41574143 }
41584144
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-
41674145 self
41684146 }
41694147
@@ -4189,9 +4167,38 @@ impl FnDeclFlags {
41894167 self . flags & Self :: LIFETIME_ELISION_ALLOWED_FLAG != 0
41904168 }
41914169
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 ) }
4170+ /// Does this function have a splatted argument?
4171+ pub const fn has_splatted_arg ( self ) -> bool {
4172+ self . flags & Self :: HAS_SPLATTED_ARG_FLAG != 0
4173+ }
4174+
4175+ /// Returns `true` if the given input contains a `#[splat]` attribute in `attrs`.
4176+ pub fn is_splatted_arg < ' hir > (
4177+ & self ,
4178+ input : & ' hir Ty < ' hir > ,
4179+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4180+ ) -> bool {
4181+ self . has_splatted_arg ( ) && find_attr ! ( attrs( input. hir_id) , Splat ( _) )
4182+ }
4183+
4184+ /// Searches `inputs` and `attrs` for the index of the splatted argument. Returns `None` if
4185+ /// there is no splatted argument.
4186+ pub fn splatted_arg_index < ' hir > (
4187+ & self ,
4188+ inputs : & ' hir [ Ty < ' hir > ] ,
4189+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4190+ ) -> Option < u16 > {
4191+ if !self . has_splatted_arg ( ) {
4192+ return None ;
4193+ }
4194+
4195+ for ( index, input) in inputs. iter ( ) . enumerate ( ) {
4196+ if self . is_splatted_arg ( input, attrs) {
4197+ return Some ( u16:: try_from ( index) . unwrap ( ) ) ;
4198+ }
4199+ }
4200+
4201+ unreachable ! ( "no splatted argument found" ) ;
41954202 }
41964203}
41974204
@@ -4240,8 +4247,27 @@ impl<'hir> FnDecl<'hir> {
42404247 self . fn_decl_kind . lifetime_elision_allowed ( )
42414248 }
42424249
4243- pub fn splatted ( & self ) -> Option < u16 > {
4244- self . fn_decl_kind . splatted ( )
4250+ /// Returns `true` if the function has a splatted argument.
4251+ pub fn has_splatted_arg ( & self ) -> bool {
4252+ self . fn_decl_kind . has_splatted_arg ( )
4253+ }
4254+
4255+ /// Returns `true` if the given argument `index` contains a `#[splat]` attribute in `attrs`.
4256+ pub fn is_splatted_arg (
4257+ & self ,
4258+ index : usize ,
4259+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4260+ ) -> bool {
4261+ self . fn_decl_kind . is_splatted_arg ( & self . inputs [ index] , attrs)
4262+ }
4263+
4264+ /// Searches `self.inputs` and `attrs` for the index of the splatted argument. Returns `None`
4265+ /// if there is no splatted argument.
4266+ pub fn splatted_arg_index (
4267+ & self ,
4268+ attrs : & ' hir dyn Fn ( HirId ) -> & ' hir [ Attribute ] ,
4269+ ) -> Option < u16 > {
4270+ self . fn_decl_kind . splatted_arg_index ( self . inputs , attrs)
42454271 }
42464272
42474273 pub fn dummy ( span : Span ) -> Self {
0 commit comments