Skip to content

Commit

Permalink
Switch from GcSmartPointer trait to Gc lang_item
Browse files Browse the repository at this point in the history
The GcSmartPointer trait was a hangover which let the compiler identify
`Gc<T>` structs when they were defined as part of a non-rustc library.
Now that the `Gc` implementation is part of the standard library, this
is unnecessary and adds complexity.

This requires the prevent_early_finalization mir-opt tests to be
temporarily ignored due to an issue with non-deterministic builds when
bringing in the alloc crate across different machines. [1]

[1]: softdevteam#45
  • Loading branch information
jacob-hughes committed May 16, 2023
1 parent 0513c67 commit 391856a
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 267 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ language_item_table! {

Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None;
NoTrace, sym::notrace, no_trace_trait, Target::Trait;
Conservative, sym::conservative, conservative_trait, Target::Trait;
GcSmartPointer, sym::gcsp, gc_smart_pointer_trait, Target::Trait;
NoTrace, sym::notrace, no_trace_trait, Target::Trait, GenericRequirement::None;
Conservative, sym::conservative, conservative_trait, Target::Trait, GenericRequirement::None;
Gc, sym::gc, gc_type, Target::Struct, GenericRequirement::Exact(1);

CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,14 +1078,6 @@ impl<'tcx> Ty<'tcx> {
!self.is_conservative(tcx_at, param_env)
}

pub fn is_gc_smart_pointer(
&'tcx self,
tcx_at: TyCtxtAt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
tcx_at.is_gc_smart_pointer_raw(param_env.and(self))
}

/// Fast path helper for testing if a type is `Freeze`.
///
/// Returning true means the type is known to be `Freeze`. Returning
Expand Down
30 changes: 24 additions & 6 deletions compiler/rustc_mir_transform/src/prevent_early_finalization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{transform::MirPass, util::patch::MirPatch};
use rustc_ast::{LlvmAsmDialect, StrStyle};
use rustc_hir as hir;
use rustc_middle::mir::*;
use rustc_middle::ty::{ParamEnv, TyCtxt};
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::DUMMY_SP;

Expand All @@ -11,7 +11,7 @@ pub struct PreventEarlyFinalization;

impl<'tcx> MirPass<'tcx> for PreventEarlyFinalization {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if tcx.lang_items().gc_smart_pointer_trait().is_none() {
if tcx.lang_items().gc_type().is_none() {
return;
}
let barrier = build_asm_barrier();
Expand Down Expand Up @@ -64,10 +64,28 @@ fn is_return<'tcx>(terminator: &Terminator<'tcx>) -> bool {
}
}

fn needs_barrier(local: &LocalDecl<'tcx>, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> bool {
local.is_user_variable()
&& !local.ty.is_no_finalize_modulo_regions(tcx.at(DUMMY_SP), param_env)
&& local.ty.is_gc_smart_pointer(tcx.at(DUMMY_SP), param_env)
fn needs_barrier<'tcx>(
local: &LocalDecl<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> bool {
if !local.is_user_variable() {
return false;
}

if let ty::Adt(def, ..) = local.ty.kind() {
if def.did != tcx.lang_items().gc_type().unwrap() {
return false;
}

if local.ty.is_no_finalize_modulo_regions(tcx.at(DUMMY_SP), param_env) {
return false;
}

return true;
}

return false;
}

fn build_asm_barrier() -> Box<LlvmInlineAsm<'tcx>> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,8 +767,8 @@ symbols! {
fundamental,
future,
future_trait,
gc,
gc_layout,
gcsp,
gdb_script_file,
ge,
gen_future,
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_ty_utils/src/common_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ fn is_no_finalize_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'
is_item_raw(tcx, query, LangItem::NoFinalize)
}

fn is_gc_smart_pointer_raw<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
is_item_raw(tcx, query, LangItem::GcSmartPointer)
}

fn is_item_raw<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
Expand All @@ -60,7 +53,6 @@ pub(crate) fn provide(providers: &mut Providers) {
is_unpin_raw,
is_conservative_raw,
is_no_trace_raw,
is_gc_smart_pointer_raw,
is_no_finalize_raw,
..*providers
};
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static ALLOCATOR: GcAllocator = GcAllocator;
/// will always implement `Send` because it requires `T` to implement `Send`.
/// This is because if `T` has a finalizer, it will be run on a seperate thread.
#[unstable(feature = "gc", issue = "none")]
#[cfg_attr(all(not(bootstrap), not(test)), lang = "gc")]
#[derive(PartialEq, Eq)]
pub struct Gc<T: ?Sized + Send> {
ptr: NonNull<GcBox<T>>,
Expand Down
8 changes: 0 additions & 8 deletions library/core/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,6 @@ impl<T> NonFinalizable<T> {
}
}

