Skip to content

Commit fa9ea6d

Browse files
authored
Rollup merge of #144529 - beetrees:pass-indirectly-attr, r=bjorn3
Add `#[rustc_pass_indirectly_in_non_rustic_abis]` This PR adds an internal `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute that can be applied to structs. Structs marked with this attribute will always be passed using `PassMode::Indirect { on_stack: false, .. }` when being passed by value to functions with non-Rustic calling conventions. This is needed by #141980; see that PR for further details. cc `@joshtriplett`
2 parents 90b6588 + 7be6d6f commit fa9ea6d

43 files changed

Lines changed: 594 additions & 57 deletions

File tree

Some content is hidden

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

‎compiler/rustc_abi/src/layout/ty.rs‎

Lines changed: 26 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
fnis_tuple(this:TyAndLayout<'a,Self>) -> bool;
173173
fnis_unit(this:TyAndLayout<'a,Self>) -> bool;
174174
fnis_transparent(this:TyAndLayout<'a,Self>) -> bool;
175+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
176+
fnis_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,30 @@ 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+
pubfnpass_indirectly_in_non_rustic_abis<C>(mutself,cx:&C) -> bool
286+
where
287+
Ty:TyAbiInterface<'a,C> + Copy,
288+
{
289+
whileself.is_transparent()
290+
&& letSome((_, field)) = self.non_1zst_field(cx)
291+
{
292+
self = field;
293+
}
294+
295+
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
296+
}
297+
272298
/// Finds the one field that is not a 1-ZST.
273299
/// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
274300
pubfnnon_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
constIS_C = 1 << 0;
8989
constIS_SIMD = 1 << 1;
9090
constIS_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
constIS_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
constRANDOMIZE_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+
constPASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5;
101+
/// Any of these flags being set prevent field reordering optimisation.
99102
constFIELD_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
@@ -676,3 +676,12 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
676676
Some(AttributeKind::Sanitize{ on_set, off_set,span: cx.attr_span})
677677
}
678678
}
679+
680+
pub(crate)structRustcPassIndirectlyInNonRusticAbisParser;
681+
682+
impl<S:Stage>NoArgsAttributeParser<S>forRustcPassIndirectlyInNonRusticAbisParser{
683+
constPATH:&[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
684+
constON_DUPLICATE:OnDuplicate<S> = OnDuplicate::Error;
685+
constALLOWED_TARGETS:AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
686+
constCREATE:fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
687+
}

‎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
usecrate::attributes::body::CoroutineParser;
2121
usecrate::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
usecrate::attributes::confusables::ConfusablesParser;
2728
usecrate::attributes::crate_level::{
@@ -243,6 +244,7 @@ attribute_parsers!(
243244
Single<WithoutArgs<PubTransparentParser>>,
244245
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
245246
Single<WithoutArgs<RustcMainParser>>,
247+
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
246248
Single<WithoutArgs<SpecializationTraitParser>>,
247249
Single<WithoutArgs<StdInternalSymbolParser>>,
248250
Single<WithoutArgs<TrackCallerParser>>,

‎compiler/rustc_feature/src/builtin_attrs.rs‎

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

661667
// Limits:
662668
ungated!(

‎compiler/rustc_hir/src/attrs/data_structures.rs‎

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

682+
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
683+
RustcPassIndirectlyInNonRusticAbis(Span),
684+
682685
/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
683686
RustcSimdMonomorphizeLaneLimit(Limit),
684687

‎compiler/rustc_hir/src/attrs/encode_cross_crate.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ impl AttributeKind {
9191
RustcLayoutScalarValidRangeStart(..) => Yes,
9292
RustcMain => No,
9393
RustcObjectLifetimeDefault => No,
94+
RustcPassIndirectlyInNonRusticAbis(..) => No,
9495
RustcSimdMonomorphizeLaneLimit(..) => Yes,// Affects layout computation, which needs to work cross-crate
9596
Sanitize{ .. } => No,
9697
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;
@@ -1173,6 +1173,11 @@ where
11731173
fnis_transparent(this:TyAndLayout<'tcx>) -> bool{
11741174
matches!(this.ty.kind(), ty::Adt(def, _)if def.repr().transparent())
11751175
}
1176+
1177+
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
1178+
fnis_pass_indirectly_in_non_rustic_abis_flag_set(this:TyAndLayout<'tcx>) -> bool{
1179+
matches!(this.ty.kind(), ty::Adt(def, _)if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
1180+
}
11761181
}
11771182

11781183
/// 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
@@ -1573,6 +1573,14 @@ impl<'tcx> TyCtxt<'tcx> {
15731573
flags.insert(ReprFlags::IS_LINEAR);
15741574
}
15751575

1576+
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
1577+
iffind_attr!(
1578+
self.get_all_attrs(did),
1579+
AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
1580+
){
1581+
flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS);
1582+
}
1583+
15761584
ReprOptions{int: size,align: max_align,pack: min_pack, flags, field_shuffle_seed }
15771585
}
15781586

‎compiler/rustc_passes/src/check_attr.rs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
284284
| AttributeKind::RustcCoherenceIsCore(..)
285285
| AttributeKind::DebuggerVisualizer(..)
286286
| AttributeKind::RustcMain
287+
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
287288
| AttributeKind::PinV2(..),
288289
) => {/* do nothing */}
289290
Attribute::Unparsed(attr_item) => {
@@ -1770,6 +1771,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
17701771
target: target.to_string(),
17711772
});
17721773
}
1774+
// Error on `#[repr(transparent)]` in combination with
1775+
// `#[rustc_pass_indirectly_in_non_rustic_abis]`
1776+
if is_transparent
1777+
&& letSome(&pass_indirectly_span) =
1778+
find_attr!(attrs,AttributeKind::RustcPassIndirectlyInNonRusticAbis(span) => span)
1779+
{
1780+
self.dcx().emit_err(errors::TransparentIncompatible{
1781+
hint_spans:vec![span, pass_indirectly_span],
1782+
target: target.to_string(),
1783+
});
1784+
}
17731785
if is_explicit_rust && (int_reprs > 0 || is_c || is_simd){
17741786
let hint_spans = hint_spans.clone().collect();
17751787
self.dcx().emit_err(errors::ReprConflicting{ hint_spans });

0 commit comments

Comments
 (0)