Change:
The MIR code currently adds drops for all types that are not , even if we can see that there is no destructor (e.g., ). This is relatively harmless (trans ignores such types) but it means more memory alloc etc than necessary. See associated FIXME.

Discussion:
use std::collections::{HashMap, HashSet}; use syntax::ast::{self, CrateNum, Name, NodeId}; use syntax::attr::{self, AttrMetaMethods}; <del> use syntax::codemap::Span; </del> <ins> use syntax::codemap::{DUMMY_SP, Span}; </ins> use syntax::parse::token::{InternedString, special_idents}; use rustc_front::hir;

|| self.sess.cstore.item_super_predicates(self, did)) } <ins> /// If `type_needs_drop` returns true, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// false, then `ty` definitely has no destructor (i.e. no drop glue). /// /// (Note that this implies that if `ty` has a destructor attached, /// then `type_needs_drop` will definitely return `true` for `ty`.) pub fn type_needs_drop_given_env<'a>(&self, ty: Ty<'tcx>, param_env: &ty::ParameterEnvironment<'a,'tcx>) -> bool { // Issue #22536: We first query type_moves_by_default.  It sees a // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no // cleanup/drop/zeroing) ... let implements_copy = !ty.moves_by_default(param_env, DUMMY_SP); if implements_copy { return false; } // ... (issue #22536 continued) but as an optimization, still use // prior logic of asking if the `needs_drop` bit is set; we need // not zero non-Copy types if they have no destructor. // FIXME(#22815): Note that calling `ty::type_contents` is a // conservative heuristic; it may report that `needs_drop` is set // when actual type does not actually have a destructor associated // with it. But since `ty` absolutely did not have the `Copy` // bound attached (see above), it is sound to treat it as having a // destructor (e.g. zero its memory on move). let contents = ty.type_contents(self); debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); contents.needs_drop(self) } </ins> /// Get the attributes of a definition. pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [ast::Attribute]> { if let Some(id) = self.map.as_local_node_id(did) {

kind: DropKind, lvalue: &Lvalue<'tcx>, lvalue_ty: Ty<'tcx>) { <del> if self.hir.needs_drop(lvalue_ty, span) { </del> <ins> if self.hir.needs_drop(lvalue_ty) { </ins> match self.scopes.iter_mut().rev().find(|s| s.extent == extent) { Some(scope) => { scope.drops.push((kind, span, lvalue.clone()));

.collect() } <del> pub fn needs_drop(&mut self, ty: Ty<'tcx>, span: Span) -> bool { if self.infcx.type_moves_by_default(ty, span) { // FIXME(#21859) we should do an add'l check here to determine if // any dtor will execute, but the relevant fn // (`type_needs_drop`) is currently factored into // `librustc_trans`, so we can't easily do so. true } else { // if type implements Copy, cannot require drop false } </del> <ins> pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool { self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment) </ins> } pub fn span_bug(&mut self, span: Span, message: &str) -> ! {

} } <del> /// If `type_needs_drop` returns true, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// false, then `ty` definitely has no destructor (i.e. no drop glue). /// /// (Note that this implies that if `ty` has a destructor attached, /// then `type_needs_drop` will definitely return `true` for `ty`.) pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { type_needs_drop_given_env(cx, ty, &cx.empty_parameter_environment()) } /// Core implementation of type_needs_drop, potentially making use of /// and/or updating caches held in the `param_env`. fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_env: &ty::ParameterEnvironment<'a,'tcx>) -> bool { // Issue #22536: We first query type_moves_by_default.  It sees a // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no // cleanup/drop/zeroing) ... let implements_copy = !ty.moves_by_default(param_env, DUMMY_SP); if implements_copy { return false; } // ... (issue #22536 continued) but as an optimization, still use // prior logic of asking if the `needs_drop` bit is set; we need // not zero non-Copy types if they have no destructor. // FIXME(#22815): Note that calling `ty::type_contents` is a // conservative heuristic; it may report that `needs_drop` is set // when actual type does not actually have a destructor associated // with it. But since `ty` absolutely did not have the `Copy` // bound attached (see above), it is sound to treat it as having a // destructor (e.g. zero its memory on move). let contents = ty.type_contents(cx); debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); contents.needs_drop(cx) } </del> fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { ty::TyStruct(def, substs) => {

/// This is the same as `common::type_needs_drop`, except that it /// may use or update caches within this `FunctionContext`. pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { <del> type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env) </del> <ins> self.ccx.tcx().type_needs_drop_given_env(ty, &self.param_env) </ins> } pub fn eh_personality(&self) -> ValueRef {

} } <ins> fn type_needs_drop<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { tcx.type_needs_drop_given_env(ty, &tcx.empty_parameter_environment()) } </ins> pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { let tcx = ccx.tcx();

// returned `tcx.types.i8` does not appear unsound. The impact on // code quality is unknown at this time.) <del> if !type_needs_drop(tcx, t) { </del> <ins> if !type_needs_drop(&tcx, t) { </ins> return tcx.types.i8; } match t.sty { <del> ty::TyBox(typ) if !type_needs_drop(tcx, typ) </del> <ins> ty::TyBox(typ) if !type_needs_drop(&tcx, typ) </ins> && type_is_sized(tcx, typ) => { let llty = sizing_type_of(ccx, typ); // `Box<ZeroSizeType>` does not allocate.