#[unstable(feature = "gc", issue = "none")]
#[cfg_attr(not(bootstrap), lang = "gcsp")]
/// An internal trait which is only implemented by the `Gc` type. This exists so
/// that the `Gc` type -- which is defined externally -- can be used as part of
/// static analysis in the compiler. Evenually, this won't be necessary because
/// `Gc` will be defined in the standard library.
pub unsafe trait GcSmartPointer {}

#[unstable(feature = "gc", issue = "none")]
impl Trace {
#[inline]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,75 @@
- // MIR for `preserve_args` before PreventEarlyFinalization
+ // MIR for `preserve_args` after PreventEarlyFinalization

| User Type Annotations
| 0: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: TypeOf(DefId(5:4632 ~ alloc[ed55]::gc::{impl#5}::new), UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:4630 ~ alloc[ed55]::gc::{impl#5}), self_ty: std::gc::Gc<^1> }) }) } at $DIR/prevent_early_finalization.rs:25:35: 25:42
| 1: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: TypeOf(DefId(5:4632 ~ alloc[ed55]::gc::{impl#5}::new), UserSubsts { substs: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:4630 ~ alloc[ed55]::gc::{impl#5}), self_ty: std::gc::Gc<^1> }) }) } at $DIR/prevent_early_finalization.rs:25:64: 25:71
|
fn preserve_args() -> () {
let mut _0: (); // return place in scope 0 at $DIR/prevent_early_finalization.rs:28:20: 28:20
let _1: Finalizable; // in scope 0 at $DIR/prevent_early_finalization.rs:29:9: 29:12
let mut _2: Finalizable; // in scope 0 at $DIR/prevent_early_finalization.rs:29:35: 29:51
let mut _3: Finalizable; // in scope 0 at $DIR/prevent_early_finalization.rs:29:53: 29:69
let mut _0: (); // return place in scope 0 at $DIR/prevent_early_finalization.rs:24:20: 24:20
let _1: std::gc::Gc<NeedsFinalize>; // in scope 0 at $DIR/prevent_early_finalization.rs:25:9: 25:12
let mut _2: std::gc::Gc<NeedsFinalize>; // in scope 0 at $DIR/prevent_early_finalization.rs:25:35: 25:62
let mut _3: NeedsFinalize; // in scope 0 at $DIR/prevent_early_finalization.rs:25:43: 25:61
let mut _4: std::gc::Gc<NeedsFinalize>; // in scope 0 at $DIR/prevent_early_finalization.rs:25:64: 25:91
let mut _5: NeedsFinalize; // in scope 0 at $DIR/prevent_early_finalization.rs:25:72: 25:90
scope 1 {
debug ret => _1; // in scope 1 at $DIR/prevent_early_finalization.rs:29:9: 29:12
debug ret => _1; // in scope 1 at $DIR/prevent_early_finalization.rs:25:9: 25:12
}

bb0: {
StorageLive(_1); // scope 0 at $DIR/prevent_early_finalization.rs:29:9: 29:12
StorageLive(_2); // scope 0 at $DIR/prevent_early_finalization.rs:29:35: 29:51
_2 = Finalizable(const 123_usize); // scope 0 at $DIR/prevent_early_finalization.rs:29:35: 29:51
StorageLive(_3); // scope 0 at $DIR/prevent_early_finalization.rs:29:53: 29:69
_3 = Finalizable(const 456_usize); // scope 0 at $DIR/prevent_early_finalization.rs:29:53: 29:69
_1 = preserve_args_inner(move _2, move _3) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/prevent_early_finalization.rs:29:15: 29:70
StorageLive(_1); // scope 0 at $DIR/prevent_early_finalization.rs:25:9: 25:12
StorageLive(_2); // scope 0 at $DIR/prevent_early_finalization.rs:25:35: 25:62
StorageLive(_3); // scope 0 at $DIR/prevent_early_finalization.rs:25:43: 25:61
_3 = NeedsFinalize(const 123_usize); // scope 0 at $DIR/prevent_early_finalization.rs:25:43: 25:61
_2 = Gc::<NeedsFinalize>::new(move _3) -> [return: bb1, unwind: bb5]; // scope 0 at $DIR/prevent_early_finalization.rs:25:35: 25:62
// mir::Constant
// + span: $DIR/prevent_early_finalization.rs:29:15: 29:34
// + literal: Const { ty: fn(Finalizable, Finalizable) -> Finalizable {preserve_args_inner}, val: Value(Scalar(<ZST>)) }
// + span: $DIR/prevent_early_finalization.rs:25:35: 25:42
// + user_ty: UserType(0)
// + literal: Const { ty: fn(NeedsFinalize) -> std::gc::Gc<NeedsFinalize> {std::gc::Gc::<NeedsFinalize>::new}, val: Value(Scalar(<ZST>)) }
}

bb1: {
StorageDead(_3); // scope 0 at $DIR/prevent_early_finalization.rs:29:69: 29:70
StorageDead(_2); // scope 0 at $DIR/prevent_early_finalization.rs:29:69: 29:70
FakeRead(ForLet, _1); // scope 0 at $DIR/prevent_early_finalization.rs:29:9: 29:12
_0 = const (); // scope 0 at $DIR/prevent_early_finalization.rs:28:20: 30:2
- StorageDead(_1); // scope 0 at $DIR/prevent_early_finalization.rs:30:1: 30:2
+ nop; // scope 0 at $DIR/prevent_early_finalization.rs:30:1: 30:2
+ llvm_asm!(LlvmInlineAsmInner { asm: "", asm_str_style: Cooked, outputs: [], inputs: ["r"], clobbers: ["memory"], volatile: true, alignstack: false, dialect: Att } : [] : [($DIR/prevent_early_finalization.rs:1:1: 1:1 (#0), _1)]); // scope 0 at $DIR/prevent_early_finalization.rs:30:2: 30:2
+ StorageDead(_1); // scope 0 at $DIR/prevent_early_finalization.rs:30:2: 30:2
return; // scope 0 at $DIR/prevent_early_finalization.rs:30:2: 30:2
}

bb2 (cleanup): {
resume; // scope 0 at $DIR/prevent_early_finalization.rs:28:1: 30:2
StorageDead(_3); // scope 0 at $DIR/prevent_early_finalization.rs:25:61: 25:62
StorageLive(_4); // scope 0 at $DIR/prevent_early_finalization.rs:25:64: 25:91
StorageLive(_5); // scope 0 at $DIR/prevent_early_finalization.rs:25:72: 25:90
_5 = NeedsFinalize(const 456_usize); // scope 0 at $DIR/prevent_early_finalization.rs:25:72: 25:90
_4 = Gc::<NeedsFinalize>::new(move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/prevent_early_finalization.rs:25:64: 25:91
// mir::Constant
// + span: $DIR/prevent_early_finalization.rs:25:64: 25:71
// + user_ty: UserType(1)
// + literal: Const { ty: fn(NeedsFinalize) -> std::gc::Gc<NeedsFinalize> {std::gc::Gc::<NeedsFinalize>::new}, val: Value(Scalar(<ZST>)) }
}

bb2: {
StorageDead(_5); // scope 0 at $DIR/prevent_early_finalization.rs:25:90: 25:91
_1 = preserve_args_inner(move _2, move _4) -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/prevent_early_finalization.rs:25:15: 25:92
// mir::Constant
// + span: $DIR/prevent_early_finalization.rs:25:15: 25:34
// + literal: Const { ty: fn(std::gc::Gc<NeedsFinalize>, std::gc::Gc<NeedsFinalize>) -> std::gc::Gc<NeedsFinalize> {preserve_args_inner}, val: Value(Scalar(<ZST>)) }
}

bb3: {
StorageDead(_4); // scope 0 at $DIR/prevent_early_finalization.rs:25:91: 25:92
StorageDead(_2); // scope 0 at $DIR/prevent_early_finalization.rs:25:91: 25:92
FakeRead(ForLet(None), _1); // scope 0 at $DIR/prevent_early_finalization.rs:25:9: 25:12
_0 = const (); // scope 0 at $DIR/prevent_early_finalization.rs:24:20: 26:2
- StorageDead(_1); // scope 0 at $DIR/prevent_early_finalization.rs:26:1: 26:2
+ nop; // scope 0 at $DIR/prevent_early_finalization.rs:26:1: 26:2
+ llvm_asm!(LlvmInlineAsmInner { asm: "", asm_str_style: Cooked, outputs: [], inputs: ["r"], clobbers: ["memory"], volatile: true, alignstack: false, dialect: Att } : [] : [(no-location (#0), _1)]); // scope 0 at $DIR/prevent_early_finalization.rs:26:2: 26:2
+ StorageDead(_1); // scope 0 at $DIR/prevent_early_finalization.rs:26:2: 26:2
return; // scope 0 at $DIR/prevent_early_finalization.rs:26:2: 26:2
}

bb4 (cleanup): {
drop(_5) -> bb6; // scope 0 at $DIR/prevent_early_finalization.rs:25:90: 25:91
}

bb5 (cleanup): {
drop(_3) -> bb6; // scope 0 at $DIR/prevent_early_finalization.rs:25:61: 25:62
}

bb6 (cleanup): {
resume; // scope 0 at $DIR/prevent_early_finalization.rs:24:1: 26:2
}
}

Loading

0 comments on commit 391856a

Please sign in to comment.