diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 6b4963ae92461..d8d4558c01209 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -35,7 +35,7 @@ pub enum CanonAbi { /// Swift calling convention, exposed via LLVM's `swiftcc`. Cross-platform /// and not tied to a specific target architecture. - Swift, + Swift { tail: bool }, /// ABIs relevant to 32-bit Arm targets Arm(ArmCall), @@ -66,7 +66,7 @@ impl CanonAbi { | CanonAbi::RustTail => true, CanonAbi::C | CanonAbi::Custom - | CanonAbi::Swift + | CanonAbi::Swift { .. } | CanonAbi::Arm(_) | CanonAbi::GpuKernel | CanonAbi::Interrupt(_) @@ -87,7 +87,7 @@ impl fmt::Display for CanonAbi { CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone, CanonAbi::RustTail => ExternAbi::RustTail, CanonAbi::Custom => ExternAbi::Custom, - CanonAbi::Swift => ExternAbi::Swift, + CanonAbi::Swift { .. } => ExternAbi::Swift, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, ArmCall::CCmseNonSecureCall => ExternAbi::CmseNonSecureCall, diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index e8779d6ee6869..eaa0c8d3b4f57 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -194,6 +194,7 @@ impl LayoutCalculator { largest_niche: element.largest_niche.filter(|_| count != 0), uninhabited: element.uninhabited && count != 0, align: element.align, + size_without_padding: size, size, max_repr_align: None, unadjusted_abi_align: element.align.abi, @@ -512,6 +513,7 @@ impl LayoutCalculator { largest_niche: None, uninhabited: false, align: AbiAlign::new(align), + size_without_padding: size, size: size.align_to(align), max_repr_align, unadjusted_abi_align, @@ -742,6 +744,7 @@ impl LayoutCalculator { backend_repr: abi, largest_niche, uninhabited, + size_without_padding: size, size, align: AbiAlign::new(align), max_repr_align, @@ -1051,6 +1054,7 @@ impl LayoutCalculator { uninhabited, backend_repr: abi, align: AbiAlign::new(align), + size_without_padding: size, size, max_repr_align, unadjusted_abi_align, @@ -1294,8 +1298,9 @@ impl LayoutCalculator { } } + let field_size = if repr.swift() { field.size_without_padding } else { field.size }; offset = - offset.checked_add(field.size, dl).ok_or(LayoutCalculatorError::SizeOverflow)?; + offset.checked_add(field_size, dl).ok_or(LayoutCalculatorError::SizeOverflow)?; } // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). @@ -1417,6 +1422,7 @@ impl LayoutCalculator { largest_niche, uninhabited, align: AbiAlign::new(align), + size_without_padding: min_size, size, max_repr_align, unadjusted_abi_align, @@ -1516,6 +1522,7 @@ where backend_repr: repr, largest_niche: elt.largest_niche, uninhabited: false, + size_without_padding: size, size, align: AbiAlign::new(align), max_repr_align: None, diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs index fd68d06c93829..7207b64f21b2f 100644 --- a/compiler/rustc_abi/src/layout/coroutine.rs +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -306,6 +306,7 @@ pub(super) fn layout< // FIXME: Remove when is implemented and aliased coroutine fields are wrapped in `UnsafePinned`. largest_niche: None, uninhabited, + size_without_padding: size, size, align, max_repr_align: None, diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index 1fffb84ec21cb..9cda6d8168192 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -22,6 +22,7 @@ impl LayoutData { largest_niche: None, uninhabited: false, align: AbiAlign::new(dl.i8_align), + size_without_padding: Size::ZERO, size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align, @@ -39,6 +40,7 @@ impl LayoutData { largest_niche: None, uninhabited: true, align: AbiAlign::new(dl.i8_align), + size_without_padding: Size::ZERO, size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align, @@ -80,6 +82,7 @@ impl LayoutData { backend_repr: BackendRepr::Scalar(scalar), largest_niche, uninhabited: false, + size_without_padding: size, size, align, max_repr_align: None, @@ -114,6 +117,7 @@ impl LayoutData { largest_niche, uninhabited: false, align: AbiAlign::new(align), + size_without_padding: size, size, max_repr_align: None, unadjusted_abi_align: align, @@ -140,6 +144,7 @@ impl LayoutData { largest_niche: None, uninhabited: true, align: AbiAlign::new(dl.i8_align), + size_without_padding: Size::ZERO, size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align, @@ -166,6 +171,7 @@ impl LayoutData { largest_niche: layout.largest_niche, uninhabited: layout.uninhabited, size: layout.size, + size_without_padding: layout.size_without_padding, align: parent.align, max_repr_align: parent.max_repr_align, unadjusted_abi_align: parent.unadjusted_abi_align, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 1e0fd78b4dd75..240f1971cafe3 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -101,11 +101,13 @@ bitflags! { /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5; const IS_SCALABLE = 1 << 6; + const IS_SWIFT = 1 << 7; // Any of these flags being set prevent field reordering optimisation. const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() | ReprFlags::IS_SCALABLE.bits() - | ReprFlags::IS_LINEAR.bits(); + | ReprFlags::IS_LINEAR.bits() + | ReprFlags::IS_SWIFT.bits(); const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits(); } } @@ -184,6 +186,11 @@ impl ReprOptions { self.flags.contains(ReprFlags::IS_C) } + #[inline] + pub fn swift(&self) -> bool { + self.flags.contains(ReprFlags::IS_SWIFT) + } + #[inline] pub fn packed(&self) -> bool { self.pack.is_some() @@ -2162,7 +2169,12 @@ pub struct LayoutData { /// especially in the case of by-pointer struct returns, which allocate stack even when unused. pub uninhabited: bool, + /// The alignment of the type in memory. pub align: AbiAlign, + /// The amount of memory occupied by this type, this excludes padding. + pub size_without_padding: Size, + /// The stride of the type is its size including padding. Or how much you need to move in + /// memory to get from one element to the next. pub size: Size, /// The largest alignment explicitly requested with `repr(align)` on this type or any field. @@ -2226,6 +2238,7 @@ where // `Interned`. We print it like this to avoid having to update // expected output in a lot of tests. let LayoutData { + size_without_padding: min_size, size, align, backend_repr, @@ -2238,6 +2251,7 @@ where randomization_seed, } = self; f.debug_struct("Layout") + .field("min_size", min_size) .field("size", size) .field("align", align) .field("backend_repr", backend_repr) @@ -2388,6 +2402,7 @@ pub enum AbiFromStrErr { #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct VariantLayout { pub size: Size, + pub size_without_padding: Size, pub backend_repr: BackendRepr, pub field_offsets: IndexVec, fields_in_memory_order: IndexVec, @@ -2403,6 +2418,7 @@ impl VariantLayout { Self { size: layout.size, + size_without_padding: layout.size_without_padding, backend_repr: layout.backend_repr, field_offsets: offsets, fields_in_memory_order: in_memory_order, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d1368d8f9f633..d5bc1a110695a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -567,7 +567,7 @@ impl<'a> AstValidator<'a> { | CanonAbi::RustCold | CanonAbi::RustPreserveNone | CanonAbi::RustTail - | CanonAbi::Swift + | CanonAbi::Swift { .. } | CanonAbi::Arm(_) | CanonAbi::X86(_) => { /* nothing to check */ } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index bb0da73df015c..e5e36ac986cbd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -141,6 +141,19 @@ fn parse_repr(cx: &mut AcceptContext<'_, '_>, param: &MetaItemParser) -> Option< cx.expect_no_args(param.args())?; Some(ReprC) } + Some(sym::Swift) => { + cx.check_target( + "(Swift)", + &AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Warn(Target::MacroCall), + ]), + ); + cx.expect_no_args(param.args())?; + Some(ReprSwift) + } Some(sym::simd) => { if cx.features.is_some_and(|feats| !feats.repr_simd()) { feature_err( diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index d24064b793390..02bec99ebdca1 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -76,7 +76,7 @@ pub(crate) fn conv_to_call_conv( _ => default_call_conv, }, - CanonAbi::Interrupt(_) | CanonAbi::Arm(_) | CanonAbi::Swift => { + CanonAbi::Interrupt(_) | CanonAbi::Arm(_) | CanonAbi::Swift { .. } => { sess.dcx().fatal(format!("call conv {c:?} is not yet implemented")) } CanonAbi::GpuKernel => { diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 1b7bb8c907735..b567689299437 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -248,6 +248,8 @@ pub fn conv_to_fn_attribute<'gcc>(sess: &Session, conv: CanonAbi) -> Option FnAttribute::Cold, + // gcc doesn't support Swift as far as I'm aware + CanonAbi::Swift { .. } => return None, // Functions with this calling convention can only be called from assembly, but it is // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 65bb32ee666f2..a3685d115439e 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -733,7 +733,11 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm: // possible to declare an `extern "custom"` block, so the backend still needs a calling // convention for declaring foreign functions. CanonAbi::Custom => llvm::CCallConv, - CanonAbi::Swift => llvm::SwiftCallConv, + CanonAbi::Swift { tail } => if tail { + llvm::SwiftCallConvTail + } else { + llvm::SwiftCallConv + } CanonAbi::GpuKernel => match &sess.target.arch { Arch::AmdGpu => llvm::AmdgpuKernel, Arch::Nvptx64 => llvm::PtxKernel, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1a60b59a93525..f550dbc240ebf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -167,6 +167,7 @@ pub(crate) enum CallConv { PreserveAll = 15, SwiftCallConv = 16, Tail = 18, + SwiftCallConvTail = 20, PreserveNone = 21, X86StdcallCallConv = 64, X86FastcallCallConv = 65, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index cc48f418d03db..4f89d91e4dfbe 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -164,13 +164,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::size_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); - let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); + let (llsize, _, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); OperandValue::Immediate(llsize) } + sym::stride_of_val => { + let tp_ty = fn_args.type_at(0); + let (_, meta) = args[0].val.pointer_parts(); + let (_, llstride, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); + OperandValue::Immediate(llstride) + } sym::align_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); - let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); + let (_, _, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); OperandValue::Immediate(llalign) } sym::vtable_size | sym::vtable_align => { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 14a5f71fbceaa..16d846d8d6510 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -228,7 +228,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let unaligned_offset = bx.cx().const_usize(offset.bytes()); // Get the alignment of the field - let (_, mut unsized_align) = size_of_val::size_and_align_of_dst(bx, field.ty, meta); + let (_, _, mut unsized_align) = size_of_val::size_and_align_of_dst(bx, field.ty, meta); // For packed types, we need to cap alignment. if let ty::Adt(def, _) = self.layout.ty.kind() diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 52ffc321cbb6f..002228713c58e 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -16,13 +16,14 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, t: Ty<'tcx>, info: Option, -) -> (Bx::Value, Bx::Value) { +) -> (Bx::Value, Bx::Value, Bx::Value) { let layout = bx.layout_of(t); trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout); if layout.is_sized() { - let size = bx.const_usize(layout.size.bytes()); + let size = bx.const_usize(layout.size_without_padding.bytes()); + let stride = bx.const_usize(layout.size.bytes()); let align = bx.const_usize(layout.align.bytes()); - return (size, align); + return (size, stride, align); } match t.kind() { ty::Dynamic(..) => { @@ -41,18 +42,19 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let align_bound = Align::max_for_target(bx.data_layout()).bytes().into(); bx.range_metadata(align, WrappingRange { start: 1, end: align_bound }); - (size, align) + (size, size, align) } ty::Slice(_) | ty::Str => { let unit = layout.field(bx, 0); // The info in this case is the length of the str, so the size is that // times the unit size. - ( - // All slice sizes must fit into `isize`, so this multiplication cannot - // wrap -- neither signed nor unsigned. - bx.unchecked_sumul(info.unwrap(), bx.const_usize(unit.size.bytes())), - bx.const_usize(unit.align.bytes()), - ) + let info = info.unwrap(); + // All slice sizes must fit into `isize`, so this multiplication cannot + // wrap -- neither signed nor unsigned. + let size = bx.unchecked_sumul(info, bx.const_usize(unit.size_without_padding.bytes())); + let stride = bx.unchecked_sumul(info, bx.const_usize(unit.size.bytes())); + let align = bx.const_usize(unit.align.bytes()); + (size, stride, align) } ty::Foreign(_) => { // `extern` type. We cannot compute the size, so panic. @@ -83,9 +85,10 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ); // This function does not return so we can now return whatever we want. - let size = bx.const_usize(layout.size.bytes()); + let size = bx.const_usize(layout.size_without_padding.bytes()); + let stride = bx.const_usize(layout.size.bytes()); let align = bx.const_usize(layout.align.bytes()); - (size, align) + (size, stride, align) } ty::Adt(..) | ty::Tuple(..) => { // First get the size of all statically known fields. @@ -107,7 +110,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Recurse to get the size of the dynamically sized field (must be // the last field). let field_ty = layout.field(bx, i).ty; - let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); + let (_, unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); // # First compute the dynamic alignment @@ -175,9 +178,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let addend = bx.sub(full_align, one); let add = bx.add(full_size, addend); let neg = bx.neg(full_align); - let full_size = bx.and(add, neg); + let full_stride = bx.and(add, neg); - (full_size, full_align) + (full_size, full_stride, full_align) } _ => bug!("size_and_align_of_dst: {t} not supported"), } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 45d57f77a4079..d19494c1508b6 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -430,7 +430,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout: &TyAndLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if layout.is_sized() { - return interp_ok(Some((layout.size, layout.align.abi))); + return interp_ok(Some((layout.size_without_padding, layout.align.abi))); } match layout.ty.kind() { ty::Adt(..) | ty::Tuple(..) => { @@ -473,7 +473,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // # Then compute the dynamic size let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align); - let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align); + let full_size = unsized_offset_adjusted + unsized_size; // Just for our sanitiy's sake, assert that this is equal to what codegen would compute. assert_eq!( @@ -511,6 +511,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty), } } + #[inline] pub fn size_and_align_of_val( &self, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index f8c308ece55b7..adf68cc0ca60e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -219,6 +219,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `size_of`"); } + let val = layout.size_without_padding.bytes(); + self.write_scalar(Scalar::from_target_usize(val, self), dest)?; + } + sym::stride_of => { + let tp_ty = instance.args.type_at(0); + let layout = self.layout_of(tp_ty)?; + if !layout.is_sized() { + span_bug!(self.cur_span(), "unsized type for `stride_of`"); + } let val = layout.size.bytes(); self.write_scalar(Scalar::from_target_usize(val, self), dest)?; } @@ -299,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&val, dest)?; } - sym::align_of_val | sym::size_of_val => { + sym::align_of_val | sym::size_of_val | sym::stride_of_val => { // Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be // dereferenceable! let place = self.imm_ptr_to_mplace(&self.read_immediate(&args[0])?)?; @@ -310,6 +319,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let result = match intrinsic_name { sym::align_of_val => align.bytes(), sym::size_of_val => size.bytes(), + sym::stride_of_val => size.align_to(align).bytes(), _ => bug!(), }; diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index a8f5e406e29ee..ac1dc5ec743cd 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -43,7 +43,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?; let layout = self.layout_of(ty)?; assert!(layout.is_sized(), "there are no vtables for unsized types"); - interp_ok((layout.size, layout.align.abi)) + interp_ok((layout.size_without_padding, layout.align.abi)) } pub(super) fn vtable_entries( diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index b15ea5da6f0cb..32475a9e75e0b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -288,6 +288,8 @@ declare_features! ( (internal, rustc_attrs, "1.0.0", None), /// Allows using the `#[stable]` and `#[unstable]` attributes. (internal, staged_api, "1.0.0", None), + /// Introduces the split between size and stride. + (unstable, stride, "CURRENT_RUSTC_VERSION", None), /// Perma-unstable, only used to test the `incomplete_features` lint. (incomplete, test_incomplete_feature, "1.96.0", None), /// Added for testing unstable lints; perma-unstable. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 94241e6a31eb0..f15830f44968a 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -177,6 +177,7 @@ pub enum ReprAttr { ReprInt(IntType), ReprRust, ReprC, + ReprSwift, ReprPacked(Align), ReprSimd, ReprTransparent, diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 9d8b0e101d374..d6a55747ad224 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -163,6 +163,7 @@ language_item_table! { Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); AlignOf, sym::mem_align_const, align_const, Target::AssocConst, GenericRequirement::Exact(0); SizeOf, sym::mem_size_const, size_const, Target::AssocConst, GenericRequirement::Exact(0); + StrideOf, sym::mem_stride_const, stride_const, Target::AssocConst, GenericRequirement::Exact(0); OffsetOf, sym::offset_of, offset_of, Target::Fn, GenericRequirement::Exact(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 67fddd87fbb1d..5bdff60c6c8cc 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -209,6 +209,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::sqrtf32 | sym::sqrtf64 | sym::sqrtf128 + | sym::stride_of | sym::sub_with_overflow | sym::three_way_compare | sym::truncf16 @@ -301,8 +302,8 @@ pub(crate) fn check_intrinsic_type( sym::amdgpu_dispatch_ptr => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)), sym::unreachable => (0, 0, vec![], tcx.types.never), sym::breakpoint => (0, 0, vec![], tcx.types.unit), - sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize), - sym::size_of_val | sym::align_of_val => { + sym::size_of | sym::stride_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize), + sym::size_of_val | sym::stride_of_val | sym::align_of_val => { (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } sym::size_of_type_id => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, tcx.types.usize)), diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d2430a06a0072..b7b6cc1f8fa7e 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | CanonAbi::RustCold | CanonAbi::RustPreserveNone | CanonAbi::RustTail - | CanonAbi::Swift + | CanonAbi::Swift { .. } | CanonAbi::Arm(_) | CanonAbi::X86(_) => {} } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 149fa69f2abbb..2b16b51e28aea 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1725,6 +1725,7 @@ impl<'tcx> TyCtxt<'tcx> { flags.insert(match *r { attr::ReprRust => ReprFlags::empty(), attr::ReprC => ReprFlags::IS_C, + attr::ReprSwift => ReprFlags::IS_SWIFT, attr::ReprPacked(pack) => { min_pack = Some(if let Some(min_pack) = min_pack { min_pack.min(pack) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a5ba6d2f14d12..549d0463e6495 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1184,6 +1184,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ReprAttr::ReprC => { is_c = true; } + ReprAttr::ReprSwift => {}, ReprAttr::ReprAlign(..) => {} ReprAttr::ReprPacked(_) => {} ReprAttr::ReprSimd => { diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 02674e4107c77..1414443572aaf 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -496,6 +496,7 @@ pub enum CallConvention { pub struct ReprFlags { pub is_simd: bool, pub is_c: bool, + pub is_swift: bool, pub is_transparent: bool, pub is_linear: bool, } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 31104ce897ffb..2d3f54c80e596 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -127,7 +127,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi { CanonAbi::RustPreserveNone => CallConvention::PreserveNone, CanonAbi::RustTail => CallConvention::Tail, CanonAbi::Custom => CallConvention::Custom, - CanonAbi::Swift => CallConvention::Swift, + CanonAbi::Swift { .. } => CallConvention::Swift, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => CallConvention::ArmAapcs, ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, @@ -414,6 +414,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags { ReprFlags { is_simd: self.intersects(Self::IS_SIMD), is_c: self.intersects(Self::IS_C), + is_swift: self.intersects(Self::IS_SWIFT), is_transparent: self.intersects(Self::IS_TRANSPARENT), is_linear: self.intersects(Self::IS_LINEAR), } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8d6661ca1194b..d3bd363dcce69 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -319,6 +319,7 @@ symbols! { String, Struct, StructuralPartialEq, + Swift, SymbolIntern, Sync, SyncUnsafeCell, @@ -1291,6 +1292,7 @@ symbols! { mem_drop, mem_forget, mem_size_const, + mem_stride_const, mem_swap, mem_uninitialized, mem_variant_count, @@ -2063,6 +2065,9 @@ symbols! { str_inherent_from_utf8_unchecked, str_inherent_from_utf8_unchecked_mut, strict_provenance_lints, + stride, + stride_of, + stride_of_val, string_deref_patterns, stringify, struct_field_attributes, diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index deea6465118ed..1aca365d0eebd 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -743,6 +743,38 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } + pub fn adjust_for_swift_abi(&mut self, _cx: &C) + where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec + HasX86AbiOpt, + { + for arg in self.args.iter_mut() { + if arg.is_ignore() { + continue; + } + // Small structs get their innards splattered inline + if arg.layout.layout.size.bytes() <= 24 { + let mut prefix: ArrayVec = ArrayVec::new(); + let mut size = arg.layout.size; + for _i in 0..8 { + let reg_size = match size.bytes() { + 8.. => 8, + 4.. => 4, + 2.. => 2, + 1.. => 1, + 0 => break, + }; + prefix.push(Reg { kind: RegKind::Integer, size: Size::from_bytes(reg_size) }); + size = Size::from_bytes(size.bytes() - reg_size); + } + arg.cast_to(CastTarget::prefixed( + prefix, + Uniform::new(Reg::i8(), Size::from_bytes(0)), + )); + } + } + } + pub fn adjust_for_rust_abi(&mut self, cx: &C) where Ty: TyAbiInterface<'a, C> + Copy, diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index dd69afec47975..15d0d6d4283fe 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -104,7 +104,7 @@ impl AbiMap { (ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone, (ExternAbi::RustTail, _) => CanonAbi::RustTail, - (ExternAbi::Swift, _) => CanonAbi::Swift, + (ExternAbi::Swift, _) => CanonAbi::Swift { tail: false }, (ExternAbi::System { .. }, ArchKind::X86) if os == OsKind::Windows && !has_c_varargs => diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index ad8918f70a582..87c26c52c315b 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -659,6 +659,9 @@ fn fn_abi_adjust_for_abi<'tcx>( fn_abi.adjust_for_rust_abi(cx); } else { fn_abi.adjust_for_foreign_abi(cx, abi); + if abi == ExternAbi::Swift { + fn_abi.adjust_for_swift_abi(cx); + } } } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index fad2cb08a8a64..88b0d815bfa89 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2944,7 +2944,7 @@ pub unsafe fn vtable_size(ptr: *const ()) -> usize; #[rustc_intrinsic] pub unsafe fn vtable_align(ptr: *const ()) -> usize; -/// The size of a type in bytes. +/// The size of a type in bytes, excluding alignment padding. /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. @@ -2952,14 +2952,14 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize; /// any safety invariants. /// /// More specifically, this is the offset in bytes between successive -/// items of the same type, including alignment padding. +/// items of the same type, excluding alignment padding. /// /// Note that, unlike most intrinsics, this can only be called at compile-time /// as backends do not have an implementation for it. The only caller (its /// stable counterpart) wraps this intrinsic call in a `const` block so that /// backends only see an evaluated constant. /// -/// The stabilized version of this intrinsic is [`core::mem::size_of`]. +/// The stabilized version of this intrinsic is [`core::mem::size_without_padding_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] @@ -2967,6 +2967,14 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize; #[rustc_comptime] pub fn size_of() -> usize; +/// See [`size_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic_const_stable_indirect] +#[rustc_intrinsic] +#[rustc_comptime] +pub fn stride_of() -> usize; + /// The minimum alignment of a type. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -3051,6 +3059,19 @@ pub fn variant_count() -> usize; #[rustc_intrinsic_const_stable_indirect] pub const unsafe fn size_of_val(ptr: *const T) -> usize; +/// The stride of the referenced value in bytes. +/// +/// The stabilized version of this intrinsic is [`core::mem::stride_of_val`]. +/// +/// # Safety +/// +/// See [`crate::mem::size_of_val_raw`] for safety conditions. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_intrinsic] +#[rustc_intrinsic_const_stable_indirect] +pub const unsafe fn stride_of_val(ptr: *const T) -> usize; + /// The required alignment of the referenced value. /// /// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0910e4bc718ea..bd9cb1a606c15 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -184,6 +184,7 @@ #![feature(s390x_target_feature)] #![feature(wasm_target_feature)] #![feature(x86_amx_intrinsics)] +#![feature(stride)] // tidy-alphabetical-end // allow using `core::` in intra-doc links diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 9a2ad0004ae4c..573f239208ad1 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -383,6 +383,15 @@ pub const fn size_of() -> usize { ::SIZE } +/// See [`size_of`]. +#[inline(always)] +#[must_use] +#[unstable(feature = "stride", issue = "none")] +#[rustc_diagnostic_item = "mem_stride_of"] +pub const fn stride_of() -> usize { + ::STRIDE +} + /// Returns the size of the pointed-to value in bytes. /// /// This is usually the same as [`size_of::()`]. However, when `T` *has* no @@ -468,6 +477,26 @@ pub const unsafe fn size_of_val_raw(val: *const T) -> usize { unsafe { intrinsics::size_of_val(val) } } +/// See [`size_of_val`]. +#[inline] +#[must_use] +#[unstable(feature = "stride", issue = "none")] +#[rustc_diagnostic_item = "mem_stride_of_val"] +pub const fn stride_of_val(val: &T) -> usize { + // SAFETY: `val` is a reference, so it's a valid raw pointer + unsafe { intrinsics::stride_of_val(val) } +} + +/// See [`size_of_val`]. +#[inline] +#[must_use] +#[unstable(feature = "stride", issue = "none")] +#[rustc_diagnostic_item = "mem_stride_without_padding_of_val_raw"] +pub const unsafe fn stride_of_val_raw(val: *const T) -> usize { + // SAFETY: the caller must provide a valid raw pointer + unsafe { intrinsics::stride_of_val(val) } +} + /// Returns the [ABI]-required minimum alignment of a type in bytes. /// /// Every reference to a value of the type `T` must be a multiple of this number. @@ -1219,7 +1248,7 @@ pub const unsafe fn transmute_prefix(src: Src) -> Dst { b: ManuallyDrop, } - match const { Ord::cmp(&Src::SIZE, &Dst::SIZE) } { + match const { Ord::cmp(&Src::STRIDE, &Dst::STRIDE) } { // SAFETY: When Dst is bigger, the union is the size of Dst Ordering::Less => unsafe { let a = transmute_neo(src); @@ -1263,7 +1292,7 @@ pub const unsafe fn transmute_prefix(src: Src) -> Dst { #[inline] #[rustc_no_writable] pub const unsafe fn transmute_neo(src: Src) -> Dst { - const { assert!(Src::SIZE == Dst::SIZE) }; + const { assert!(Src::STRIDE == Dst::STRIDE) }; // SAFETY: the const-assert just checked that they're the same size, // and any other safety invariants need to be upheld by the caller. @@ -1463,6 +1492,11 @@ pub trait SizedTypeProperties: Sized { #[lang = "mem_size_const"] const SIZE: usize = intrinsics::size_of::(); + #[doc(hidden)] + #[unstable(feature = "sized_type_properties", issue = "none")] + #[lang = "mem_stride_const"] + const STRIDE: usize = intrinsics::stride_of::(); + #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] #[lang = "mem_align_const"] @@ -1502,7 +1536,7 @@ pub trait SizedTypeProperties: Sized { /// ``` #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] - const IS_ZST: bool = Self::SIZE == 0; + const IS_ZST: bool = Self::STRIDE == 0; #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] @@ -1510,7 +1544,7 @@ pub trait SizedTypeProperties: Sized { // SAFETY: if the type is instantiated, rustc already ensures that its // layout is valid. Use the unchecked constructor to avoid inserting a // panicking codepath that needs to be optimized out. - unsafe { Layout::from_size_align_unchecked(Self::SIZE, Self::ALIGN) } + unsafe { Layout::from_size_align_unchecked(Self::STRIDE, Self::ALIGN) } }; /// The largest safe length for a `[Self]`. @@ -1519,7 +1553,7 @@ pub trait SizedTypeProperties: Sized { /// which is never allowed for a single object. #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] - const MAX_SLICE_LEN: usize = match Self::SIZE { + const MAX_SLICE_LEN: usize = match Self::STRIDE { 0 => usize::MAX, n => (isize::MAX as usize) / n, }; diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 3a62e7f61b2b4..a131c73460514 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -153,7 +153,7 @@ where // for reading `len` values, which also means the size is guaranteed // not to overflow because it exists in memory; unsafe { - let size = crate::intrinsics::unchecked_mul(len, Self::SIZE); + let size = crate::intrinsics::unchecked_mul(len, Self::STRIDE); compare_bytes(lhs as _, rhs as _, size) == 0 } } diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr index 73e1578242675..0b217b5869aa0 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-1.stderr @@ -1,7 +1,7 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | - = note: evaluation of ` as std::mem::SizedTypeProperties>::SIZE` failed here + = note: evaluation of ` as std::mem::SizedTypeProperties>::STRIDE` failed here note: the above error was encountered while instantiating `fn std::mem::size_of::>` --> $DIR/debuginfo-type-name-layout-ice-94961-1.rs:13:5 diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr index 4ce1e2e407e9d..9785948d0432c 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.stderr @@ -1,7 +1,7 @@ error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | - = note: evaluation of ` as std::mem::SizedTypeProperties>::SIZE` failed here + = note: evaluation of ` as std::mem::SizedTypeProperties>::STRIDE` failed here note: the above error was encountered while instantiating `fn std::mem::size_of::>` --> $DIR/debuginfo-type-name-layout-ice-94961-2.rs:16:5 diff --git a/tests/ui/feature-gates/feature-gate-stride.rs b/tests/ui/feature-gates/feature-gate-stride.rs new file mode 100644 index 0000000000000..21ed123b6da01 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-stride.rs @@ -0,0 +1,6 @@ +use std::mem; + +fn main() { + let tmp = mem::stride_of::(); + //~^ ERROR use of unstable library feature `stride` +} diff --git a/tests/ui/feature-gates/feature-gate-stride.stderr b/tests/ui/feature-gates/feature-gate-stride.stderr new file mode 100644 index 0000000000000..321293538699f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-stride.stderr @@ -0,0 +1,12 @@ +error[E0658]: use of unstable library feature `stride` + --> $DIR/feature-gate-stride.rs:4:15 + | +LL | let tmp = mem::stride_of::(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(stride)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/layout/layout-cycle.stderr b/tests/ui/layout/layout-cycle.stderr index 346bae58c1b2e..52f601e358f4f 100644 --- a/tests/ui/layout/layout-cycle.stderr +++ b/tests/ui/layout/layout-cycle.stderr @@ -11,6 +11,7 @@ LL | type I: Tr; | ^^^^^^^^^^ = note: ...which again requires computing layout of `S>`, completing the cycle note: cycle used when const-evaluating + checking `core::mem::SizedTypeProperties::SIZE` +note: cycle used when const-evaluating + checking `core::mem::SizedTypeProperties::STRIDE` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL = note: for more information, see and diff --git a/tests/ui/layout/swift/struct-offsets.rs b/tests/ui/layout/swift/struct-offsets.rs new file mode 100644 index 0000000000000..c46251ce5f0cf --- /dev/null +++ b/tests/ui/layout/swift/struct-offsets.rs @@ -0,0 +1,36 @@ +//@ run-pass +//@ reference: layout.swift.struct-offsets +//@ edition: 2024 + +// LLVM <{ i64, i8 }> +#[repr(Swift)] +struct S { + a: isize, + b: u8, +} + +// LLVM <{ i8, [7 x i8], <{ i64, i8 }>, i8, [6 x i8] i64, i64 }> +#[repr(Swift)] +struct S2 { + a: u8, + b: S, + c: u8, + d: isize, + e: (), + f: isize, +} + +fn main() { + assert_eq!(core::mem::offset_of!(S, a), 0); + assert_eq!(core::mem::offset_of!(S, b), 8); + + assert_eq!(core::mem::offset_of!(S2, a), 0); + assert_eq!(core::mem::offset_of!(S2, b), 8); + assert_eq!(core::mem::offset_of!(S2, c), 17); + assert_eq!(core::mem::offset_of!(S2, d), 24); + assert_eq!(core::mem::offset_of!(S2, e), 32); + assert_eq!(core::mem::offset_of!(S2, f), 32); + + assert_eq!(core::mem::size_of::(), 40); + assert_eq!(core::mem::align_of::(), 8); +}