Skip to content

Commit a5a5b02

Browse files
committed
Add #[rustc_pass_indirectly_in_non_rustic_abis]
1 parent 981353c commit a5a5b02

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+437
-56
lines changed

compiler/rustc_abi/src/layout/ty.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
172172
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
173173
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
174174
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
175+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
176+
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
175177
}
176178

177179
impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -269,6 +271,29 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
269271
Ty::is_transparent(self)
270272
}
271273

274+
/// If this method returns `true`, then this type should always have a `PassMode` of
275+
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
276+
/// non-Rustic ABI (this is true for structs annotated with the
277+
/// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute).
278+
///
279+
/// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike
280+
/// C any changes the caller makes to the passed value will not be reflected in the callee, so
281+
/// the attribute is only useful for types where observing the value in the caller after the
282+
/// function call isn't allowed (a.k.a. `va_list`).
283+
///
284+
/// This function handles transparent types automatically.
285+
pub fn pass_indirectly_in_non_rustic_abis<C>(mut self, cx: &C) -> bool
286+
where
287+
Ty: TyAbiInterface<'a, C> + Copy,
288+
{
289+
while self.is_transparent()
290+
&& let Some((_, field)) = self.non_1zst_field(cx)
291+
{
292+
self = field;
293+
}
294+
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
295+
}
296+
272297
/// Finds the one field that is not a 1-ZST.
273298
/// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
274299
pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>

compiler/rustc_abi/src/lib.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,17 @@ bitflags! {
8888
const IS_C = 1 << 0;
8989
const IS_SIMD = 1 << 1;
9090
const IS_TRANSPARENT = 1 << 2;
91-
// Internal only for now. If true, don't reorder fields.
92-
// On its own it does not prevent ABI optimizations.
91+
/// Internal only for now. If true, don't reorder fields.
92+
/// On its own it does not prevent ABI optimizations.
9393
const IS_LINEAR = 1 << 3;
94-
// If true, the type's crate has opted into layout randomization.
95-
// Other flags can still inhibit reordering and thus randomization.
96-
// The seed stored in `ReprOptions.field_shuffle_seed`.
94+
/// If true, the type's crate has opted into layout randomization.
95+
/// Other flags can still inhibit reordering and thus randomization.
96+
/// The seed stored in `ReprOptions.field_shuffle_seed`.
9797
const RANDOMIZE_LAYOUT = 1 << 4;
98-
// Any of these flags being set prevent field reordering optimisation.
98+
/// If true, the type is always passed indirectly by non-Rustic ABIs.
99+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
100+
const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
101+
/// Any of these flags being set prevent field reordering optimisation.
99102
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
100103
| ReprFlags::IS_SIMD.bits()
101104
| ReprFlags::IS_LINEAR.bits();

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,3 +673,12 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
673673
Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span })
674674
}
675675
}
676+
677+
pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
678+
679+
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {
680+
const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
681+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
682+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
683+
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
684+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ use crate::attributes::allow_unstable::{
2020
use crate::attributes::body::CoroutineParser;
2121
use crate::attributes::codegen_attrs::{
2222
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
23-
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser,
24-
TargetFeatureParser, TrackCallerParser, UsedParser,
23+
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
24+
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
25+
TrackCallerParser, UsedParser,
2526
};
2627
use crate::attributes::confusables::ConfusablesParser;
2728
use crate::attributes::crate_level::{
@@ -238,6 +239,7 @@ attribute_parsers!(
238239
Single<WithoutArgs<ProcMacroParser>>,
239240
Single<WithoutArgs<PubTransparentParser>>,
240241
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
242+
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
241243
Single<WithoutArgs<SpecializationTraitParser>>,
242244
Single<WithoutArgs<StdInternalSymbolParser>>,
243245
Single<WithoutArgs<TrackCallerParser>>,

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
652652
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"),
653653
WarnFollowing, EncodeCrossCrate::No
654654
),
655+
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
656+
rustc_attr!(
657+
rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing,
658+
EncodeCrossCrate::No,
659+
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis."
660+
),
655661

656662
// Limits:
657663
ungated!(

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,9 @@ pub enum AttributeKind {
669669
/// Represents `#[rustc_object_lifetime_default]`.
670670
RustcObjectLifetimeDefault,
671671

672+
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
673+
RustcPassIndirectlyInNonRusticAbis(Span),
674+
672675
/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
673676
RustcSimdMonomorphizeLaneLimit(Limit),
674677

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ impl AttributeKind {
8989
RustcLayoutScalarValidRangeEnd(..) => Yes,
9090
RustcLayoutScalarValidRangeStart(..) => Yes,
9191
RustcObjectLifetimeDefault => No,
92+
RustcPassIndirectlyInNonRusticAbis(..) => No,
9293
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
9394
Sanitize { .. } => No,
9495
ShouldPanic { .. } => No,

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{cmp, fmt};
33

44
use rustc_abi::{
55
AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
6-
PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
6+
PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
77
TyAbiInterface, VariantIdx, Variants,
88
};
99
use rustc_error_messages::DiagMessage;
@@ -1169,6 +1169,11 @@ where
11691169
fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
11701170
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
11711171
}
1172+
1173+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
1174+
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
1175+
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
1176+
}
11721177
}
11731178

11741179
/// Calculates whether a function's ABI can unwind or not.

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,14 @@ impl<'tcx> TyCtxt<'tcx> {
15241524
flags.insert(ReprFlags::IS_LINEAR);
15251525
}
15261526

1527+
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
1528+
if find_attr!(
1529+
self.get_all_attrs(did),
1530+
AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
1531+
) {
1532+
flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS);
1533+
}
1534+
15271535
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
15281536
}
15291537

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
283283
| AttributeKind::ObjcSelector { .. }
284284
| AttributeKind::RustcCoherenceIsCore(..)
285285
| AttributeKind::DebuggerVisualizer(..)
286+
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
286287
) => { /* do nothing */ }
287288
Attribute::Unparsed(attr_item) => {
288289
style = Some(attr_item.style);

0 commit comments

Comments
 (0)