Skip to content
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3059,21 +3059,23 @@ impl FnDecl {
}

/// The marker index for "no splatted arguments".
/// Higher values are also not supported, for performance reasons.
///
/// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `FnDeclFlags::NO_SPLATTED_ARG_INDEX`.
pub const NO_SPLATTED_ARG_INDEX: u16 = u16::MAX;
pub const NO_SPLATTED_ARG_INDEX: u8 = u8::MAX;

/// Returns a splatted argument index, if any are present.
pub fn splatted(&self) -> Option<u16> {
pub fn splatted(&self) -> Option<u8> {
self.inputs.iter().enumerate().find_map(|(index, arg)| {
if index == Self::NO_SPLATTED_ARG_INDEX as usize {
if index >= usize::from(Self::NO_SPLATTED_ARG_INDEX) {
// AST validation has already checked the splatted argument index is valid, so just
// ignore invalid indexes here.
None
} else {
arg.attrs
.iter()
.any(|attr| attr.has_name(sym::splat))
.then_some(u16::try_from(index).unwrap())
.then_some(u8::try_from(index).unwrap())
}
})
}
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ struct ParamInfo {
pub c_variadic: bool,

/// The index of the splatted parameter, if any.
pub splatted: Option<u16>,
pub splatted: Option<u8>,
}

const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
Expand Down Expand Up @@ -364,11 +364,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn param_info(&self, def_id: DefId) -> ParamInfo {
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();

// FIXME(splat): use `sig.splatted()` once FnSig has it
ParamInfo {
param_count: sig.inputs().len() + usize::from(sig.c_variadic()),
c_variadic: sig.c_variadic(),
splatted: None,
splatted: sig.splatted(),
}
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,11 @@ impl<'a> AstValidator<'a> {
})
.unzip();

// A splatted argument at the "no splatted" marker index is not supported (this is an
// unlikely edge case).
// A splatted argument greater than or equal to the "no splatted" marker index is not
// supported.
if let (Some(&splatted_arg_index), Some(&splatted_span)) =
(splatted_arg_indexes.last(), splatted_spans.last())
&& splatted_arg_index == FnDecl::NO_SPLATTED_ARG_INDEX
&& splatted_arg_index >= u16::from(FnDecl::NO_SPLATTED_ARG_INDEX)
{
self.dcx().emit_err(diagnostics::InvalidSplattedArg {
splatted_arg_index,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_cranelift/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
.map(|local| {
let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty);

// FIXME(splat): un-tuple splatted arguments in codegen, for performance
// Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
if Some(local) == fx.mir.spread_arg {
// This argument (e.g. the last argument in the "rust-call" ABI)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ fn push_debuginfo_type_name<'tcx>(
output.push_str("fn(");
}

// FIXME(splat): should debuginfo be de-tupled in the callee (and caller)?
if !sig.inputs().is_empty() {
for &parameter_type in sig.inputs() {
push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
};

// Split the rust-call tupled arguments off.
// FIXME(splat): un-tuple splatted arguments in codegen, for performance
let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall
&& let Some((tup, args)) = args.split_last()
{
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let arg_decl = &mir.local_decls[local];
let arg_ty = fx.monomorphize(arg_decl.ty);

// FIXME(splat): re-tuple splatted arguments that were un-tupled in the ABI
if Some(local) == mir.spread_arg {
// This argument (e.g., the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_const_eval/src/const_eval/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_ast::Mutability;
use rustc_hir::LangItem;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Const, FnHeader, FnSigTys, ScalarInt, Ty, TyCtxt};
use rustc_middle::ty::{self, Const, FnHeader, FnSigKind, FnSigTys, ScalarInt, Ty, TyCtxt};
use rustc_span::{Symbol, sym};

use crate::const_eval::CompileTimeMachine;
Expand Down Expand Up @@ -436,6 +436,22 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
sym::variadic => {
self.write_scalar(Scalar::from_bool(fn_sig_kind.c_variadic()), &field_place)?;
}
sym::is_splatted => {
self.write_scalar(
Scalar::from_bool(fn_sig_kind.splatted().is_some()),
&field_place,
)?;
}
sym::splatted_index => {
self.write_scalar(
Scalar::from_u8(
// Currently the same encoding as FnSigKind.splatted
// FIXME(splat): make these two fields into a single Option<u8/u16>, or choose a stable encoding
fn_sig_kind.splatted().unwrap_or(FnSigKind::NO_SPLATTED_ARG_INDEX),
),
&field_place,
)?;
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
};

// Special handling for the closure ABI: untuple the last argument.
// FIXME(splat): un-tuple splatted arguments that were tupled in typecheck
let args: Cow<'_, [FnArg<'tcx, M::Provenance>]> =
if caller_abi == ExternAbi::RustCall && !args.is_empty() {
// Untuple
Expand Down
43 changes: 22 additions & 21 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4025,12 +4025,12 @@ pub struct Param<'hir> {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SplattedArgIndexError {
/// The splatted argument index is invalid.
/// Currently the only unsupported index is `u16::MAX`, which is used to indicate that no argument
/// is splatted.
InvalidIndex { splatted_arg_index: u16 },
/// A `u8::MAX` argument index used to indicate that no argument is splatted.
/// Higher values are also not supported, for performance reasons.
InvalidIndex { splatted_arg_index: u8 },

/// The splatted argument index is outside the bounds of the function arguments.
OutOfBounds { splatted_arg_index: u16, args_len: u16 },
OutOfBounds { splatted_arg_index: u8, args_len: u16 },
}

/// Contains the packed non-type fields of a function declaration.
Expand All @@ -4041,9 +4041,9 @@ pub struct FnDeclFlags {
flags: u8,

/// Which function argument is splatted into multiple arguments in callers, if any?
/// Splatting functions with `u16::MAX` arguments is not supported, see `FnSigKind` for
/// Splatting functions with `>= u8::MAX` arguments is not supported, see `FnSigKind` for
/// details.
splatted: u16,
splatted: u8,
}

impl fmt::Debug for FnDeclFlags {
Expand Down Expand Up @@ -4081,13 +4081,13 @@ impl FnDeclFlags {

/// Marker index for "no splatted argument".
/// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `rustc_ast::FnDecl::NO_SPLATTED_ARG_INDEX`.
const NO_SPLATTED_ARG_INDEX: u16 = u16::MAX;
const NO_SPLATTED_ARG_INDEX: u8 = u8::MAX;

/// Create a new FnDeclKind with no implicit self, no lifetime elision, no C-style variadic
/// argument, and no splatting.
/// To modify these flags, use the `set_*` methods, for readability.
// FIXME: use Default instead when that trait is const stable.
pub const fn default() -> Self {
pub fn default() -> Self {
Self { flags: 0, splatted: 0 }
.set_implicit_self(ImplicitSelfKind::None)
.set_lifetime_elision_allowed(false)
Expand All @@ -4097,7 +4097,7 @@ impl FnDeclFlags {

/// Set the implicit self kind.
#[must_use = "this method does not modify the receiver"]
pub const fn set_implicit_self(mut self, implicit_self: ImplicitSelfKind) -> Self {
pub fn set_implicit_self(mut self, implicit_self: ImplicitSelfKind) -> Self {
self.flags &= !Self::IMPLICIT_SELF_MASK;

match implicit_self {
Expand All @@ -4113,7 +4113,7 @@ impl FnDeclFlags {

/// Set the C-style variadic argument flag.
#[must_use = "this method does not modify the receiver"]
pub const fn set_c_variadic(mut self, c_variadic: bool) -> Self {
pub fn set_c_variadic(mut self, c_variadic: bool) -> Self {
if c_variadic {
self.flags |= Self::C_VARIADIC_FLAG;
} else {
Expand All @@ -4125,7 +4125,7 @@ impl FnDeclFlags {

/// Set the lifetime elision allowed flag.
#[must_use = "this method does not modify the receiver"]
pub const fn set_lifetime_elision_allowed(mut self, allowed: bool) -> Self {
pub fn set_lifetime_elision_allowed(mut self, allowed: bool) -> Self {
if allowed {
self.flags |= Self::LIFETIME_ELISION_ALLOWED_FLAG;
} else {
Expand All @@ -4138,16 +4138,17 @@ impl FnDeclFlags {
/// Set the splatted argument index.
/// The number of function arguments is used for error checking.
#[must_use = "this method does not modify the receiver"]
pub const fn set_splatted(
pub fn set_splatted(
mut self,
splatted: Option<u16>,
splatted: Option<u8>,
args_len: usize,
) -> Result<Self, SplattedArgIndexError> {
if let Some(splatted_arg_index) = splatted {
if splatted_arg_index == Self::NO_SPLATTED_ARG_INDEX {
if splatted_arg_index >= Self::NO_SPLATTED_ARG_INDEX {
Comment thread
teor2345 marked this conversation as resolved.
Outdated
// This index value is used as a marker for "no splatting", so it is unsupported.
// Higher values are also not supported, for performance reasons.
return Err(SplattedArgIndexError::InvalidIndex { splatted_arg_index });
} else if splatted_arg_index as usize >= args_len {
} else if usize::from(splatted_arg_index) >= args_len {
return Err(SplattedArgIndexError::OutOfBounds {
splatted_arg_index,
args_len: args_len as u16,
Expand All @@ -4164,14 +4165,14 @@ impl FnDeclFlags {

/// Set "no splatted arguments" for the function declaration.
#[must_use = "this method does not modify the receiver"]
pub const fn set_no_splatted_args(mut self) -> Self {
pub fn set_no_splatted_args(mut self) -> Self {
self.splatted = Self::NO_SPLATTED_ARG_INDEX;

self
}

/// Get the implicit self kind.
pub const fn implicit_self(self) -> ImplicitSelfKind {
pub fn implicit_self(self) -> ImplicitSelfKind {
match self.flags & Self::IMPLICIT_SELF_MASK {
0 => ImplicitSelfKind::None,
1 => ImplicitSelfKind::Imm,
Expand All @@ -4183,17 +4184,17 @@ impl FnDeclFlags {
}

/// Do the function arguments end with a C-style variadic argument?
pub const fn c_variadic(self) -> bool {
pub fn c_variadic(self) -> bool {
self.flags & Self::C_VARIADIC_FLAG != 0
}

/// Is lifetime elision allowed?
pub const fn lifetime_elision_allowed(self) -> bool {
pub fn lifetime_elision_allowed(self) -> bool {
self.flags & Self::LIFETIME_ELISION_ALLOWED_FLAG != 0
}

/// Get the splatted argument index, if any.
pub const fn splatted(self) -> Option<u16> {
pub fn splatted(self) -> Option<u8> {
if self.splatted == Self::NO_SPLATTED_ARG_INDEX { None } else { Some(self.splatted) }
}
}
Expand Down Expand Up @@ -4243,7 +4244,7 @@ impl<'hir> FnDecl<'hir> {
self.fn_decl_kind.lifetime_elision_allowed()
}

pub fn splatted(&self) -> Option<u16> {
pub fn splatted(&self) -> Option<u8> {
self.fn_decl_kind.splatted()
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,11 +445,13 @@ fn fn_sig_suggestion<'tcx>(
predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
assoc: ty::AssocItem,
) -> String {
let splatted_arg_index = sig.splatted().map(usize::from);
let args = sig
.inputs()
.iter()
.enumerate()
.map(|(i, ty)| {
let splat = if splatted_arg_index == Some(i) { "#[splat] " } else { "" };
let arg_ty = match ty.kind() {
ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
ty::Ref(reg, ref_ty, mutability) if i == 0 => {
Expand Down Expand Up @@ -478,7 +480,7 @@ fn fn_sig_suggestion<'tcx>(
}
}
};
Some(format!("{arg_ty}"))
Some(format!("{splat}{arg_ty}"))
})
.chain(std::iter::once(if sig.c_variadic() { Some("...".to_string()) } else { None }))
.flatten()
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1714,7 +1714,16 @@ fn check_fn_or_method<'tcx>(
let span = tcx.def_span(def_id);
let has_implicit_self = hir_decl.implicit_self().has_implicit_self();
let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 });
// FIXME(splat): use `sig.splatted()` once FnSig has it
// FIXME(splat): support the rest of closure splatting, or replace this code with an error
if let Some(mut splatted_arg_index) = sig.splatted() {
let mut inputs_count = sig.inputs().len();
if has_implicit_self {
splatted_arg_index = splatted_arg_index.strict_sub(1);
inputs_count = inputs_count.strict_sub(1);
}
debug!(?splatted_arg_index, ?inputs_count, ?has_implicit_self, ?sig);
sig = sig.set_splatted(Some(splatted_arg_index), inputs_count).unwrap();
}
// Check that the argument is a tuple and is sized
if let Some(ty) = inputs.next() {
wfcx.register_bound(
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3551,11 +3551,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?output_ty);

debug!(?abi, ?safety, ?decl.fn_decl_kind, input_tys_len = ?input_tys.len());
// FIXME(splat): use `set_splatted()` once FnSig has it
let fn_sig_kind = FnSigKind::default()
.set_abi(abi)
.set_safety(safety)
.set_c_variadic(decl.fn_decl_kind.c_variadic());
.set_c_variadic(decl.fn_decl_kind.c_variadic())
.set_splatted(decl.splatted(), input_tys.len())
.unwrap();
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, fn_sig_kind);
let fn_ptr_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);

Expand Down
Loading
Loading