Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 03ef470

Browse files
committed
Initial UnsafePinned impl [Part 2: Lowering]
1 parent 40dacd5 commit 03ef470

18 files changed

+932
-9
lines changed

‎compiler/rustc_ast_ir/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContex
1717
pub mod visit;
1818

1919
/// The movability of a coroutine / closure literal:
20-
/// whether a coroutine contains self-references, causing it to be `!Unpin`.
20+
/// whether a coroutine contains self-references, causing it to be `![Unsafe]Unpin`.
2121
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
2222
#[cfg_attr(
2323
feature = "nightly",
2424
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
2525
)]
2626
pub enum Movability {
27-
/// May contain self-references, `!Unpin`.
27+
/// May contain self-references, `!Unpin + !UnsafeUnpin`.
2828
Static,
29-
/// Must not contain self-references, `Unpin`.
29+
/// Must not contain self-references, `Unpin + UnsafeUnpin`.
3030
Movable,
3131
}
3232

‎compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3385,7 +3385,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
33853385
Some(3)
33863386
} else if string.starts_with("static") {
33873387
// `static` is 6 chars long
3388-
// This is used for `!Unpin` coroutines
3388+
// This is used for immovable (self-referential) coroutines
33893389
Some(6)
33903390
} else {
33913391
None

‎compiler/rustc_middle/src/mir/query.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub struct CoroutineSavedTy<'tcx> {
2929
pub source_info: SourceInfo,
3030
/// Whether the local should be ignored for trait bound computations.
3131
pub ignore_for_traits: bool,
32+
/// If this local is borrowed across a suspension point and thus is
33+
/// "wrapped" in `UnsafePinned`. Always false for movable coroutines.
34+
pub pinned: bool,
3235
}
3336

3437
/// The layout of coroutine state.

‎compiler/rustc_middle/src/ty/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
335335
self.coroutine_hidden_types(def_id)
336336
}
337337

338+
fn coroutine_has_pinned_fields(self, def_id: DefId) -> Option<bool> {
339+
self.coroutine_has_pinned_fields(def_id)
340+
}
341+
338342
fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
339343
self.fn_sig(def_id)
340344
}
@@ -734,6 +738,7 @@ bidirectional_lang_item_map! {
734738
TransmuteTrait,
735739
Tuple,
736740
Unpin,
741+
UnsafeUnpin,
737742
Unsize,
738743
// tidy-alphabetical-end
739744
}

‎compiler/rustc_middle/src/ty/util.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,13 @@ impl<'tcx> TyCtxt<'tcx> {
790790
))
791791
}
792792

793+
/// True if the given coroutine has any pinned fields.
794+
/// `None` if the coroutine is tainted by errors.
795+
pub fn coroutine_has_pinned_fields(self, def_id: DefId) -> Option<bool> {
796+
self.mir_coroutine_witnesses(def_id)
797+
.map(|layout| layout.field_tys.iter().any(|ty| ty.pinned))
798+
}
799+
793800
/// Expands the given impl trait type, stopping if the type is recursive.
794801
#[instrument(skip(self), level = "debug", ret)]
795802
pub fn try_expand_impl_trait_type(

‎compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,15 @@ struct LivenessInfo {
639639
/// Parallel vec to the above with SourceInfo for each yield terminator.
640640
source_info_at_suspension_points: Vec<SourceInfo>,
641641

642+
/// Coroutine saved locals that are borrowed across a suspension point.
643+
/// This corresponds to locals that are "wrapped" with `UnsafePinned`.
644+
///
645+
/// Note that movable coroutines do not allow borrowing locals across
646+
/// suspension points and thus will always have this set empty.
647+
///
648+
/// For more information, see [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html).
649+
saved_locals_borrowed_across_suspension_points: DenseBitSet<CoroutineSavedLocal>,
650+
642651
/// For every saved local, the set of other saved locals that are
643652
/// storage-live at the same time as this local. We cannot overlap locals in
644653
/// the layout which have conflicting storage.
@@ -690,6 +699,8 @@ fn locals_live_across_suspend_points<'tcx>(
690699
let mut live_locals_at_suspension_points = Vec::new();
691700
let mut source_info_at_suspension_points = Vec::new();
692701
let mut live_locals_at_any_suspension_point = DenseBitSet::new_empty(body.local_decls.len());
702+
let mut locals_borrowed_across_any_suspension_point =
703+
DenseBitSet::new_empty(body.local_decls.len());
693704

694705
for (block, data) in body.basic_blocks.iter_enumerated() {
695706
if let TerminatorKind::Yield { .. } = data.terminator().kind {
@@ -711,6 +722,7 @@ fn locals_live_across_suspend_points<'tcx>(
711722
// of the local, which happens using the `intersect` operation below.
712723
borrowed_locals_cursor.seek_before_primary_effect(loc);
713724
live_locals.union(borrowed_locals_cursor.get());
725+
locals_borrowed_across_any_suspension_point.union(borrowed_locals_cursor.get());
714726
}
715727

716728
// Store the storage liveness for later use so we can restore the state
@@ -726,6 +738,7 @@ fn locals_live_across_suspend_points<'tcx>(
726738

727739
// The coroutine argument is ignored.
728740
live_locals.remove(SELF_ARG);
741+
locals_borrowed_across_any_suspension_point.remove(SELF_ARG);
729742

730743
debug!("loc = {:?}, live_locals = {:?}", loc, live_locals);
731744

@@ -741,13 +754,18 @@ fn locals_live_across_suspend_points<'tcx>(
741754
debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point);
742755
let saved_locals = CoroutineSavedLocals(live_locals_at_any_suspension_point);
743756

757+
debug!("borrowed_locals = {:?}", locals_borrowed_across_any_suspension_point);
758+
744759
// Renumber our liveness_map bitsets to include only the locals we are
745760
// saving.
746761
let live_locals_at_suspension_points = live_locals_at_suspension_points
747762
.iter()
748763
.map(|live_here| saved_locals.renumber_bitset(live_here))
749764
.collect();
750765

766+
let saved_locals_borrowed_across_suspension_points =
767+
saved_locals.renumber_bitset(&locals_borrowed_across_any_suspension_point);
768+
751769
let storage_conflicts = compute_storage_conflicts(
752770
body,
753771
&saved_locals,
@@ -759,6 +777,7 @@ fn locals_live_across_suspend_points<'tcx>(
759777
saved_locals,
760778
live_locals_at_suspension_points,
761779
source_info_at_suspension_points,
780+
saved_locals_borrowed_across_suspension_points,
762781
storage_conflicts,
763782
storage_liveness: storage_liveness_map,
764783
}
@@ -931,6 +950,7 @@ fn compute_layout<'tcx>(
931950
saved_locals,
932951
live_locals_at_suspension_points,
933952
source_info_at_suspension_points,
953+
saved_locals_borrowed_across_suspension_points,
934954
storage_conflicts,
935955
storage_liveness,
936956
} = liveness;
@@ -960,8 +980,14 @@ fn compute_layout<'tcx>(
960980
ClearCrossCrate::Set(box LocalInfo::FakeBorrow) => true,
961981
_ => false,
962982
};
963-
let decl =
964-
CoroutineSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits };
983+
let pinned = saved_locals_borrowed_across_suspension_points.contains(saved_local);
984+
985+
let decl = CoroutineSavedTy {
986+
ty: decl.ty,
987+
source_info: decl.source_info,
988+
ignore_for_traits,
989+
pinned,
990+
};
965991
debug!(?decl);
966992

