Skip to content

Commit 2a196cd

Browse files
committed
Add #[rustc_pass_indirectly_in_non_rustic_abis]
1 parent 48aee7e commit 2a196cd

29 files changed

+621
-21
lines changed

compiler/rustc_abi/src/layout/ty.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
182182
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
183183
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
184184
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
185+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
186+
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
185187
}
186188

187189
impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -279,6 +281,30 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
279281
Ty::is_transparent(self)
280282
}
281283

284+
/// If this method returns `true`, then this type should always have a `PassMode` of
285+
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
286+
/// non-Rustic ABI (this is true for structs annotated with the
287+
/// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute). Currently this is only used by
288+
/// `VaList`, so this only needs to be handled on architectures where `VaList` requires it:
289+
/// specifically there is a `support_architectures` array in the
290+
/// `check_pass_indirectly_in_non_rustic_abis` function in
291+
/// `compiler/rustc_passes/src/check_attr.rs` which lists all the architectures this needs to be
292+
/// handled on. See the comment near the top of `library/core/src/ffi/va_list.rs` for more
293+
/// details.
294+
///
295+
/// This function handles transparent types automatically.
296+
pub fn pass_indirectly_in_non_rustic_abis<C>(mut self, cx: &C) -> bool
297+
where
298+
Ty: TyAbiInterface<'a, C> + Copy,
299+
{
300+
while self.is_transparent()
301+
&& let Some((_, field)) = self.non_1zst_field(cx)
302+
{
303+
self = field;
304+
}
305+
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
306+
}
307+
282308
/// Finds the one field that is not a 1-ZST.
283309
/// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
284310
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
@@ -86,14 +86,17 @@ bitflags! {
8686
const IS_C = 1 << 0;
8787
const IS_SIMD = 1 << 1;
8888
const IS_TRANSPARENT = 1 << 2;
89-
// Internal only for now. If true, don't reorder fields.
90-
// On its own it does not prevent ABI optimizations.
89+
/// Internal only for now. If true, don't reorder fields.
90+
/// On its own it does not prevent ABI optimizations.
9191
const IS_LINEAR = 1 << 3;
92-
// If true, the type's crate has opted into layout randomization.
93-
// Other flags can still inhibit reordering and thus randomization.
94-
// The seed stored in `ReprOptions.field_shuffle_seed`.
92+
/// If true, the type's crate has opted into layout randomization.
93+
/// Other flags can still inhibit reordering and thus randomization.
94+
/// The seed stored in `ReprOptions.field_shuffle_seed`.
9595
const RANDOMIZE_LAYOUT = 1 << 4;
96-
// Any of these flags being set prevent field reordering optimisation.
96+
/// If true, the type is always passed indirectly by non-Rustic ABIs.
97+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
98+
const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
99+
/// Any of these flags being set prevent field reordering optimisation.
97100
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
98101
| ReprFlags::IS_SIMD.bits()
99102
| ReprFlags::IS_LINEAR.bits();

compiler/rustc_attr_data_structures/src/attributes.rs

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

302+
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
303+
RustcPassIndirectlyInNonRusticAbis(Span),
304+
302305
/// Represents `#[rustc_skip_during_method_dispatch]`.
303306
SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
304307

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl AttributeKind {
2727
LinkSection { .. } => No,
2828
MacroTransparency(..) => Yes,
2929
Repr(..) => No,
30+
RustcPassIndirectlyInNonRusticAbis(..) => No,
3031
Stability { .. } => Yes,
3132
Cold(..) => No,
3233
ConstContinue(..) => No,

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,10 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
330330
features
331331
}
332332
}
333+
334+
pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
335+
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {
336+
const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
337+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
338+
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
339+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1616

1717
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
1818
use crate::attributes::codegen_attrs::{
19-
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser,
20-
TrackCallerParser, UsedParser,
19+
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
20+
RustcPassIndirectlyInNonRusticAbisParser, TargetFeatureParser, TrackCallerParser, UsedParser,
2121
};
2222
use crate::attributes::confusables::ConfusablesParser;
2323
use crate::attributes::deprecation::DeprecationParser;
@@ -143,6 +143,7 @@ attribute_parsers!(
143143
Single<WithoutArgs<MayDangleParser>>,
144144
Single<WithoutArgs<NoMangleParser>>,
145145
Single<WithoutArgs<PubTransparentParser>>,
146+
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
146147
Single<WithoutArgs<TrackCallerParser>>,
147148
// tidy-alphabetical-end
148149
];

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
497497
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
498498
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
499499
ungated!(unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
500+
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
501+
rustc_attr!(
502+
rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing,
503+
EncodeCrossCrate::No,
504+
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis."
505+
),
500506

501507
// Limits:
502508
ungated!(

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;
@@ -1138,6 +1138,11 @@ where
11381138
fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
11391139
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
11401140
}
1141+
1142+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
1143+
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
1144+
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
1145+
}
11411146
}
11421147

11431148
/// 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
@@ -1585,6 +1585,14 @@ impl<'tcx> TyCtxt<'tcx> {
15851585
flags.insert(ReprFlags::IS_LINEAR);
15861586
}
15871587

1588+
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
1589+
if attr::find_attr!(
1590+
self.get_all_attrs(did),
1591+
AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
1592+
) {
1593+
flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS);
1594+
}
1595+
15881596
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
15891597
}
15901598

compiler/rustc_passes/messages.ftl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,14 @@ passes_pass_by_value =
579579
`pass_by_value` attribute should be applied to a struct, enum or type alias
580580
.label = is not a struct, enum or type alias
581581
582+
passes_pass_indirectly_not_a_struct =
583+
`#[rustc_pass_indirectly_in_non_rustic_abis]` can only be applied to `struct`s
584+
.label = is not a `struct`
585+
586+
passes_pass_indirectly_unsupported_arch =
587+
support for `#[rustc_pass_indirectly_in_non_rustic_abis]` on `{$arch}` has not yet been implemented
588+
.help = see the comment near the top of `library/core/src/ffi/va_list.rs` for details
589+
582590
passes_proc_macro_bad_sig = {$kind} has incorrect signature
583591
584592
passes_remove_fields =

0 commit comments

Comments
 (0)