Skip to content

Commit

Permalink
Merge pull request #128 from jacob-hughes/rename_finalizer_optional
Browse files Browse the repository at this point in the history
s/FinalizerOptional/DropMethodFinalizerElidable
  • Loading branch information
ltratt authored Oct 21, 2024
2 parents 0a0c337 + e786cc7 commit 7883188
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 92 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ language_item_table! {

FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;

FinalizerOptional, sym::finalizer_optional, finalizer_optional_trait, Target::Trait, GenericRequirement::Exact(0);
DropMethodFinalizerElidable, sym::drop_method_finalizer_elidable, drop_method_finalizer_elidable_trait, Target::Trait, GenericRequirement::Exact(0);
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
FusedIterator, sym::fused_iterator, fused_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1345,7 +1345,7 @@ rustc_queries! {
desc { "computing whether `{}` is `Unpin`", env.value }
}
/// Query backing `Ty::must_check_component_tys_for_finalizer`.
query finalizer_optional_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
query drop_method_finalizer_elidable_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` contains types which might need finalizing", env.value }
}
/// Query backing `Ty::needs_drop`.
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1235,8 +1235,12 @@ impl<'tcx> Ty<'tcx> {
self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self))
}

pub fn finalizer_optional(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
tcx.finalizer_optional_raw(param_env.and(self))
pub fn drop_method_finalizer_elidable(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
tcx.drop_method_finalizer_elidable_raw(param_env.and(self))
}

/// Fast path helper for testing if a type is `Freeze`.
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 @@ -842,7 +842,7 @@ symbols! {
field,
field_init_shorthand,
file,
finalizer_optional,
drop_method_finalizer_elidable,
float,
float_to_int_unchecked,
floorf128,
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_ty_utils/src/common_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
is_item_raw(tcx, query, LangItem::Unpin)
}

fn finalizer_optional_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
is_item_raw(tcx, query, LangItem::FinalizerOptional)
fn drop_method_finalizer_elidable_raw<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
is_item_raw(tcx, query, LangItem::DropMethodFinalizerElidable)
}

fn is_item_raw<'tcx>(
Expand All @@ -43,7 +46,7 @@ pub(crate) fn provide(providers: &mut Providers) {
is_sized_raw,
is_freeze_raw,
is_unpin_raw,
finalizer_optional_raw,
drop_method_finalizer_elidable_raw,
..*providers
};
}
150 changes: 78 additions & 72 deletions compiler/rustc_ty_utils/src/needs_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,14 @@ where
// `ManuallyDrop`. If it's a struct or enum without a `Drop`
// impl then check whether the field types need `Drop`.
ty::Adt(adt_def, args) => {
let finalizer_optional = self.analysis_kind.is_finalization()
&& component.finalizer_optional(tcx, self.param_env);
let drop_method_finalizer_elidable = self.analysis_kind.is_finalization()
&& component.drop_method_finalizer_elidable(tcx, self.param_env);

if self.analysis_kind.is_finalization() {
self.analysis_kind.cache_type(component);
}

if finalizer_optional {
if drop_method_finalizer_elidable {
for arg_ty in args.types() {
// Required to prevent cycles when checking for finalizers. For
// example, to check whether a Box<T> requires a finalizer, its type
Expand All @@ -215,7 +215,11 @@ where
continue;
}

let tys = match (self.adt_components)(adt_def, args, finalizer_optional) {
let tys = match (self.adt_components)(
adt_def,
args,
drop_method_finalizer_elidable,
) {
Err(e) => return Some(Err(e)),
Ok(tys) => tys,
};
Expand Down Expand Up @@ -339,53 +343,54 @@ fn drop_tys_helper<'tcx>(
})
}

let adt_components =
move |adt_def: ty::AdtDef<'tcx>, args: GenericArgsRef<'tcx>, finalizer_optional: bool| {
if adt_def.is_manually_drop() {
debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
Ok(Vec::new())
} else if let Some(dtor_info) = adt_has_dtor(adt_def)
&& !finalizer_optional
{
match dtor_info {
DtorType::Significant => {
debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
Err(AlwaysRequiresDrop)
}
DtorType::Insignificant => {
debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);
let adt_components = move |adt_def: ty::AdtDef<'tcx>,
args: GenericArgsRef<'tcx>,
drop_method_finalizer_elidable: bool| {
if adt_def.is_manually_drop() {
debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
Ok(Vec::new())
} else if let Some(dtor_info) = adt_has_dtor(adt_def)
&& !drop_method_finalizer_elidable
{
match dtor_info {
DtorType::Significant => {
debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
Err(AlwaysRequiresDrop)
}
DtorType::Insignificant => {
debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);

// Since the destructor is insignificant, we just want to make sure all of
// the passed in type parameters are also insignificant.
// Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
Ok(args.types().collect())
}
// Since the destructor is insignificant, we just want to make sure all of
// the passed in type parameters are also insignificant.
// Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
Ok(args.types().collect())
}
} else if adt_def.is_union() {
debug!("drop_tys_helper: `{:?}` is a union", adt_def);
Ok(Vec::new())
}
} else if adt_def.is_union() {
debug!("drop_tys_helper: `{:?}` is a union", adt_def);
Ok(Vec::new())
} else {
let field_tys = adt_def.all_fields().map(|field| {
let r = tcx.type_of(field.did).instantiate(tcx, args);
debug!(
"drop_tys_helper: Instantiate into {:?} with {:?} getting {:?}",
field, args, r
);
r
});
if only_significant {
// We can't recurse through the query system here because we might induce a cycle
Ok(field_tys.collect())
} else {
let field_tys = adt_def.all_fields().map(|field| {
let r = tcx.type_of(field.did).instantiate(tcx, args);
debug!(
"drop_tys_helper: Instantiate into {:?} with {:?} getting {:?}",
field, args, r
);
r
});
if only_significant {
// We can't recurse through the query system here because we might induce a cycle
Ok(field_tys.collect())
} else {
// We can use the query system if we consider all drops significant. In that case,
// ADTs are `needs_drop` exactly if they `impl Drop` or if any of their "transitive"
// fields do. There can be no cycles here, because ADTs cannot contain themselves as
// fields.
with_query_cache(tcx, field_tys)
}
// We can use the query system if we consider all drops significant. In that case,
// ADTs are `needs_drop` exactly if they `impl Drop` or if any of their "transitive"
// fields do. There can be no cycles here, because ADTs cannot contain themselves as
// fields.
with_query_cache(tcx, field_tys)
}
.map(|v| v.into_iter())
};
}
.map(|v| v.into_iter())
};

NeedsDropTypes::new(tcx, param_env, ty, adt_components, AnalysisKind::Destruction)
}
Expand Down Expand Up @@ -454,31 +459,32 @@ fn needs_finalizer_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<
let adt_has_dtor =
|adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant);

let adt_components =
move |adt_def: ty::AdtDef<'tcx>, args: GenericArgsRef<'tcx>, finalizer_optional: bool| {
if adt_def.is_manually_drop() {
debug!("finalize_tys_helper: `{:?}` is manually drop", adt_def);
Ok(Vec::new())
} else if adt_has_dtor(adt_def).is_some() && !finalizer_optional {
debug!("finalize_tys_helper: `{:?}` implements `Drop`", adt_def);
Err(AlwaysRequiresDrop)
} else if adt_def.is_union() {
debug!("finalize_tys_helper: `{:?}` is a union", adt_def);
Ok(Vec::new())
} else {
let field_tys = adt_def.all_fields().map(|field| {
let r = tcx.type_of(field.did).instantiate(tcx, args);
debug!(
"finalize_tys_helper: Subst into {:?} with {:?} getting {:?}",
field, args, r
);
r
});

Ok(field_tys.collect())
}
.map(|v| v.into_iter())
};
let adt_components = move |adt_def: ty::AdtDef<'tcx>,
args: GenericArgsRef<'tcx>,
drop_method_finalizer_elidable: bool| {
if adt_def.is_manually_drop() {
debug!("finalize_tys_helper: `{:?}` is manually drop", adt_def);
Ok(Vec::new())
} else if adt_has_dtor(adt_def).is_some() && !drop_method_finalizer_elidable {
debug!("finalize_tys_helper: `{:?}` implements `Drop`", adt_def);
Err(AlwaysRequiresDrop)
} else if adt_def.is_union() {
debug!("finalize_tys_helper: `{:?}` is a union", adt_def);
Ok(Vec::new())
} else {
let field_tys = adt_def.all_fields().map(|field| {
let r = tcx.type_of(field.did).instantiate(tcx, args);
debug!(
"finalize_tys_helper: Subst into {:?} with {:?} getting {:?}",
field, args, r
);
r
});

Ok(field_tys.collect())
}
.map(|v| v.into_iter())
};

let res = NeedsDropTypes::new(
tcx,
Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ use core::cmp::Ordering;
use core::error::Error;
use core::fmt;
use core::future::Future;
use core::gc::FinalizerOptional;
use core::gc::DropMethodFinalizerElidable;
use core::hash::{Hash, Hasher};
use core::iter::FusedIterator;
use core::marker::Tuple;
Expand Down Expand Up @@ -2508,4 +2508,4 @@ impl<T: core::error::Error> core::error::Error for Box<T> {
}

#[unstable(feature = "gc", issue = "none")]
unsafe impl<T: ?Sized, A: Allocator> FinalizerOptional for Box<T, A> {}
unsafe impl<T: ?Sized, A: Allocator> DropMethodFinalizerElidable for Box<T, A> {}
4 changes: 2 additions & 2 deletions library/alloc/src/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use core::alloc::LayoutError;
use core::cmp;
use core::gc::FinalizerOptional;
use core::gc::DropMethodFinalizerElidable;
use core::hint;
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
use core::ptr::{self, NonNull, Unique};
Expand Down Expand Up @@ -587,7 +587,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
}

#[unstable(feature = "gc", issue = "none")]
unsafe impl<T, A: Allocator> FinalizerOptional for RawVec<T, A> {}
unsafe impl<T, A: Allocator> DropMethodFinalizerElidable for RawVec<T, A> {}

// Central function for reserve error handling.
#[cfg(not(no_global_oom_handling))]
Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
use core::cmp;
use core::cmp::Ordering;
use core::fmt;
use core::gc::FinalizerOptional;
use core::gc::DropMethodFinalizerElidable;
use core::hash::{Hash, Hasher};
#[cfg(not(no_global_oom_handling))]
use core::iter;
Expand Down Expand Up @@ -3277,7 +3277,7 @@ impl<T: Ord, A: Allocator> Ord for Vec<T, A> {
}

#[unstable(feature = "gc", issue = "none")]
unsafe impl<T, A: Allocator> FinalizerOptional for Vec<T, A> {}
unsafe impl<T, A: Allocator> DropMethodFinalizerElidable for Vec<T, A> {}

#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
Expand Down
8 changes: 4 additions & 4 deletions library/core/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use crate::ops::{Deref, DerefMut};
///
/// Unsafe because this should be used with care. Preventing drop from
/// running can lead to surprising behaviour.
#[rustc_diagnostic_item = "finalizer_optional"]
#[cfg_attr(not(bootstrap), lang = "finalizer_optional")]
pub unsafe trait FinalizerOptional {}
#[rustc_diagnostic_item = "drop_method_finalizer_elidable"]
#[cfg_attr(not(bootstrap), lang = "drop_method_finalizer_elidable")]
pub unsafe trait DropMethodFinalizerElidable {}

/// A wrapper which prevents `T` from being finalized when used in a `Gc`.
///
/// This is useful for when its not possible to implement `FinalizerOptional`
/// This is useful for when its not possible to implement `DropMethodFinalizerElidable`
/// because of the orphan rule. However, if `NonFinalizable<T>` is used as a
/// field type of another type which is finalizable, then `T` will also be
/// finalized.
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/runtime/gc/needs_finalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![feature(gc)]
#![allow(dead_code)]

use std::gc::{FinalizerOptional, Gc, NonFinalizable};
use std::gc::{DropMethodFinalizerElidable, Gc, NonFinalizable};
use std::mem;
use std::rc::Rc;

Expand All @@ -26,7 +26,7 @@ struct ExplicitNoFinalize;
// This struct doesn't need finalizing, but it's not annoted as such.
struct NonAnnotated(usize);

unsafe impl FinalizerOptional for HasDropNoFinalize {}
unsafe impl DropMethodFinalizerElidable for HasDropNoFinalize {}

impl<T> Drop for FinalizedContainer<T> {
fn drop(&mut self) {}
Expand Down

0 comments on commit 7883188

Please sign in to comment.