967993
tys.push(decl);

‎compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,13 +1148,13 @@ where
11481148

11491149
ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
11501150

1151-
// Coroutines have one special built-in candidate, `Unpin`, which
1152-
// takes precedence over the structural auto trait candidate being
1153-
// assembled.
1151+
// Coroutines have two special built-in candidates, `Unpin` and `UnsafeUnpin`.
1152+
// These take precedence over the structural auto trait candidate being assembled.
11541153
ty::Coroutine(def_id, _)
11551154
if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
11561155
{
11571156
match self.cx().coroutine_movability(def_id) {
1157+
// immovable coroutines are *never* Unpin
11581158
Movability::Static => Some(Err(NoSolution)),
11591159
Movability::Movable => Some(
11601160
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
@@ -1163,6 +1163,21 @@ where
11631163
),
11641164
}
11651165
}
1166+
ty::Coroutine(def_id, _)
1167+
if self
1168+
.cx()
1169+
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::UnsafeUnpin) =>
1170+
{
1171+
match self.cx().coroutine_has_pinned_fields(def_id) {
1172+
Some(true) => Some(Err(NoSolution)),
1173+
Some(false) => Some(
1174+
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1175+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1176+
}),
1177+
),
1178+
None => None, // coro tainted by errors
1179+
}
1180+
}
11661181

11671182
// If we still have an alias here, it must be rigid. For opaques, it's always
11681183
// okay to consider auto traits because that'll reveal its hidden type. For

‎compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
751751
// The auto impl might apply; we don't know.
752752
candidates.ambiguous = true;
753753
}
754+
754755
ty::Coroutine(coroutine_def_id, _)
755756
if self.tcx().is_lang_item(def_id, LangItem::Unpin) =>
756757
{
@@ -766,6 +767,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
766767
}
767768
}
768769
}
770+
ty::Coroutine(coroutine_def_id, _)
771+
if self.tcx().is_lang_item(def_id, LangItem::UnsafeUnpin) =>
772+
{
773+
match self.tcx().coroutine_has_pinned_fields(coroutine_def_id) {
774+
Some(true) => {}
775+
Some(false) => {
776+
candidates.vec.push(BuiltinCandidate { has_nested: false });
777+
}
778+
// coro tainted by errors
779+
None => candidates.vec.push(AutoImplCandidate),
780+
}
781+
}
769782

770783
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
771784
bug!(

‎compiler/rustc_type_ir/src/interner.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ pub trait Interner:
205205
def_id: Self::DefId,
206206
) -> ty::EarlyBinder<Self, ty::Binder<Self, Self::Tys>>;
207207

208+
fn coroutine_has_pinned_fields(self, def_id: Self::DefId) -> Option<bool>;
209+
208210
fn fn_sig(
209211
self,
210212
def_id: Self::DefId,

‎compiler/rustc_type_ir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub enum TraitSolverLangItem {
3838
TransmuteTrait,
3939
Tuple,
4040
Unpin,
41+
UnsafeUnpin,
4142
Unsize,
4243
// tidy-alphabetical-end
4344
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /