diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 8d3c10fd770a6..99e3f5b17a66c 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -172,6 +172,8 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug { fn is_tuple(this: TyAndLayout<'a, Self>) -> bool; fn is_unit(this: TyAndLayout<'a, Self>) -> bool; fn is_transparent(this: TyAndLayout<'a, Self>) -> bool; + /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. + fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool; } impl<'a, Ty> TyAndLayout<'a, Ty> { @@ -269,6 +271,34 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } + /// If this method returns `true`, then this type should always have a `PassMode` of + /// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a + /// non-Rustic ABI (this is true for structs annotated with the + /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute). + /// + /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike + /// C any changes the caller makes to the passed value will not be reflected in the callee, so + /// the attribute is only useful for types where observing the value in the caller after the + /// function call isn't allowed (a.k.a. `va_list`). + /// + /// This function handles transparent types automatically. + pub fn pass_indirectly_in_non_rustic_abis(mut self, cx: &C) -> bool + where + Ty: TyAbiInterface<'a, C> + Copy, + { + loop { + if Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self) { + return true; + } else if self.is_transparent() + && let Some((_, field)) = self.non_1zst_field(cx) + { + self = field; + } else { + return false; + } + } + } + /// Finds the one field that is not a 1-ZST. /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. pub fn non_1zst_field(&self, cx: &C) -> Option<(FieldIdx, Self)> diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index de44c8755a078..05b25da8043ad 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -88,14 +88,17 @@ bitflags! { const IS_C = 1 << 0; const IS_SIMD = 1 << 1; const IS_TRANSPARENT = 1 << 2; - // Internal only for now. If true, don't reorder fields. - // On its own it does not prevent ABI optimizations. + /// Internal only for now. If true, don't reorder fields. + /// On its own it does not prevent ABI optimizations. const IS_LINEAR = 1 << 3; - // If true, the type's crate has opted into layout randomization. - // Other flags can still inhibit reordering and thus randomization. - // The seed stored in `ReprOptions.field_shuffle_seed`. + /// If true, the type's crate has opted into layout randomization. + /// Other flags can still inhibit reordering and thus randomization. + /// The seed stored in `ReprOptions.field_shuffle_seed`. const RANDOMIZE_LAYOUT = 1 << 4; - // Any of these flags being set prevent field reordering optimisation. + /// If true, the type is always passed indirectly by non-Rustic ABIs. + /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. + const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5; + /// Any of these flags being set prevent field reordering optimisation. const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() | ReprFlags::IS_LINEAR.bits(); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 7978bf28214cf..5b76e74e0f116 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -673,3 +673,12 @@ impl SingleAttributeParser for SanitizeParser { Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span }) } } + +pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser; + +impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser { + const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index e8bb4caa41664..6b8f2772e43d5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,8 +20,9 @@ use crate::attributes::allow_unstable::{ use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, - NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser, - TargetFeatureParser, TrackCallerParser, UsedParser, + NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, + RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser, + TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ @@ -238,6 +239,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 220388ffe4353..0bb32fa0f0d02 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -652,6 +652,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"), WarnFollowing, EncodeCrossCrate::No ), + // See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details. + rustc_attr!( + rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, + "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis." + ), // Limits: ungated!( diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index beeca7332cb17..ef3611fa460dc 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -669,6 +669,9 @@ pub enum AttributeKind { /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, + /// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]` + RustcPassIndirectlyInNonRusticAbis(Span), + /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`. RustcSimdMonomorphizeLaneLimit(Limit), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 1611b865c7726..9cdec10b5fe72 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -89,6 +89,7 @@ impl AttributeKind { RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, + RustcPassIndirectlyInNonRusticAbis(..) => No, RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate Sanitize { .. } => No, ShouldPanic { .. } => No, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 507a25a432594..a4c7e603c920c 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -3,7 +3,7 @@ use std::{cmp, fmt}; use rustc_abi::{ AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo, - PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, + PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, TyAbiInterface, VariantIdx, Variants, }; use rustc_error_messages::DiagMessage; @@ -1169,6 +1169,11 @@ where fn is_transparent(this: TyAndLayout<'tcx>) -> bool { matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent()) } + + /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. + fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool { + matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS)) + } } /// Calculates whether a function's ABI can unwind or not. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ce4de6b95e0bb..8dbcbf1d7a87b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1524,6 +1524,14 @@ impl<'tcx> TyCtxt<'tcx> { flags.insert(ReprFlags::IS_LINEAR); } + // See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details. + if find_attr!( + self.get_all_attrs(did), + AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) + ) { + flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS); + } + ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4ea237cfa0321..7a071c2960221 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -283,6 +283,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ObjcSelector { .. } | AttributeKind::RustcCoherenceIsCore(..) | AttributeKind::DebuggerVisualizer(..) + | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a177cbe50142..a583e6381699a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1935,6 +1935,7 @@ symbols! { rustc_partition_codegened, rustc_partition_reused, rustc_pass_by_value, + rustc_pass_indirectly_in_non_rustic_abis, rustc_peek, rustc_peek_liveness, rustc_peek_maybe_init, diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs index 5c23e7036b043..b86d0baeb942e 100644 --- a/compiler/rustc_target/src/callconv/aarch64.rs +++ b/compiler/rustc_target/src/callconv/aarch64.rs @@ -114,6 +114,10 @@ where // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { if kind == AbiKind::DarwinPCS { // On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits, diff --git a/compiler/rustc_target/src/callconv/amdgpu.rs b/compiler/rustc_target/src/callconv/amdgpu.rs index 3ec6d0b3da20b..98ab3ce8eb746 100644 --- a/compiler/rustc_target/src/callconv/amdgpu.rs +++ b/compiler/rustc_target/src/callconv/amdgpu.rs @@ -10,11 +10,15 @@ where ret.extend_integer_width_to(32); } -fn classify_arg<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index abc9a404e2ea4..4c1ff27aac509 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -65,6 +65,10 @@ where // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; diff --git a/compiler/rustc_target/src/callconv/avr.rs b/compiler/rustc_target/src/callconv/avr.rs index 0d690eff68dcf..0646d3c8ea1a4 100644 --- a/compiler/rustc_target/src/callconv/avr.rs +++ b/compiler/rustc_target/src/callconv/avr.rs @@ -30,6 +30,8 @@ //! compatible with AVR-GCC - Rust and AVR-GCC only differ in the small amount //! of compiler frontend specific calling convention logic implemented here. +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret_ty(ret: &mut ArgAbi<'_, Ty>) { @@ -38,13 +40,23 @@ fn classify_ret_ty(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg_ty(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() { arg.make_indirect(); } } -pub(crate) fn compute_abi_info(fty: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fty.ret.is_ignore() { classify_ret_ty(&mut fty.ret); } @@ -54,6 +66,6 @@ pub(crate) fn compute_abi_info(fty: &mut FnAbi<'_, Ty>) { continue; } - classify_arg_ty(arg); + classify_arg_ty(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/bpf.rs b/compiler/rustc_target/src/callconv/bpf.rs index f958aeb9bb654..453716d8d0426 100644 --- a/compiler/rustc_target/src/callconv/bpf.rs +++ b/compiler/rustc_target/src/callconv/bpf.rs @@ -1,4 +1,6 @@ // see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -9,7 +11,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 { arg.make_indirect(); } else { @@ -17,7 +26,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -26,6 +38,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/csky.rs b/compiler/rustc_target/src/callconv/csky.rs index cf289e639eac4..95741f137feab 100644 --- a/compiler/rustc_target/src/callconv/csky.rs +++ b/compiler/rustc_target/src/callconv/csky.rs @@ -4,6 +4,8 @@ // Reference: Clang CSKY lowering code // https://github.com/llvm/llvm-project/blob/4a074f32a6914f2a8d7215d78758c24942dddc3d/clang/lib/CodeGen/Targets/CSKY.cpp#L76-L162 +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform}; fn classify_ret(arg: &mut ArgAbi<'_, Ty>) { @@ -27,11 +29,18 @@ fn classify_ret(arg: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !arg.layout.is_sized() { // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } // For argument type, the first 4*XLen parts of aggregate will be passed // in registers, and the rest will be passed in stack. // So we can coerce to integers directly and let backend handle it correctly. @@ -47,7 +56,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -56,6 +68,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/hexagon.rs b/compiler/rustc_target/src/callconv/hexagon.rs index d4f6dd0a5b4d3..e08e6daa7405a 100644 --- a/compiler/rustc_target/src/callconv/hexagon.rs +++ b/compiler/rustc_target/src/callconv/hexagon.rs @@ -1,3 +1,5 @@ +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -8,7 +10,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 { arg.make_indirect(); } else { @@ -16,7 +25,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -25,6 +37,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index bc3c9601fa3d3..1d1f390bedab6 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -284,9 +284,15 @@ fn classify_arg<'a, Ty, C>( Ty: TyAbiInterface<'a, C> + Copy, { if !arg.layout.is_sized() { + // FIXME: Update avail_gprs? // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *avail_gprs = (*avail_gprs).saturating_sub(1); + return; + } if !is_vararg { match should_use_fp_conv(cx, &arg.layout, xlen, flen) { Some(FloatConv::Float(f)) if *avail_fprs >= 1 => { diff --git a/compiler/rustc_target/src/callconv/m68k.rs b/compiler/rustc_target/src/callconv/m68k.rs index 0b637e1e27a5b..f4668b4afbd20 100644 --- a/compiler/rustc_target/src/callconv/m68k.rs +++ b/compiler/rustc_target/src/callconv/m68k.rs @@ -1,3 +1,5 @@ +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { @@ -8,11 +10,18 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !arg.layout.is_sized() { // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() { arg.pass_by_stack_offset(None); } else { @@ -20,7 +29,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -29,6 +41,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/mips.rs b/compiler/rustc_target/src/callconv/mips.rs index 8ffd7bd177849..d424214aa497e 100644 --- a/compiler/rustc_target/src/callconv/mips.rs +++ b/compiler/rustc_target/src/callconv/mips.rs @@ -1,4 +1,4 @@ -use rustc_abi::{HasDataLayout, Size}; +use rustc_abi::{HasDataLayout, Size, TyAbiInterface}; use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform}; @@ -14,15 +14,22 @@ where } } -fn classify_arg(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !arg.layout.is_sized() { + // FIXME: Update offset? // Not touching this... return; } let dl = cx.data_layout(); + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *offset += dl.pointer_size(); + return; + } let size = arg.layout.size; let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); @@ -36,8 +43,9 @@ where *offset = offset.align_to(align) + size.align_to(align); } -pub(crate) fn compute_abi_info(cx: &C, fn_abi: &mut FnAbi<'_, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { let mut offset = Size::ZERO; diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 8386a15933c98..313ad6ddce800 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -82,6 +82,10 @@ where extend_integer_width_mips(arg, 64); return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } let dl = cx.data_layout(); let size = arg.layout.size; diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index c59af581a1fe4..1e7295d499d3d 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -676,30 +676,30 @@ impl<'a, Ty> FnAbi<'a, Ty> { } "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), - "avr" => avr::compute_abi_info(self), + "avr" => avr::compute_abi_info(cx, self), "loongarch32" | "loongarch64" => loongarch::compute_abi_info(cx, self), - "m68k" => m68k::compute_abi_info(self), - "csky" => csky::compute_abi_info(self), + "m68k" => m68k::compute_abi_info(cx, self), + "csky" => csky::compute_abi_info(cx, self), "mips" | "mips32r6" => mips::compute_abi_info(cx, self), "mips64" | "mips64r6" => mips64::compute_abi_info(cx, self), "powerpc" => powerpc::compute_abi_info(cx, self), "powerpc64" => powerpc64::compute_abi_info(cx, self), "s390x" => s390x::compute_abi_info(cx, self), - "msp430" => msp430::compute_abi_info(self), + "msp430" => msp430::compute_abi_info(cx, self), "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), "nvptx64" => { if abi == ExternAbi::PtxKernel || abi == ExternAbi::GpuKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) } else { - nvptx64::compute_abi_info(self) + nvptx64::compute_abi_info(cx, self) } } - "hexagon" => hexagon::compute_abi_info(self), + "hexagon" => hexagon::compute_abi_info(cx, self), "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), "wasm32" | "wasm64" => wasm::compute_abi_info(cx, self), - "bpf" => bpf::compute_abi_info(self), + "bpf" => bpf::compute_abi_info(cx, self), arch => panic!("no lowering implemented for {arch}"), } } diff --git a/compiler/rustc_target/src/callconv/msp430.rs b/compiler/rustc_target/src/callconv/msp430.rs index 3b53d183ddcda..7d2336346beb5 100644 --- a/compiler/rustc_target/src/callconv/msp430.rs +++ b/compiler/rustc_target/src/callconv/msp430.rs @@ -1,6 +1,8 @@ // Reference: MSP430 Embedded Application Binary Interface // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; // 3.5 Structures or Unions Passed and Returned by Reference @@ -17,7 +19,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 { arg.make_indirect(); } else { @@ -25,7 +34,10 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -34,6 +46,6 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index dc32dd87a7e76..a19b89c0132f8 100644 --- a/compiler/rustc_target/src/callconv/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs @@ -11,7 +11,14 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if arg.layout.is_aggregate() && arg.layout.is_sized() { classify_aggregate(arg) } else if arg.layout.size.bits() < 32 && arg.layout.is_sized() { @@ -81,7 +88,10 @@ where } } -pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } @@ -90,7 +100,7 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { if arg.is_ignore() { continue; } - classify_arg(arg); + classify_arg(cx, arg); } } diff --git a/compiler/rustc_target/src/callconv/powerpc.rs b/compiler/rustc_target/src/callconv/powerpc.rs index 2f6129626b812..67066672eca3f 100644 --- a/compiler/rustc_target/src/callconv/powerpc.rs +++ b/compiler/rustc_target/src/callconv/powerpc.rs @@ -1,3 +1,5 @@ +use rustc_abi::TyAbiInterface; + use crate::callconv::{ArgAbi, FnAbi}; use crate::spec::HasTargetSpec; @@ -9,7 +11,10 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn classify_arg(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) { +fn classify_arg<'a, Ty, C: HasTargetSpec>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if arg.is_ignore() { // powerpc-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs. if cx.target_spec().os == "linux" @@ -20,14 +25,17 @@ fn classify_arg(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) { } return; } - if arg.layout.is_aggregate() { + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) || arg.layout.is_aggregate() { arg.make_indirect(); } else { arg.extend_integer_width_to(32); } } -pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ if !fn_abi.ret.is_ignore() { classify_ret(&mut fn_abi.ret); } diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index be1d13816eff7..380b280fbc644 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -52,6 +52,10 @@ where // Not touching this... return; } + if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 16de3fe070dd4..c4310bf6ccfb0 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -290,9 +290,15 @@ fn classify_arg<'a, Ty, C>( Ty: TyAbiInterface<'a, C> + Copy, { if !arg.layout.is_sized() { + // FIXME: Update avail_gprs? // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *avail_gprs = (*avail_gprs).saturating_sub(1); + return; + } if !is_vararg { match should_use_fp_conv(cx, &arg.layout, xlen, flen) { Some(FloatConv::Float(f)) if *avail_fprs >= 1 => { diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index d2ae404b23b8b..c2f2b47690cab 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -37,6 +37,10 @@ where } return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } let size = arg.layout.size; if size.bits() <= 128 { diff --git a/compiler/rustc_target/src/callconv/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs index 8ffd7bd177849..d424214aa497e 100644 --- a/compiler/rustc_target/src/callconv/sparc.rs +++ b/compiler/rustc_target/src/callconv/sparc.rs @@ -1,4 +1,4 @@ -use rustc_abi::{HasDataLayout, Size}; +use rustc_abi::{HasDataLayout, Size, TyAbiInterface}; use crate::callconv::{ArgAbi, FnAbi, Reg, Uniform}; @@ -14,15 +14,22 @@ where } } -fn classify_arg(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, offset: &mut Size) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !arg.layout.is_sized() { + // FIXME: Update offset? // Not touching this... return; } let dl = cx.data_layout(); + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + *offset += dl.pointer_size(); + return; + } let size = arg.layout.size; let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); @@ -36,8 +43,9 @@ where *offset = offset.align_to(align) + size.align_to(align); } -pub(crate) fn compute_abi_info(cx: &C, fn_abi: &mut FnAbi<'_, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where + Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { let mut offset = Size::ZERO; diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 62c8ed1dc21b1..911eaaf08f825 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -140,6 +140,10 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; diff --git a/compiler/rustc_target/src/callconv/wasm.rs b/compiler/rustc_target/src/callconv/wasm.rs index a308f378ee871..5be8cd5d88f26 100644 --- a/compiler/rustc_target/src/callconv/wasm.rs +++ b/compiler/rustc_target/src/callconv/wasm.rs @@ -52,6 +52,10 @@ where // Not touching this... return; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + return; + } arg.extend_integer_width_to(32); if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) { arg.make_indirect(); diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 918b71c80c4f0..93dc60dc1593e 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -64,6 +64,11 @@ where continue; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + continue; + } + let t = cx.target_spec(); let align_4 = Align::from_bytes(4).unwrap(); let align_16 = Align::from_bytes(16).unwrap(); diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index d8db7ed6e4c0f..04eecbfbc8dd6 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -183,9 +183,15 @@ where let mut x86_64_arg_or_ret = |arg: &mut ArgAbi<'a, Ty>, is_arg: bool| { if !arg.layout.is_sized() { + // FIXME: Update int_regs? // Not touching this... return; } + if is_arg && arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + int_regs = int_regs.saturating_sub(1); + arg.make_indirect(); + return; + } let mut cls_or_mem = classify_arg(cx, arg); if is_arg { diff --git a/compiler/rustc_target/src/callconv/x86_win32.rs b/compiler/rustc_target/src/callconv/x86_win32.rs index 554a7368848b5..824e7cc098a46 100644 --- a/compiler/rustc_target/src/callconv/x86_win32.rs +++ b/compiler/rustc_target/src/callconv/x86_win32.rs @@ -46,6 +46,11 @@ pub(crate) fn compute_abi_info<'a, Ty, C>( continue; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + continue; + } + // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 // See https://reviews.llvm.org/D72114 for Clang behavior diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 8f8597ea662a8..85ee59eabc7c4 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -1,11 +1,14 @@ -use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size}; +use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size, TyAbiInterface}; use crate::callconv::{ArgAbi, FnAbi, Reg}; use crate::spec::{HasTargetSpec, RustcAbi}; // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing -pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { +pub(crate) fn compute_abi_info<'a, Ty, C: HasTargetSpec>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| { match a.layout.backend_repr { BackendRepr::Memory { sized: false } => {} @@ -59,6 +62,10 @@ pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<' arg.make_indirect_from_ignore(); continue; } + if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + arg.make_indirect(); + continue; + } fixup(arg, false); } // FIXME: We should likely also do something about ZST return types, similar to above. diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index 561ee98787dee..4dc9fad650636 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -15,7 +15,7 @@ const NUM_RET_GPRS: u64 = 4; const MAX_ARG_IN_REGS_SIZE: u64 = NUM_ARG_GPRS * 32; const MAX_RET_IN_REGS_SIZE: u64 = NUM_RET_GPRS * 32; -fn classify_ret_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>) +fn classify_ret_ty<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, { @@ -26,7 +26,7 @@ where // The rules for return and argument types are the same, // so defer to `classify_arg_ty`. let mut arg_gprs_left = NUM_RET_GPRS; - classify_arg_ty(arg, &mut arg_gprs_left, MAX_RET_IN_REGS_SIZE); + classify_arg_ty(cx, arg, &mut arg_gprs_left, true); // Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisible reference match arg.mode { super::PassMode::Indirect { attrs: _, meta_attrs: _, ref mut on_stack } => { @@ -36,12 +36,24 @@ where } } -fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, max_size: u64) -where +fn classify_arg_ty<'a, Ty, C>( + cx: &C, + arg: &mut ArgAbi<'a, Ty>, + arg_gprs_left: &mut u64, + is_ret: bool, +) where Ty: TyAbiInterface<'a, C> + Copy, { assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow"); + let max_size = if is_ret { MAX_RET_IN_REGS_SIZE } else { MAX_ARG_IN_REGS_SIZE }; + + if !is_ret && arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + *arg_gprs_left = arg_gprs_left.saturating_sub(1); + arg.make_indirect(); + return; + } + // Ignore empty structs/unions. if arg.layout.is_zst() { return; @@ -95,13 +107,13 @@ where } } -pub(crate) fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { if !fn_abi.ret.is_ignore() { - classify_ret_ty(&mut fn_abi.ret); + classify_ret_ty(cx, &mut fn_abi.ret); } let mut arg_gprs_left = NUM_ARG_GPRS; @@ -110,7 +122,7 @@ where if arg.is_ignore() { continue; } - classify_arg_ty(arg, &mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE); + classify_arg_ty(cx, arg, &mut arg_gprs_left, false); } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index e4ed084b073b6..3580eea92d7d9 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,3 +1,4 @@ +use std::assert_matches::assert_matches; use std::iter; use rustc_abi::Primitive::Pointer; @@ -387,6 +388,12 @@ fn fn_abi_sanity_check<'tcx>( if let PassMode::Indirect { on_stack, .. } = arg.mode { assert!(!on_stack, "rust abi shouldn't use on_stack"); } + } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) { + assert_matches!( + arg.mode, + PassMode::Indirect { on_stack: false, .. }, + "the {spec_abi} ABI does not implement `#[rustc_pass_indirectly_in_non_rustic_abis]`" + ); } match &arg.mode { diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 46ccf330d1c22..3c9587d383e30 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -299,3 +299,15 @@ impl<'f> Drop for VaListImpl<'f> { // This works for now, since `va_end` is a no-op on all current LLVM targets. } } + +// Checks (via an assert in `compiler/rustc_ty_utils/src/abi.rs`) that the C ABI for the current +// target correctly implements `rustc_pass_indirectly_in_non_rustic_abis`. +const _: () = { + #[repr(C)] + #[rustc_pass_indirectly_in_non_rustic_abis] + struct Type(usize); + + const extern "C" fn c(_: Type) {} + + c(Type(0)) +}; diff --git a/tests/ui/abi/pass-indirectly-attr.rs b/tests/ui/abi/pass-indirectly-attr.rs new file mode 100644 index 0000000000000..17a81523a2164 --- /dev/null +++ b/tests/ui/abi/pass-indirectly-attr.rs @@ -0,0 +1,37 @@ +//@ check-fail +//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED" +//@ compile-flags: -O + +#![feature(rustc_attrs)] +#![crate_type = "lib"] + +#[repr(C)] +#[rustc_pass_indirectly_in_non_rustic_abis] +pub struct Type(u8); + +#[rustc_abi(debug)] +pub extern "C" fn extern_c(_: Type) {} +//~^ ERROR fn_abi_of(extern_c) = FnAbi { +//~| ERROR mode: Indirect +//~| ERROR on_stack: false, +//~| ERROR conv: C, + +#[rustc_abi(debug)] +pub extern "Rust" fn extern_rust(_: Type) {} +//~^ ERROR fn_abi_of(extern_rust) = FnAbi { +//~| ERROR mode: Cast +//~| ERROR conv: Rust + +#[repr(transparent)] +struct Inner(u64); + +#[rustc_pass_indirectly_in_non_rustic_abis] +#[repr(transparent)] +struct Wrapper(Inner); + +#[rustc_abi(debug)] +pub extern "C" fn wrapped_transparent(_: Wrapper) {} +//~^ ERROR fn_abi_of(wrapped_transparent) = FnAbi { +//~| ERROR mode: Indirect { +//~| ERROR on_stack: false, +//~| ERROR conv: C diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr new file mode 100644 index 0000000000000..96db19051a980 --- /dev/null +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -0,0 +1,272 @@ +error: fn_abi_of(extern_c) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: Type, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: NoAlias | CapturesAddress | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(1 bytes), + pointee_align: Some( + Align(1 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: C, + can_unwind: false, + } + --> $DIR/pass-indirectly-attr.rs:13:1 + | +LL | pub extern "C" fn extern_c(_: Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(extern_rust) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: Type, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Cast { + pad_i32: false, + cast: CastTarget { + prefix: [ + None, + None, + None, + None, + None, + None, + None, + None, + ], + rest_offset: None, + rest: Uniform { + unit: Reg { + kind: Integer, + size: Size(1 bytes), + }, + total: Size(1 bytes), + is_consecutive: false, + }, + attrs: ArgAttributes { + regular: , + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + }, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: true, + } + --> $DIR/pass-indirectly-attr.rs:20:1 + | +LL | pub extern "Rust" fn extern_rust(_: Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(wrapped_transparent) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: Wrapper, + layout: Layout { + size: Size(8 bytes), + align: AbiAlign { + abi: Align(8 bytes), + }, + backend_repr: Scalar( + Initialized { + value: Int( + I64, + false, + ), + valid_range: 0..=18446744073709551615, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(8 bytes), + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: NoAlias | CapturesAddress | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(8 bytes), + pointee_align: Some( + Align(8 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: C, + can_unwind: false, + } + --> $DIR/pass-indirectly-attr.rs:33:1 + | +LL | pub extern "C" fn wrapped_transparent(_: Wrapper) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/attributes/pass-indirectly.rs b/tests/ui/attributes/pass-indirectly.rs new file mode 100644 index 0000000000000..0eacffbf01fbe --- /dev/null +++ b/tests/ui/attributes/pass-indirectly.rs @@ -0,0 +1,15 @@ +//@ check-fail + +#![feature(rustc_attrs)] +#![crate_type = "lib"] + +#[rustc_pass_indirectly_in_non_rustic_abis] +//~^ ERROR: `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute cannot be used on functions +fn not_a_struct() {} + +#[repr(C)] +#[rustc_pass_indirectly_in_non_rustic_abis] +struct YesAStruct { + foo: u8, + bar: u16, +} diff --git a/tests/ui/attributes/pass-indirectly.stderr b/tests/ui/attributes/pass-indirectly.stderr new file mode 100644 index 0000000000000..2011f3d928f69 --- /dev/null +++ b/tests/ui/attributes/pass-indirectly.stderr @@ -0,0 +1,10 @@ +error: `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute cannot be used on functions + --> $DIR/pass-indirectly.rs:6:1 + | +LL | #[rustc_pass_indirectly_in_non_rustic_abis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_pass_indirectly_in_non_rustic_abis]` can only be applied to structs + +error: aborting due to 1 previous error +