2013-05-30 03:16:33 -07:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 16:48:01 -08:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
//!
|
|
|
|
//
|
|
|
|
// Code relating to taking, dropping, etc as well as type descriptors.
|
|
|
|
|
2013-05-17 15:28:44 -07:00
|
|
|
|
2013-02-25 14:11:21 -05:00
|
|
|
use back::abi;
|
|
|
|
use back::link::*;
|
2014-05-28 22:26:56 -07:00
|
|
|
use llvm::{ValueRef, True, get_param};
|
2014-07-07 17:58:01 -07:00
|
|
|
use llvm;
|
2014-10-01 01:26:04 +03:00
|
|
|
use middle::lang_items::ExchangeFreeFnLangItem;
|
2014-05-13 11:35:42 -04:00
|
|
|
use middle::subst;
|
2014-08-06 11:59:40 +02:00
|
|
|
use middle::subst::Subst;
|
2013-02-24 22:46:33 -08:00
|
|
|
use middle::trans::adt;
|
2012-12-13 13:05:22 -08:00
|
|
|
use middle::trans::base::*;
|
2014-01-10 14:02:36 -08:00
|
|
|
use middle::trans::build::*;
|
2012-12-23 17:41:37 -05:00
|
|
|
use middle::trans::callee;
|
2014-01-15 14:39:08 -05:00
|
|
|
use middle::trans::cleanup;
|
|
|
|
use middle::trans::cleanup::CleanupMethods;
|
2012-12-13 13:05:22 -08:00
|
|
|
use middle::trans::common::*;
|
2014-08-06 11:59:40 +02:00
|
|
|
use middle::trans::datum;
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
use middle::trans::debuginfo;
|
2013-02-25 14:11:21 -05:00
|
|
|
use middle::trans::expr;
|
|
|
|
use middle::trans::machine::*;
|
2012-12-23 17:41:37 -05:00
|
|
|
use middle::trans::tvec;
|
2014-01-10 14:02:36 -08:00
|
|
|
use middle::trans::type_::Type;
|
2014-08-06 11:59:40 +02:00
|
|
|
use middle::trans::type_of::{type_of, sizing_type_of, align_of};
|
2013-02-25 14:11:21 -05:00
|
|
|
use middle::ty;
|
2014-08-27 21:46:52 -04:00
|
|
|
use util::ppaux::{ty_to_short_str, Repr};
|
2014-01-10 14:02:36 -08:00
|
|
|
use util::ppaux;
|
2013-06-16 22:52:44 +12:00
|
|
|
|
2014-01-22 14:03:02 -05:00
|
|
|
use arena::TypedArena;
|
2013-08-03 17:13:14 -07:00
|
|
|
use std::c_str::ToCStr;
|
2014-02-26 12:58:41 -05:00
|
|
|
use libc::c_uint;
|
2013-02-25 14:11:21 -05:00
|
|
|
use syntax::ast;
|
2014-01-10 14:02:36 -08:00
|
|
|
use syntax::parse::token;
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2014-09-06 19:13:04 +03:00
|
|
|
pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
|
|
|
|
size: ValueRef, align: ValueRef)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-17 16:23:24 +12:00
|
|
|
let _icx = push_ctxt("trans_exchange_free");
|
2014-05-21 00:18:10 -04:00
|
|
|
let ccx = cx.ccx();
|
2013-06-16 15:45:48 +12:00
|
|
|
callee::trans_lang_call(cx,
|
2013-07-15 20:42:13 -07:00
|
|
|
langcall(cx, None, "", ExchangeFreeFnLangItem),
|
2014-08-06 11:59:40 +02:00
|
|
|
[PointerCast(cx, v, Type::i8p(ccx)), size, align],
|
2013-07-08 08:12:01 +02:00
|
|
|
Some(expr::Ignore)).bcx
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
2014-09-06 19:13:04 +03:00
|
|
|
pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
|
2014-10-14 23:36:11 +03:00
|
|
|
size: u64, align: u32) -> Block<'blk, 'tcx> {
|
|
|
|
trans_exchange_free_dyn(cx, v, C_uint(cx.ccx(), size),
|
|
|
|
C_uint(cx.ccx(), align))
|
2014-08-06 11:59:40 +02:00
|
|
|
}
|
|
|
|
|
2014-09-06 19:13:04 +03:00
|
|
|
pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef,
|
|
|
|
content_ty: ty::t) -> Block<'blk, 'tcx> {
|
2014-08-06 11:59:40 +02:00
|
|
|
assert!(ty::type_is_sized(bcx.ccx().tcx(), content_ty));
|
2014-05-21 00:18:10 -04:00
|
|
|
let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
|
|
|
|
let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
|
|
|
|
|
|
|
|
// `Box<ZeroSizeType>` does not allocate.
|
|
|
|
if content_size != 0 {
|
2014-08-06 11:59:40 +02:00
|
|
|
let content_align = align_of(bcx.ccx(), content_ty);
|
2014-05-21 00:18:10 -04:00
|
|
|
trans_exchange_free(bcx, ptr, content_size, content_align)
|
|
|
|
} else {
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:07:48 -04:00
|
|
|
pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
|
2014-03-15 22:29:34 +02:00
|
|
|
let tcx = ccx.tcx();
|
2014-08-06 11:59:40 +02:00
|
|
|
// Even if there is no dtor for t, there might be one deeper down and we
|
|
|
|
// might need to pass in the vtable ptr.
|
|
|
|
if !ty::type_is_sized(tcx, t) {
|
|
|
|
return t
|
|
|
|
}
|
2014-02-06 01:07:06 -05:00
|
|
|
if !ty::type_needs_drop(tcx, t) {
|
|
|
|
return ty::mk_i8();
|
|
|
|
}
|
|
|
|
match ty::get(t).sty {
|
DST coercions and DST structs
[breaking-change]
1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code.
2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible.
3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string.
2014-08-04 14:20:11 +02:00
|
|
|
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ)
|
|
|
|
&& ty::type_is_sized(tcx, typ) => {
|
|
|
|
let llty = sizing_type_of(ccx, typ);
|
|
|
|
// `Box<ZeroSizeType>` does not allocate.
|
|
|
|
if llsize_of_alloc(ccx, llty) == 0 {
|
|
|
|
ty::mk_i8()
|
|
|
|
} else {
|
2014-09-04 23:58:39 -04:00
|
|
|
t
|
2014-05-21 00:18:10 -04:00
|
|
|
}
|
|
|
|
}
|
2014-02-06 01:07:06 -05:00
|
|
|
_ => t
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
v: ValueRef,
|
|
|
|
t: ty::t,
|
|
|
|
source_location: Option<NodeInfo>)
|
2014-09-06 19:13:04 +03:00
|
|
|
-> Block<'blk, 'tcx> {
|
2012-08-28 15:54:45 -07:00
|
|
|
// NB: v is an *alias* of type t here, not a direct value.
|
2014-08-27 21:46:52 -04:00
|
|
|
debug!("drop_ty(t={})", t.repr(bcx.tcx()));
|
2013-06-17 16:23:24 +12:00
|
|
|
let _icx = push_ctxt("drop_ty");
|
2014-02-06 01:07:06 -05:00
|
|
|
if ty::type_needs_drop(bcx.tcx(), t) {
|
2014-04-25 15:14:52 +12:00
|
|
|
let ccx = bcx.ccx();
|
2014-02-06 01:07:06 -05:00
|
|
|
let glue = get_drop_glue(ccx, t);
|
|
|
|
let glue_type = get_drop_glue_type(ccx, t);
|
|
|
|
let ptr = if glue_type != t {
|
|
|
|
PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
|
|
|
|
} else {
|
|
|
|
v
|
|
|
|
};
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
|
|
|
|
match source_location {
|
|
|
|
Some(sl) => debuginfo::set_source_location(bcx.fcx, sl.id, sl.span),
|
|
|
|
None => debuginfo::clear_source_location(bcx.fcx)
|
|
|
|
};
|
|
|
|
|
2014-07-25 16:06:44 -07:00
|
|
|
Call(bcx, glue, [ptr], None);
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
2014-02-06 01:07:06 -05:00
|
|
|
bcx
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
v: ValueRef,
|
|
|
|
t: ty::t,
|
|
|
|
source_location: Option<NodeInfo>)
|
2014-09-06 19:13:04 +03:00
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-17 16:23:24 +12:00
|
|
|
let _icx = push_ctxt("drop_ty_immediate");
|
2013-09-30 22:40:44 -04:00
|
|
|
let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
|
|
|
|
Store(bcx, v, vp);
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
drop_ty(bcx, vp, t, source_location)
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
2014-03-06 18:47:24 +02:00
|
|
|
pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef {
|
2014-08-06 11:59:40 +02:00
|
|
|
debug!("make drop glue for {}", ppaux::ty_to_string(ccx.tcx(), t));
|
2014-02-06 01:07:06 -05:00
|
|
|
let t = get_drop_glue_type(ccx, t);
|
2014-08-06 11:59:40 +02:00
|
|
|
debug!("drop glue type {}", ppaux::ty_to_string(ccx.tcx(), t));
|
2014-09-05 09:18:53 -07:00
|
|
|
match ccx.drop_glues().borrow().find(&t) {
|
2014-03-15 22:29:34 +02:00
|
|
|
Some(&glue) => return glue,
|
|
|
|
_ => { }
|
2012-09-12 14:48:13 -07:00
|
|
|
}
|
|
|
|
|
2014-08-06 11:59:40 +02:00
|
|
|
let llty = if ty::type_is_sized(ccx.tcx(), t) {
|
|
|
|
type_of(ccx, t).ptr_to()
|
|
|
|
} else {
|
|
|
|
type_of(ccx, ty::mk_uniq(ccx.tcx(), t)).ptr_to()
|
|
|
|
};
|
|
|
|
|
|
|
|
let llfnty = Type::glue_fn(ccx, llty);
|
2014-07-31 16:45:29 -07:00
|
|
|
|
|
|
|
let (glue, new_sym) = match ccx.available_drop_glues().borrow().find(&t) {
|
|
|
|
Some(old_sym) => {
|
|
|
|
let glue = decl_cdecl_fn(ccx, old_sym.as_slice(), llfnty, ty::mk_nil());
|
|
|
|
(glue, None)
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
let (sym, glue) = declare_generic_glue(ccx, t, llfnty, "drop");
|
|
|
|
(glue, Some(sym))
|
|
|
|
},
|
|
|
|
};
|
2012-09-12 14:48:13 -07:00
|
|
|
|
2014-09-05 09:18:53 -07:00
|
|
|
ccx.drop_glues().borrow_mut().insert(t, glue);
|
2014-01-11 16:39:32 +02:00
|
|
|
|
2014-07-31 16:45:29 -07:00
|
|
|
// To avoid infinite recursion, don't `make_drop_glue` until after we've
|
|
|
|
// added the entry to the `drop_glues` cache.
|
|
|
|
match new_sym {
|
|
|
|
Some(sym) => {
|
|
|
|
ccx.available_drop_glues().borrow_mut().insert(t, sym);
|
|
|
|
// We're creating a new drop glue, so also generate a body.
|
|
|
|
make_generic_glue(ccx, t, glue, make_drop_glue, "drop");
|
|
|
|
},
|
|
|
|
None => {},
|
|
|
|
}
|
2012-09-12 14:48:13 -07:00
|
|
|
|
2014-02-06 01:07:06 -05:00
|
|
|
glue
|
|
|
|
}
|
2012-09-12 14:48:13 -07:00
|
|
|
|
2014-09-06 19:13:04 +03:00
|
|
|
fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|
|
|
t: ty::t,
|
|
|
|
v0: ValueRef,
|
|
|
|
dtor_did: ast::DefId,
|
|
|
|
class_did: ast::DefId,
|
|
|
|
substs: &subst::Substs)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-02-24 23:20:08 -08:00
|
|
|
let repr = adt::represent_type(bcx.ccx(), t);
|
2014-08-06 11:59:40 +02:00
|
|
|
let struct_data = if ty::type_is_sized(bcx.tcx(), t) {
|
|
|
|
v0
|
|
|
|
} else {
|
|
|
|
let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]);
|
|
|
|
Load(bcx, llval)
|
|
|
|
};
|
|
|
|
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
|
2014-06-14 15:55:55 +02:00
|
|
|
with_cond(bcx, load_ty(bcx, drop_flag.val, ty::mk_bool()), |cx| {
|
2013-10-31 23:31:11 -07:00
|
|
|
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
2013-11-21 15:42:55 -08:00
|
|
|
})
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
2014-09-06 19:13:04 +03:00
|
|
|
fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
t: ty::t,
|
|
|
|
v0: ValueRef,
|
|
|
|
dtor_did: ast::DefId,
|
|
|
|
class_did: ast::DefId,
|
|
|
|
substs: &subst::Substs)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-23 14:41:45 +12:00
|
|
|
let repr = adt::represent_type(bcx.ccx(), t);
|
|
|
|
|
|
|
|
// Find and call the actual destructor
|
2014-05-21 15:07:48 -04:00
|
|
|
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t,
|
2014-05-07 07:20:15 -04:00
|
|
|
class_did, substs);
|
2013-06-23 14:41:45 +12:00
|
|
|
|
2014-08-06 11:59:40 +02:00
|
|
|
// The first argument is the "self" argument for drop
|
2013-06-23 14:41:45 +12:00
|
|
|
let params = unsafe {
|
|
|
|
let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
|
|
|
|
ty.element_type().func_params()
|
|
|
|
};
|
|
|
|
|
2014-08-06 11:59:40 +02:00
|
|
|
let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs);
|
|
|
|
let self_ty = match ty::get(fty).sty {
|
|
|
|
ty::ty_bare_fn(ref f) => {
|
|
|
|
assert!(f.sig.inputs.len() == 1);
|
|
|
|
f.sig.inputs[0]
|
|
|
|
}
|
|
|
|
_ => bcx.sess().bug(format!("Expected function type, found {}",
|
|
|
|
bcx.ty_to_string(fty)).as_slice())
|
|
|
|
};
|
|
|
|
|
|
|
|
let (struct_data, info) = if ty::type_is_sized(bcx.tcx(), t) {
|
|
|
|
(v0, None)
|
|
|
|
} else {
|
|
|
|
let data = GEPi(bcx, v0, [0, abi::slice_elt_base]);
|
|
|
|
let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
|
|
|
|
(Load(bcx, data), Some(Load(bcx, info)))
|
|
|
|
};
|
|
|
|
|
|
|
|
adt::fold_variants(bcx, &*repr, struct_data, |variant_cx, st, value| {
|
2014-06-14 15:55:55 +02:00
|
|
|
// Be sure to put all of the fields into a scope so we can use an invoke
|
|
|
|
// instruction to call the user destructor but still call the field
|
2014-10-09 15:17:22 -04:00
|
|
|
// destructors if the user destructor panics.
|
2014-06-14 15:55:55 +02:00
|
|
|
let field_scope = variant_cx.fcx.push_custom_cleanup_scope();
|
|
|
|
|
|
|
|
// Class dtors have no explicit args, so the params should
|
|
|
|
// just consist of the environment (self).
|
|
|
|
assert_eq!(params.len(), 1);
|
2014-08-06 11:59:40 +02:00
|
|
|
let self_arg = if ty::type_is_fat_ptr(bcx.tcx(), self_ty) {
|
|
|
|
// The dtor expects a fat pointer, so make one, even if we have to fake it.
|
|
|
|
let boxed_ty = ty::mk_open(bcx.tcx(), t);
|
|
|
|
let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_self");
|
|
|
|
Store(bcx, value, GEPi(bcx, scratch.val, [0, abi::slice_elt_base]));
|
|
|
|
Store(bcx,
|
|
|
|
// If we just had a thin pointer, make a fat pointer by sticking
|
|
|
|
// null where we put the unsizing info. This works because t
|
|
|
|
// is a sized type, so we will only unpack the fat pointer, never
|
|
|
|
// use the fake info.
|
|
|
|
info.unwrap_or(C_null(Type::i8p(bcx.ccx()))),
|
|
|
|
GEPi(bcx, scratch.val, [0, abi::slice_elt_len]));
|
2014-10-14 23:05:01 -07:00
|
|
|
PointerCast(variant_cx, scratch.val, params[0])
|
2014-08-06 11:59:40 +02:00
|
|
|
} else {
|
2014-10-14 23:05:01 -07:00
|
|
|
PointerCast(variant_cx, value, params[0])
|
2014-08-06 11:59:40 +02:00
|
|
|
};
|
2014-06-14 15:55:55 +02:00
|
|
|
let args = vec!(self_arg);
|
|
|
|
|
|
|
|
// Add all the fields as a value which needs to be cleaned at the end of
|
2014-08-14 00:15:14 -07:00
|
|
|
// this scope. Iterate in reverse order so a Drop impl doesn't reverse
|
|
|
|
// the order in which fields get dropped.
|
|
|
|
for (i, ty) in st.fields.iter().enumerate().rev() {
|
2014-06-14 15:55:55 +02:00
|
|
|
let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
|
2014-08-06 11:59:40 +02:00
|
|
|
|
|
|
|
let val = if ty::type_is_sized(bcx.tcx(), *ty) {
|
|
|
|
llfld_a
|
|
|
|
} else {
|
|
|
|
let boxed_ty = ty::mk_open(bcx.tcx(), *ty);
|
|
|
|
let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_field");
|
|
|
|
Store(bcx, llfld_a, GEPi(bcx, scratch.val, [0, abi::slice_elt_base]));
|
|
|
|
Store(bcx, info.unwrap(), GEPi(bcx, scratch.val, [0, abi::slice_elt_len]));
|
|
|
|
scratch.val
|
|
|
|
};
|
2014-06-14 15:55:55 +02:00
|
|
|
variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
|
2014-08-06 11:59:40 +02:00
|
|
|
val, *ty);
|
2014-06-14 15:55:55 +02:00
|
|
|
}
|
2013-06-23 14:41:45 +12:00
|
|
|
|
2014-06-14 15:55:55 +02:00
|
|
|
let dtor_ty = ty::mk_ctor_fn(variant_cx.tcx(), ast::DUMMY_NODE_ID,
|
|
|
|
[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
|
2014-08-06 11:59:40 +02:00
|
|
|
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None, false);
|
2014-01-15 14:39:08 -05:00
|
|
|
|
2014-06-14 15:55:55 +02:00
|
|
|
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
|
|
|
|
variant_cx
|
|
|
|
})
|
2013-06-23 14:41:45 +12:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2014-09-06 19:13:04 +03:00
|
|
|
fn size_and_align_of_dst(bcx: Block, t :ty::t, info: ValueRef) -> (ValueRef, ValueRef) {
|
2014-08-06 11:59:40 +02:00
|
|
|
debug!("calculate size of DST: {}; with lost info: {}",
|
|
|
|
bcx.ty_to_string(t), bcx.val_to_string(info));
|
|
|
|
if ty::type_is_sized(bcx.tcx(), t) {
|
|
|
|
let sizing_type = sizing_type_of(bcx.ccx(), t);
|
2014-10-14 23:36:11 +03:00
|
|
|
let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
|
|
|
|
let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t));
|
2014-08-06 11:59:40 +02:00
|
|
|
return (size, align);
|
|
|
|
}
|
|
|
|
match ty::get(t).sty {
|
|
|
|
ty::ty_struct(id, ref substs) => {
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
// First get the size of all statically known fields.
|
|
|
|
// Don't use type_of::sizing_type_of because that expects t to be sized.
|
|
|
|
assert!(!ty::type_is_simd(bcx.tcx(), t));
|
|
|
|
let repr = adt::represent_type(ccx, t);
|
|
|
|
let sizing_type = adt::sizing_type_of(ccx, &*repr, true);
|
2014-10-14 23:36:11 +03:00
|
|
|
let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type));
|
|
|
|
let sized_align = C_uint(ccx, llalign_of_min(ccx, sizing_type));
|
2014-08-06 11:59:40 +02:00
|
|
|
|
|
|
|
// Recurse to get the size of the dynamically sized field (must be
|
|
|
|
// the last field).
|
|
|
|
let fields = ty::struct_fields(bcx.tcx(), id, substs);
|
|
|
|
let last_field = fields[fields.len()-1];
|
|
|
|
let field_ty = last_field.mt.ty;
|
|
|
|
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
|
|
|
|
|
|
|
|
// Return the sum of sizes and max of aligns.
|
|
|
|
let size = Add(bcx, sized_size, unsized_size);
|
|
|
|
let align = Select(bcx,
|
|
|
|
ICmp(bcx, llvm::IntULT, sized_align, unsized_align),
|
|
|
|
sized_align,
|
|
|
|
unsized_align);
|
|
|
|
(size, align)
|
|
|
|
}
|
|
|
|
ty::ty_trait(..) => {
|
|
|
|
// info points to the vtable and the second entry in the vtable is the
|
|
|
|
// dynamic size of the object.
|
|
|
|
let info = PointerCast(bcx, info, Type::int(bcx.ccx()).ptr_to());
|
|
|
|
let size_ptr = GEPi(bcx, info, [1u]);
|
|
|
|
let align_ptr = GEPi(bcx, info, [2u]);
|
|
|
|
(Load(bcx, size_ptr), Load(bcx, align_ptr))
|
|
|
|
}
|
|
|
|
ty::ty_vec(unit_ty, None) => {
|
|
|
|
// The info in this case is the length of the vec, so the size is that
|
|
|
|
// times the unit size.
|
|
|
|
let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
|
|
|
|
let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
|
2014-10-14 23:36:11 +03:00
|
|
|
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size)), C_uint(bcx.ccx(), 8u))
|
2014-08-06 11:59:40 +02:00
|
|
|
}
|
|
|
|
_ => bcx.sess().bug(format!("Unexpected unsized type, found {}",
|
|
|
|
bcx.ty_to_string(t)).as_slice())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 19:13:04 +03:00
|
|
|
fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2012-08-28 15:54:45 -07:00
|
|
|
// NB: v0 is an *alias* of type t here, not a direct value.
|
2013-06-17 16:23:24 +12:00
|
|
|
let _icx = push_ctxt("make_drop_glue");
|
2013-07-13 03:25:46 +02:00
|
|
|
match ty::get(t).sty {
|
2014-01-27 14:18:36 +02:00
|
|
|
ty::ty_uniq(content_ty) => {
|
2014-04-09 19:15:31 +12:00
|
|
|
match ty::get(content_ty).sty {
|
DST coercions and DST structs
[breaking-change]
1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code.
2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible.
3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string.
2014-08-04 14:20:11 +02:00
|
|
|
ty::ty_vec(ty, None) => {
|
2014-08-29 18:37:45 +12:00
|
|
|
tvec::make_drop_glue_unboxed(bcx, v0, ty, true)
|
2014-04-09 19:15:31 +12:00
|
|
|
}
|
2014-04-29 13:10:23 +12:00
|
|
|
ty::ty_str => {
|
2014-10-03 23:00:20 -07:00
|
|
|
let unit_ty = ty::sequence_element_type(bcx.tcx(), content_ty);
|
2014-08-29 18:37:45 +12:00
|
|
|
tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, true)
|
2014-04-27 10:19:15 +12:00
|
|
|
}
|
2014-06-11 17:18:57 +12:00
|
|
|
ty::ty_trait(..) => {
|
|
|
|
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
|
|
|
|
// Only drop the value when it is non-null
|
2014-08-06 11:59:40 +02:00
|
|
|
let concrete_ptr = Load(bcx, lluniquevalue);
|
|
|
|
with_cond(bcx, IsNotNull(bcx, concrete_ptr), |bcx| {
|
2014-06-11 17:18:57 +12:00
|
|
|
let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
|
|
|
|
let dtor = Load(bcx, dtor_ptr);
|
|
|
|
Call(bcx,
|
|
|
|
dtor,
|
|
|
|
[PointerCast(bcx, lluniquevalue, Type::i8p(bcx.ccx()))],
|
2014-07-25 16:06:44 -07:00
|
|
|
None);
|
2014-06-11 17:18:57 +12:00
|
|
|
bcx
|
|
|
|
})
|
|
|
|
}
|
2014-08-06 11:59:40 +02:00
|
|
|
ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), content_ty) => {
|
|
|
|
let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]);
|
|
|
|
let llbox = Load(bcx, llval);
|
|
|
|
let not_null = IsNotNull(bcx, llbox);
|
|
|
|
with_cond(bcx, not_null, |bcx| {
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
let bcx = drop_ty(bcx, v0, content_ty, None);
|
2014-08-06 11:59:40 +02:00
|
|
|
let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
|
|
|
|
let info = Load(bcx, info);
|
|
|
|
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
|
2014-09-05 03:39:15 -04:00
|
|
|
trans_exchange_free_dyn(bcx, llbox, llsize, llalign)
|
2014-08-06 11:59:40 +02:00
|
|
|
})
|
|
|
|
}
|
2014-04-09 19:15:31 +12:00
|
|
|
_ => {
|
2014-08-06 11:59:40 +02:00
|
|
|
assert!(ty::type_is_sized(bcx.tcx(), content_ty));
|
|
|
|
let llval = v0;
|
DST coercions and DST structs
[breaking-change]
1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code.
2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible.
3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string.
2014-08-04 14:20:11 +02:00
|
|
|
let llbox = Load(bcx, llval);
|
2014-06-11 17:18:57 +12:00
|
|
|
let not_null = IsNotNull(bcx, llbox);
|
2014-04-09 19:15:31 +12:00
|
|
|
with_cond(bcx, not_null, |bcx| {
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
let bcx = drop_ty(bcx, llbox, content_ty, None);
|
2014-05-21 00:18:10 -04:00
|
|
|
trans_exchange_free_ty(bcx, llbox, content_ty)
|
2014-04-09 19:15:31 +12:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2014-01-27 14:18:36 +02:00
|
|
|
}
|
2014-06-14 15:55:55 +02:00
|
|
|
ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) => {
|
2014-01-27 14:18:36 +02:00
|
|
|
let tcx = bcx.tcx();
|
|
|
|
match ty::ty_dtor(tcx, did) {
|
|
|
|
ty::TraitDtor(dtor, true) => {
|
2014-08-06 11:59:40 +02:00
|
|
|
// FIXME(16758) Since the struct is unsized, it is hard to
|
|
|
|
// find the drop flag (which is at the end of the struct).
|
|
|
|
// Lets just ignore the flag and pretend everything will be
|
|
|
|
// OK.
|
|
|
|
if ty::type_is_sized(bcx.tcx(), t) {
|
|
|
|
trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
|
|
|
|
} else {
|
|
|
|
// Give the user a heads up that we are doing something
|
|
|
|
// stupid and dangerous.
|
|
|
|
bcx.sess().warn(format!("Ignoring drop flag in destructor for {}\
|
|
|
|
because the struct is unsized. See issue\
|
|
|
|
#16758",
|
|
|
|
bcx.ty_to_string(t)).as_slice());
|
|
|
|
trans_struct_drop(bcx, t, v0, dtor, did, substs)
|
|
|
|
}
|
2014-01-27 14:18:36 +02:00
|
|
|
}
|
|
|
|
ty::TraitDtor(dtor, false) => {
|
|
|
|
trans_struct_drop(bcx, t, v0, dtor, did, substs)
|
|
|
|
}
|
|
|
|
ty::NoDtor => {
|
|
|
|
// No dtor? Just the default case
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
|
2014-01-27 14:18:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
ty::ty_unboxed_closure(..) => iter_structural_ty(bcx,
|
|
|
|
v0,
|
|
|
|
t,
|
|
|
|
|bb, vv, tt| drop_ty(bb, vv, tt, None)),
|
2014-04-11 18:03:10 +03:00
|
|
|
ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
|
2014-01-27 14:18:36 +02:00
|
|
|
let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
|
|
|
|
let env = Load(bcx, box_cell_v);
|
2014-03-15 22:29:34 +02:00
|
|
|
let env_ptr_ty = Type::at_box(bcx.ccx(), Type::i8(bcx.ccx())).ptr_to();
|
2014-01-27 14:18:36 +02:00
|
|
|
let env = PointerCast(bcx, env, env_ptr_ty);
|
|
|
|
with_cond(bcx, IsNotNull(bcx, env), |bcx| {
|
2014-09-15 16:31:32 -04:00
|
|
|
let dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_drop_glue]);
|
2014-02-05 23:05:30 -05:00
|
|
|
let dtor = Load(bcx, dtor_ptr);
|
2014-09-05 01:07:51 -04:00
|
|
|
Call(bcx, dtor, [PointerCast(bcx, box_cell_v, Type::i8p(bcx.ccx()))], None);
|
|
|
|
bcx
|
2014-01-27 14:18:36 +02:00
|
|
|
})
|
|
|
|
}
|
2014-08-06 11:59:40 +02:00
|
|
|
ty::ty_trait(..) => {
|
|
|
|
// No need to do a null check here (as opposed to the Box<trait case
|
|
|
|
// above), because this happens for a trait field in an unsized
|
|
|
|
// struct. If anything is null, it is the whole struct and we won't
|
|
|
|
// get here.
|
|
|
|
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
|
|
|
|
let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
|
|
|
|
let dtor = Load(bcx, dtor_ptr);
|
|
|
|
Call(bcx,
|
|
|
|
dtor,
|
|
|
|
[PointerCast(bcx, Load(bcx, lluniquevalue), Type::i8p(bcx.ccx()))],
|
|
|
|
None);
|
|
|
|
bcx
|
|
|
|
}
|
2014-08-29 18:37:45 +12:00
|
|
|
ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
|
2014-01-27 14:18:36 +02:00
|
|
|
_ => {
|
2014-08-06 11:59:40 +02:00
|
|
|
assert!(ty::type_is_sized(bcx.tcx(), t));
|
2014-03-15 22:29:34 +02:00
|
|
|
if ty::type_needs_drop(bcx.tcx(), t) &&
|
2014-01-27 14:18:36 +02:00
|
|
|
ty::type_is_structural(t) {
|
debuginfo: Make sure that all calls to drop glue are associated with debug locations.
This commit makes rustc emit debug locations for all call
and invoke statements in LLVM IR, if they are contained
within a function that debuginfo is enabled for. This is
important because LLVM does not handle the case where a
function body containing debuginfo is inlined into another
function with debuginfo, but the inlined call statement
does not have a debug location. In this case, LLVM will
not know where (in terms of source code coordinates) the
function was inlined to and we end up with some statements
still linked to the source locations in there original,
non-inlined function without any indication that they are
indeed an inline-copy. Later, when generating DWARF from
the IR, LLVM will interpret this as corrupt IR and abort.
Unfortunately, the undesirable case described above can
still occur when using LTO. If there is a crate compiled
without debuginfo calling into a crate compiled with
debuginfo, we again end up with the conditions triggering
the error. This is why some LTO tests still fail with the
dreaded assertion, if the standard library was built with
debuginfo enabled.
That is, `RUSTFLAGS_STAGE2=-g make rustc-stage2` will
succeed but `RUSTFLAGS_STAGE2=-g make check` will still
fail after this commit has been merged. This is a problem
that has to be dealt with separately.
Fixes #17201
Fixes #15816
Fixes #15156
2014-09-24 08:49:38 +02:00
|
|
|
iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
|
2014-01-27 14:18:36 +02:00
|
|
|
} else {
|
|
|
|
bcx
|
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
2013-07-13 03:25:46 +02:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generates the declaration for (but doesn't emit) a type descriptor.
|
2014-04-22 03:45:16 +03:00
|
|
|
pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info {
|
2012-08-28 15:54:45 -07:00
|
|
|
// If emit_tydescs already ran, then we shouldn't be creating any new
|
|
|
|
// tydescs.
|
2014-09-05 09:18:53 -07:00
|
|
|
assert!(!ccx.finished_tydescs().get());
|
2012-08-28 15:54:45 -07:00
|
|
|
|
|
|
|
let llty = type_of(ccx, t);
|
|
|
|
|
2014-03-05 16:36:01 +02:00
|
|
|
if ccx.sess().count_type_sizes() {
|
2013-09-24 22:16:43 -07:00
|
|
|
println!("{}\t{}", llsize_of_real(ccx, llty),
|
2014-06-21 03:39:03 -07:00
|
|
|
ppaux::ty_to_string(ccx.tcx(), t));
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
let llsize = llsize_of(ccx, llty);
|
|
|
|
let llalign = llalign_of(ccx, llty);
|
2014-01-31 12:42:39 -08:00
|
|
|
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc");
|
2014-06-21 03:39:03 -07:00
|
|
|
debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name);
|
2014-05-09 18:45:36 -07:00
|
|
|
let gvar = name.as_slice().with_c_str(|buf| {
|
2013-01-10 21:23:07 -08:00
|
|
|
unsafe {
|
2014-09-05 09:18:53 -07:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf)
|
2013-01-10 21:23:07 -08:00
|
|
|
}
|
2013-11-21 15:42:55 -08:00
|
|
|
});
|
2014-01-31 12:42:39 -08:00
|
|
|
note_unique_llvm_symbol(ccx, name);
|
2013-09-03 04:44:47 -04:00
|
|
|
|
2014-05-09 18:45:36 -07:00
|
|
|
let ty_name = token::intern_and_get_ident(
|
2014-06-21 03:39:03 -07:00
|
|
|
ppaux::ty_to_string(ccx.tcx(), t).as_slice());
|
2014-01-13 15:06:50 -08:00
|
|
|
let ty_name = C_str_slice(ccx, ty_name);
|
2013-09-03 04:44:47 -04:00
|
|
|
|
2014-06-21 03:39:03 -07:00
|
|
|
debug!("--- declare_tydesc {}", ppaux::ty_to_string(ccx.tcx(), t));
|
2014-04-22 03:45:16 +03:00
|
|
|
tydesc_info {
|
2013-02-04 14:02:01 -08:00
|
|
|
ty: t,
|
|
|
|
tydesc: gvar,
|
|
|
|
size: llsize,
|
|
|
|
align: llalign,
|
2013-09-03 04:44:47 -04:00
|
|
|
name: ty_name,
|
2014-04-22 03:45:16 +03:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
2014-01-11 16:39:32 +02:00
|
|
|
fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
|
2014-07-31 16:45:29 -07:00
|
|
|
name: &str) -> (String, ValueRef) {
|
2013-06-17 16:23:24 +12:00
|
|
|
let _icx = push_ctxt("declare_generic_glue");
|
2014-05-19 17:23:26 -07:00
|
|
|
let fn_nm = mangle_internal_name_by_type_and_seq(
|
|
|
|
ccx,
|
|
|
|
t,
|
|
|
|
format!("glue_{}", name).as_slice());
|
2014-05-12 20:03:34 +03:00
|
|
|
let llfn = decl_cdecl_fn(ccx, fn_nm.as_slice(), llfnty, ty::mk_nil());
|
2014-07-31 16:45:29 -07:00
|
|
|
note_unique_llvm_symbol(ccx, fn_nm.clone());
|
|
|
|
return (fn_nm, llfn);
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
2014-03-06 18:47:24 +02:00
|
|
|
fn make_generic_glue(ccx: &CrateContext,
|
2014-01-22 14:03:02 -05:00
|
|
|
t: ty::t,
|
|
|
|
llfn: ValueRef,
|
2014-09-06 19:13:04 +03:00
|
|
|
helper: <'blk, 'tcx> |Block<'blk, 'tcx>, ValueRef, ty::t|
|
|
|
|
-> Block<'blk, 'tcx>,
|
2014-01-22 14:03:02 -05:00
|
|
|
name: &str)
|
|
|
|
-> ValueRef {
|
2014-01-11 16:39:32 +02:00
|
|
|
let _icx = push_ctxt("make_generic_glue");
|
2014-05-27 20:44:58 -07:00
|
|
|
let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx(), t));
|
2014-01-11 16:39:32 +02:00
|
|
|
let _s = StatRecorder::new(ccx, glue_name);
|
2014-01-07 08:54:58 -08:00
|
|
|
|
2014-01-22 14:03:02 -05:00
|
|
|
let arena = TypedArena::new();
|
2014-05-14 20:53:48 -04:00
|
|
|
let empty_param_substs = param_substs::empty();
|
2014-10-24 21:14:37 +02:00
|
|
|
let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, ty::FnConverging(ty::mk_nil()),
|
2014-08-11 16:55:13 -07:00
|
|
|
&empty_param_substs, None, &arena);
|
2014-01-22 14:03:02 -05:00
|
|
|
|
2014-10-24 21:14:37 +02:00
|
|
|
let bcx = init_function(&fcx, false, ty::FnConverging(ty::mk_nil()));
|
2014-01-07 08:54:58 -08:00
|
|
|
|
2014-08-01 12:27:12 -07:00
|
|
|
update_linkage(ccx, llfn, None, OriginalTranslation);
|
2014-07-31 16:45:29 -07:00
|
|
|
|
2014-09-05 09:18:53 -07:00
|
|
|
ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1u);
|
2012-08-28 15:54:45 -07:00
|
|
|
// All glue functions take values passed *by alias*; this is a
|
|
|
|
// requirement since in many contexts glue is invoked indirectly and
|
|
|
|
// the caller has no idea if it's dealing with something that can be
|
|
|
|
// passed by value.
|
Use concrete types in glue functions
We used to have concrete types in glue functions, but the way we used
to implement that broke inlining of those functions. To fix that, we
converted all glue to just take an i8* and always casted to that type.
The problem with the old implementation was that we made a wrong
assumption about the glue functions, taking it for granted that they
always take an i8*, because that's the function type expected by the
TyDesc fields. Therefore, we always ended up with some kind of cast.
But actually, we can initially have the glue with concrete types and
only cast the functions to the generic type once we actually emit the
TyDesc data.
That means that for glue calls that can be statically resolved, we don't
need any casts, unless the glue uses a simplified type. In that case we
cast the argument. And for glue calls that are resolved at runtime, we
cast the argument to i8*, because that's what the glue function in the
TyDesc expects.
Since most of out glue calls are static, this saves a lot of bitcasts.
The size of the unoptimized librustc.ll goes down by 240k lines.
2013-07-13 18:23:08 +02:00
|
|
|
//
|
|
|
|
// llfn is expected be declared to take a parameter of the appropriate
|
|
|
|
// type, so we don't need to explicitly cast the function parameter.
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2014-05-28 22:26:56 -07:00
|
|
|
let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
|
2013-07-13 03:25:46 +02:00
|
|
|
let bcx = helper(bcx, llrawptr0, t);
|
2014-10-24 21:14:37 +02:00
|
|
|
finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil()));
|
2013-06-16 22:52:44 +12:00
|
|
|
|
2014-01-11 16:39:32 +02:00
|
|
|
llfn
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
2014-03-06 18:47:24 +02:00
|
|
|
pub fn emit_tydescs(ccx: &CrateContext) {
|
2013-06-17 16:23:24 +12:00
|
|
|
let _icx = push_ctxt("emit_tydescs");
|
2012-08-28 15:54:45 -07:00
|
|
|
// As of this point, allow no more tydescs to be created.
|
2014-09-05 09:18:53 -07:00
|
|
|
ccx.finished_tydescs().set(true);
|
2013-06-22 21:36:00 +02:00
|
|
|
let glue_fn_ty = Type::generic_glue_fn(ccx).ptr_to();
|
2014-09-05 09:18:53 -07:00
|
|
|
for (_, ti) in ccx.tydescs().borrow().iter() {
|
2012-08-28 15:54:45 -07:00
|
|
|
// Each of the glue functions needs to be cast to a generic type
|
|
|
|
// before being put into the tydesc because we only have a singleton
|
|
|
|
// tydesc type. Then we'll recast each function to its real type when
|
|
|
|
// calling it.
|
2014-02-06 01:07:06 -05:00
|
|
|
let drop_glue = unsafe {
|
|
|
|
llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
|
|
|
|
};
|
2014-09-05 09:18:53 -07:00
|
|
|
ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1);
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2014-03-15 22:29:34 +02:00
|
|
|
let tydesc = C_named_struct(ccx.tydesc_type(),
|
2013-06-20 14:45:10 +02:00
|
|
|
[ti.size, // size
|
2013-08-11 13:29:14 -04:00
|
|
|
ti.align, // align
|
|
|
|
drop_glue, // drop_glue
|
2013-09-03 04:44:47 -04:00
|
|
|
ti.name]); // name
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2013-01-10 21:23:07 -08:00
|
|
|
unsafe {
|
|
|
|
let gvar = ti.tydesc;
|
|
|
|
llvm::LLVMSetInitializer(gvar, tydesc);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2014-07-07 17:58:01 -07:00
|
|
|
llvm::SetLinkage(gvar, llvm::InternalLinkage);
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|