From c20717ef1d04680d5d4df676dd8479d092801374 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Sun, 21 Jul 2019 20:58:55 -0700 Subject: [PATCH] Lower core::ops::drop directly to MIR drop This change causes drop() to always drop in-place. This is meant to allow internal optimizations (see #62508). This does _not_ change the documented contract for drop(). Only internal compiler code is allowed to rely on this for now. --- src/libcore/mem/mod.rs | 1 + src/libcore/ops/drop.rs | 3 +- src/librustc/middle/lang_items.rs | 3 +- src/librustc_mir/build/expr/into.rs | 67 +++++++++++++++++++--------- src/test/mir-opt/box_expr.rs | 2 +- src/test/mir-opt/issue-49232.rs | 2 +- src/test/ui/type_length_limit.rs | 4 +- src/test/ui/type_length_limit.stderr | 8 ++-- 8 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index f2729168763bb..8871f667dcf28 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -693,6 +693,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// [`Copy`]: ../../std/marker/trait.Copy.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), lang = "drop")] pub fn drop(_x: T) { } /// Interprets `src` as having type `&U`, and then reads `src` without moving diff --git a/src/libcore/ops/drop.rs b/src/libcore/ops/drop.rs index eae63ea2390a8..2bd3234f5ae09 100644 --- a/src/libcore/ops/drop.rs +++ b/src/libcore/ops/drop.rs @@ -80,7 +80,8 @@ /// let _second = PrintOnDrop("Declared second!"); /// } /// ``` -#[lang = "drop"] +#[cfg_attr(not(bootstrap), lang = "drop_trait")] +#[cfg_attr(bootstrap, lang = "drop")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Drop { /// Executes the destructor for this type. diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index bdd48b3447498..1d94b165cacec 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -279,7 +279,7 @@ language_item_table! { SyncTraitLangItem, "sync", sync_trait, Target::Trait; FreezeTraitLangItem, "freeze", freeze_trait, Target::Trait; - DropTraitLangItem, "drop", drop_trait, Target::Trait; + DropTraitLangItem, "drop_trait", drop_trait, Target::Trait; CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait; DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait; @@ -349,6 +349,7 @@ language_item_table! { ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn, Target::Fn; BoxFreeFnLangItem, "box_free", box_free_fn, Target::Fn; + DropFnLangItem, "drop", drop_fn, Target::Fn; DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn, Target::Fn; OomLangItem, "oom", oom, Target::Fn; AllocLayoutLangItem, "alloc_layout", alloc_layout, Target::Struct; diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index e433da904a678..4fb5650e7d725 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -191,16 +191,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { exit_block.unit() } ExprKind::Call { ty, fun, args, from_hir_call } => { - let intrinsic = match ty.sty { + let (fn_def_id, intrinsic) = match ty.sty { ty::FnDef(def_id, _) => { let f = ty.fn_sig(this.hir.tcx()); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { - Some(this.hir.tcx().item_name(def_id).as_str()) + (Some(def_id), Some(this.hir.tcx().item_name(def_id).as_str())) } else { - None + (Some(def_id), None) } } - _ => None, + _ => (None, None), }; let intrinsic = intrinsic.as_ref().map(|s| &s[..]); let fun = unpack!(block = this.as_local_operand(block, fun)); @@ -237,26 +237,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|arg| unpack!(block = this.as_local_operand(block, arg))) .collect(); + let drop_location = if fn_def_id.is_some() + && this.hir.tcx().lang_items().drop_fn() == fn_def_id + { + assert_eq!(args.len(), 1, "drop() must have exactly one argument"); + match &args[0] { + Operand::Move(place) => Some(place.clone()), + _ => None, + } + } else { + None + }; + let success = this.cfg.start_new_block(); let cleanup = this.diverge_cleanup(); - this.cfg.terminate( - block, - source_info, - TerminatorKind::Call { - func: fun, - args, - cleanup: Some(cleanup), - // FIXME(varkor): replace this with an uninhabitedness-based check. - // This requires getting access to the current module to call - // `tcx.is_ty_uninhabited_from`, which is currently tricky to do. - destination: if expr.ty.is_never() { - None - } else { - Some((destination.clone(), success)) + + if let Some(location) = drop_location { + this.cfg.terminate( + block, + source_info, + TerminatorKind::Drop { + location, + target: success, + unwind: Some(cleanup) }, - from_hir_call, - }, - ); + ); + } else { + this.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func: fun, + args, + cleanup: Some(cleanup), + // FIXME(varkor): replace this with an uninhabitedness-based check. + // This requires getting access to the current module to call + // `tcx.is_ty_uninhabited_from`, which is currently tricky to do. + destination: if expr.ty.is_never() { + None + } else { + Some((destination.clone(), success)) + }, + from_hir_call, + }, + ); + } success.unit() } } diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index d9fa3d3d4736d..206b54d471d26 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -53,7 +53,7 @@ impl Drop for S { // StorageLive(_3); // StorageLive(_4); // _4 = move _1; -// _3 = const std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; +// drop(_4) -> [return: bb5, unwind: bb7]; // } // // bb5: { diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index d0dbcbd7515f8..a7e8efbaa5270 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -76,7 +76,7 @@ fn main() { // StorageLive(_5); // StorageLive(_6); // _6 = &_2; -// _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb4]; +// drop(_6) -> [return: bb13, unwind: bb4]; // } // bb13: { // StorageDead(_6); diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs index cd15f81a61535..7d4d40a885bd7 100644 --- a/src/test/ui/type_length_limit.rs +++ b/src/test/ui/type_length_limit.rs @@ -22,6 +22,8 @@ link! { F, G } pub struct G; +fn take(x: T) {} + fn main() { - drop::>(None); + take::>(None); } diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index 7e308f107ba00..532e6bd272bde 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -1,8 +1,8 @@ -error: reached the type-length limit while instantiating `std::mem::drop::>` - --> $SRC_DIR/libcore/mem/mod.rs:LL:COL +error: reached the type-length limit while instantiating `take::>` + --> $DIR/type_length_limit.rs:25:1 | -LL | pub fn drop(_x: T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn take(x: T) {} + | ^^^^^^^^^^^^^^^^^^^ | = note: consider adding a `#![type_length_limit="1094"]` attribute to your crate