2014-02-10 08:36:31 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06: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 17:54:45 -05:00
|
|
|
/*!
|
2014-01-15 13:39:08 -06:00
|
|
|
* # Translation of Expressions
|
|
|
|
*
|
|
|
|
* Public entry points:
|
|
|
|
*
|
|
|
|
* - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression,
|
|
|
|
* storing the result into `dest`. This is the preferred form, if you
|
|
|
|
* can manage it.
|
|
|
|
*
|
|
|
|
* - `trans(bcx, expr) -> DatumBlock`: evaluates an expression, yielding
|
|
|
|
* `Datum` with the result. You can then store the datum, inspect
|
|
|
|
* the value, etc. This may introduce temporaries if the datum is a
|
|
|
|
* structural type.
|
|
|
|
*
|
|
|
|
* - `trans_to_lvalue(bcx, expr, "...") -> DatumBlock`: evaluates an
|
|
|
|
* expression and ensures that the result has a cleanup associated with it,
|
|
|
|
* creating a temporary stack slot if necessary.
|
|
|
|
*
|
|
|
|
* - `trans_local_var -> Datum`: looks up a local variable or upvar.
|
|
|
|
*
|
|
|
|
* See doc.rs for more comments.
|
|
|
|
*/
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2014-03-21 20:05:05 -05:00
|
|
|
#![allow(non_camel_case_types)]
|
2014-02-10 08:36:31 -06:00
|
|
|
|
2014-11-06 02:05:53 -06:00
|
|
|
pub use self::cast_kind::*;
|
|
|
|
pub use self::Dest::*;
|
|
|
|
use self::lazy_binop_ty::*;
|
|
|
|
|
2013-02-25 13:11:21 -06:00
|
|
|
use back::abi;
|
2014-07-07 19:58:01 -05:00
|
|
|
use llvm;
|
|
|
|
use llvm::{ValueRef};
|
2014-05-14 14:31:30 -05:00
|
|
|
use middle::def;
|
2014-06-01 18:35:01 -05:00
|
|
|
use middle::mem_categorization::Typer;
|
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 07:20:11 -05:00
|
|
|
use middle::subst;
|
2014-09-12 10:42:58 -05:00
|
|
|
use middle::subst::Subst;
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::_match;
|
|
|
|
use trans::adt;
|
|
|
|
use trans::asm;
|
|
|
|
use trans::base::*;
|
|
|
|
use trans::base;
|
|
|
|
use trans::build::*;
|
|
|
|
use trans::callee;
|
|
|
|
use trans::cleanup;
|
|
|
|
use trans::cleanup::CleanupMethods;
|
|
|
|
use trans::closure;
|
|
|
|
use trans::common::*;
|
|
|
|
use trans::consts;
|
|
|
|
use trans::controlflow;
|
|
|
|
use trans::datum::*;
|
|
|
|
use trans::debuginfo;
|
|
|
|
use trans::glue;
|
|
|
|
use trans::machine;
|
|
|
|
use trans::meth;
|
|
|
|
use trans::inline;
|
|
|
|
use trans::tvec;
|
|
|
|
use trans::type_of;
|
2014-08-09 22:54:33 -05:00
|
|
|
use middle::ty::{struct_fields, tup_fields};
|
2014-09-11 00:07:49 -05:00
|
|
|
use middle::ty::{AdjustDerefRef, AdjustAddEnv, AutoUnsafe};
|
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 07:20:11 -05:00
|
|
|
use middle::ty::{AutoPtr};
|
2014-09-13 13:09:25 -05:00
|
|
|
use middle::ty::{mod, Ty};
|
2014-06-01 18:35:01 -05:00
|
|
|
use middle::typeck;
|
2014-06-11 17:01:48 -05:00
|
|
|
use middle::typeck::MethodCall;
|
2012-12-13 15:05:22 -06:00
|
|
|
use util::common::indenter;
|
2013-03-15 14:24:24 -05:00
|
|
|
use util::ppaux::Repr;
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::machine::{llsize_of, llsize_of_alloc};
|
|
|
|
use trans::type_::Type;
|
2013-06-16 05:52:44 -05:00
|
|
|
|
2013-01-09 11:49:11 -06:00
|
|
|
use syntax::ast;
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::codemap;
|
2014-06-21 05:39:03 -05:00
|
|
|
use syntax::print::pprust::{expr_to_string};
|
2014-09-07 12:09:06 -05:00
|
|
|
use syntax::ptr::P;
|
2014-09-12 10:42:58 -05:00
|
|
|
use std::rc::Rc;
|
2014-05-16 12:15:33 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
// Destinations
|
|
|
|
|
|
|
|
// These are passed around by the code generating functions to track the
|
|
|
|
// destination of a computation's value.
|
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq)]
|
2013-01-29 19:57:02 -06:00
|
|
|
pub enum Dest {
|
2012-08-28 17:54:45 -05:00
|
|
|
SaveIn(ValueRef),
|
|
|
|
Ignore,
|
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl Dest {
|
2014-06-21 05:39:03 -05:00
|
|
|
pub fn to_string(&self, ccx: &CrateContext) -> String {
|
2013-02-22 00:41:37 -06:00
|
|
|
match *self {
|
2014-09-05 11:18:53 -05:00
|
|
|
SaveIn(v) => format!("SaveIn({})", ccx.tn().val_to_string(v)),
|
2014-05-25 05:17:19 -05:00
|
|
|
Ignore => "Ignore".to_string()
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
dest: Dest)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-01-15 13:39:08 -06:00
|
|
|
/*!
|
|
|
|
* This function is equivalent to `trans(bcx, expr).store_to_dest(dest)`
|
|
|
|
* but it may generate better optimized LLVM code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
let mut bcx = bcx;
|
|
|
|
|
2014-03-20 21:49:20 -05:00
|
|
|
if bcx.tcx().adjustments.borrow().contains_key(&expr.id) {
|
2014-01-15 13:39:08 -06:00
|
|
|
// use trans, which may be less efficient but
|
|
|
|
// which will perform the adjustments:
|
|
|
|
let datum = unpack_datum!(bcx, trans(bcx, expr));
|
|
|
|
return datum.store_to_dest(bcx, dest, expr.id)
|
|
|
|
}
|
|
|
|
|
|
|
|
debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
|
|
|
|
|
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 01:49:38 -05:00
|
|
|
let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(expr.id,
|
|
|
|
expr.span,
|
|
|
|
false);
|
|
|
|
bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
|
2014-01-15 13:39:08 -06: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 01:49:38 -05:00
|
|
|
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
|
2014-04-09 10:18:40 -05:00
|
|
|
let kind = ty::expr_kind(bcx.tcx(), expr);
|
2014-01-15 13:39:08 -06:00
|
|
|
bcx = match kind {
|
|
|
|
ty::LvalueExpr | ty::RvalueDatumExpr => {
|
|
|
|
trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
|
|
|
|
}
|
|
|
|
ty::RvalueDpsExpr => {
|
|
|
|
trans_rvalue_dps_unadjusted(bcx, expr, dest)
|
|
|
|
}
|
|
|
|
ty::RvalueStmtExpr => {
|
|
|
|
trans_rvalue_stmt_unadjusted(bcx, expr)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
/*!
|
|
|
|
* Translates an expression, returning a datum (and new block)
|
|
|
|
* encapsulating the result. When possible, it is preferred to
|
|
|
|
* use `trans_into`, as that may avoid creating a temporary on
|
|
|
|
* the stack.
|
|
|
|
*/
|
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
debug!("trans(expr={})", bcx.expr_to_string(expr));
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-05-07 10:41:27 -05:00
|
|
|
let mut bcx = bcx;
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
|
|
|
|
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 01:49:38 -05:00
|
|
|
let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(expr.id,
|
|
|
|
expr.span,
|
|
|
|
false);
|
|
|
|
fcx.push_ast_cleanup_scope(cleanup_debug_loc);
|
2014-01-15 13:39:08 -06:00
|
|
|
let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
|
|
|
|
let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
|
|
|
|
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
|
2014-05-28 14:36:05 -05:00
|
|
|
return DatumBlock::new(bcx, datum);
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn get_len(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
|
2014-11-17 02:39:01 -06:00
|
|
|
GEPi(bcx, fat_ptr, &[0u, abi::slice_elt_len])
|
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 07:20:11 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
|
2014-11-17 02:39:01 -06:00
|
|
|
GEPi(bcx, fat_ptr, &[0u, abi::slice_elt_base])
|
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 07:20:11 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
/*!
|
|
|
|
* Helper for trans that apply adjustments from `expr` to `datum`,
|
|
|
|
* which should be the unadjusted translation of `expr`.
|
|
|
|
*/
|
|
|
|
|
|
|
|
let mut bcx = bcx;
|
|
|
|
let mut datum = datum;
|
2014-11-07 13:35:18 -06:00
|
|
|
let adjustment = match bcx.tcx().adjustments.borrow().get(&expr.id).cloned() {
|
2014-03-20 21:49:20 -05:00
|
|
|
None => {
|
2014-05-28 14:36:05 -05:00
|
|
|
return DatumBlock::new(bcx, datum);
|
2013-12-19 20:26:45 -06:00
|
|
|
}
|
2014-03-20 21:49:20 -05:00
|
|
|
Some(adj) => { adj }
|
2013-05-07 10:41:27 -05:00
|
|
|
};
|
2014-01-15 13:39:08 -06:00
|
|
|
debug!("unadjusted datum for expr {}: {}",
|
2014-06-21 05:39:03 -05:00
|
|
|
expr.id, datum.to_string(bcx.ccx()));
|
2014-04-10 08:26:26 -05:00
|
|
|
match adjustment {
|
2014-09-11 00:07:49 -05:00
|
|
|
AdjustAddEnv(..) => {
|
2013-05-07 10:41:27 -05:00
|
|
|
datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
|
|
|
|
}
|
2014-09-11 00:07:49 -05:00
|
|
|
AdjustDerefRef(ref adj) => {
|
2014-08-25 19:35:25 -05:00
|
|
|
let (autoderefs, use_autoref) = match adj.autoref {
|
|
|
|
// Extracting a value from a box counts as a deref, but if we are
|
|
|
|
// just converting Box<[T, ..n]> to Box<[T]> we aren't really doing
|
|
|
|
// a deref (and wouldn't if we could treat Box like a normal struct).
|
|
|
|
Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true),
|
|
|
|
// We are a bit paranoid about adjustments and thus might have a re-
|
|
|
|
// borrow here which merely derefs and then refs again (it might have
|
|
|
|
// a different region or mutability, but we don't care here. It might
|
|
|
|
// also be just in case we need to unsize. But if there are no nested
|
|
|
|
// adjustments then it should be a no-op).
|
|
|
|
Some(ty::AutoPtr(_, _, None)) if adj.autoderefs == 1 => {
|
|
|
|
match ty::get(datum.ty).sty {
|
|
|
|
// Don't skip a conversion from Box<T> to &T, etc.
|
|
|
|
ty::ty_rptr(..) => {
|
|
|
|
let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1);
|
2014-11-06 11:25:16 -06:00
|
|
|
let method = bcx.tcx().method_map.borrow().get(&method_call).is_some();
|
2014-08-25 19:35:25 -05:00
|
|
|
if method {
|
|
|
|
// Don't skip an overloaded deref.
|
|
|
|
(adj.autoderefs, true)
|
|
|
|
} else {
|
|
|
|
(adj.autoderefs - 1, false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => (adj.autoderefs, true),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => (adj.autoderefs, true)
|
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 07:20:11 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
if autoderefs > 0 {
|
2014-08-25 19:35:25 -05:00
|
|
|
// Schedule cleanup.
|
|
|
|
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
|
2014-01-15 13:39:08 -06:00
|
|
|
datum = unpack_datum!(
|
2014-08-06 04:59:40 -05:00
|
|
|
bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs));
|
2012-09-11 23:25:01 -05:00
|
|
|
}
|
|
|
|
|
2014-08-25 19:35:25 -05:00
|
|
|
// (You might think there is a more elegant way to do this than a
|
|
|
|
// use_autoref bool, but then you remember that the borrow checker exists).
|
|
|
|
match (use_autoref, &adj.autoref) {
|
|
|
|
(true, &Some(ref a)) => {
|
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 07:20:11 -05:00
|
|
|
datum = unpack_datum!(bcx, apply_autoref(a,
|
|
|
|
bcx,
|
|
|
|
expr,
|
|
|
|
datum));
|
2013-03-15 14:24:24 -05:00
|
|
|
}
|
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 07:20:11 -05:00
|
|
|
_ => {}
|
|
|
|
}
|
2013-12-26 12:54:41 -06:00
|
|
|
}
|
2013-05-07 10:41:27 -05:00
|
|
|
}
|
2014-06-21 05:39:03 -05:00
|
|
|
debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
|
2014-08-25 19:35:25 -05:00
|
|
|
return DatumBlock::new(bcx, datum);
|
2012-09-11 23:25:01 -05:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef,
|
|
|
|
bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
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 07:20:11 -05:00
|
|
|
let mut bcx = bcx;
|
|
|
|
let mut datum = datum;
|
|
|
|
|
|
|
|
let datum = match autoref {
|
2014-08-27 00:07:28 -05:00
|
|
|
&AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => {
|
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 07:20:11 -05:00
|
|
|
debug!(" AutoPtr");
|
|
|
|
match a {
|
|
|
|
&Some(box ref a) => datum = unpack_datum!(bcx,
|
|
|
|
apply_autoref(a, bcx, expr, datum)),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
unpack_datum!(bcx, ref_ptr(bcx, expr, datum))
|
|
|
|
}
|
|
|
|
&ty::AutoUnsize(ref k) => {
|
|
|
|
debug!(" AutoUnsize");
|
|
|
|
unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k))
|
|
|
|
}
|
|
|
|
|
|
|
|
&ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => {
|
|
|
|
debug!(" AutoUnsizeUniq(UnsizeLength)");
|
|
|
|
unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len))
|
|
|
|
}
|
|
|
|
&ty::AutoUnsizeUniq(ref k) => {
|
|
|
|
debug!(" AutoUnsizeUniq");
|
|
|
|
unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k))
|
|
|
|
}
|
|
|
|
};
|
2012-09-11 23:25:01 -05:00
|
|
|
|
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 07:20:11 -05:00
|
|
|
DatumBlock::new(bcx, datum)
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn ref_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
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 07:20:11 -05:00
|
|
|
if !ty::type_is_sized(bcx.tcx(), datum.ty) {
|
|
|
|
debug!("Taking address of unsized type {}",
|
2014-08-06 04:59:40 -05:00
|
|
|
bcx.ty_to_string(datum.ty));
|
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 07:20:11 -05:00
|
|
|
ref_fat_ptr(bcx, expr, datum)
|
|
|
|
} else {
|
|
|
|
debug!("Taking address of sized type {}",
|
2014-08-06 04:59:40 -05:00
|
|
|
bcx.ty_to_string(datum.ty));
|
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 07:20:11 -05:00
|
|
|
auto_ref(bcx, datum, expr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the information we are losing (making dynamic) in an unsizing
|
|
|
|
// adjustment.
|
2014-08-06 04:59:40 -05:00
|
|
|
// When making a dtor, we need to do different things depending on the
|
|
|
|
// ownership of the object.. mk_ty is a function for turning unsized_type
|
|
|
|
// into a type to be destructed. If we want to end up with a Box pointer,
|
|
|
|
// then mk_ty should make a Box pointer (T -> Box<T>), if we want a
|
|
|
|
// borrowed reference then it should be T -> &T.
|
2014-09-06 11:13:04 -05:00
|
|
|
fn unsized_info<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
kind: &ty::UnsizeKind,
|
|
|
|
id: ast::NodeId,
|
2014-09-13 13:09:25 -05:00
|
|
|
unsized_ty: Ty,
|
|
|
|
mk_ty: |Ty| -> Ty) -> ValueRef {
|
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 07:20:11 -05:00
|
|
|
match kind {
|
|
|
|
&ty::UnsizeLength(len) => C_uint(bcx.ccx(), len),
|
2014-08-06 04:59:40 -05:00
|
|
|
&ty::UnsizeStruct(box ref k, tp_index) => match ty::get(unsized_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 07:20:11 -05:00
|
|
|
ty::ty_struct(_, ref substs) => {
|
2014-08-06 04:59:40 -05:00
|
|
|
let ty_substs = substs.types.get_slice(subst::TypeSpace);
|
|
|
|
// The dtor for a field treats it like a value, so mk_ty
|
|
|
|
// should just be the identity function.
|
|
|
|
unsized_info(bcx, k, id, ty_substs[tp_index], |t| t)
|
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 07:20:11 -05:00
|
|
|
}
|
|
|
|
_ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}",
|
2014-08-06 04:59:40 -05:00
|
|
|
bcx.ty_to_string(unsized_ty)).as_slice())
|
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 07:20:11 -05:00
|
|
|
},
|
2014-11-07 05:16:57 -06:00
|
|
|
&ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
|
2014-11-15 15:50:34 -06:00
|
|
|
let substs = principal.substs.with_self_ty(unsized_ty).erase_regions();
|
2014-09-12 10:42:58 -05:00
|
|
|
let trait_ref =
|
2014-11-07 05:16:57 -06:00
|
|
|
Rc::new(ty::TraitRef { def_id: principal.def_id,
|
2014-09-12 10:42:58 -05:00
|
|
|
substs: substs });
|
|
|
|
let trait_ref =
|
2014-11-15 15:50:34 -06:00
|
|
|
trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs.substs());
|
2014-09-12 10:42:58 -05:00
|
|
|
let box_ty = mk_ty(unsized_ty);
|
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 07:20:11 -05:00
|
|
|
PointerCast(bcx,
|
2014-09-12 10:42:58 -05:00
|
|
|
meth::get_vtable(bcx, box_ty, trait_ref),
|
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 07:20:11 -05:00
|
|
|
Type::vtable_ptr(bcx.ccx()))
|
2014-09-12 10:42:58 -05:00
|
|
|
}
|
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 07:20:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>,
|
|
|
|
k: &ty::UnsizeKind)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
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 07:20:11 -05:00
|
|
|
let tcx = bcx.tcx();
|
|
|
|
let datum_ty = datum.ty;
|
|
|
|
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
|
|
|
|
let dest_ty = ty::mk_open(tcx, unsized_ty);
|
|
|
|
// Closures for extracting and manipulating the data and payload parts of
|
|
|
|
// the fat pointer.
|
|
|
|
let base = match k {
|
|
|
|
&ty::UnsizeStruct(..) =>
|
|
|
|
|bcx, val| PointerCast(bcx,
|
|
|
|
val,
|
|
|
|
type_of::type_of(bcx.ccx(), unsized_ty).ptr_to()),
|
|
|
|
&ty::UnsizeLength(..) =>
|
2014-11-17 02:39:01 -06:00
|
|
|
|bcx, val| GEPi(bcx, val, &[0u, 0u]),
|
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 07:20:11 -05:00
|
|
|
&ty::UnsizeVtable(..) =>
|
|
|
|
|_bcx, val| PointerCast(bcx, val, Type::i8p(bcx.ccx()))
|
|
|
|
};
|
2014-08-06 04:59:40 -05:00
|
|
|
let info = |bcx, _val| unsized_info(bcx,
|
|
|
|
k,
|
|
|
|
expr.id,
|
|
|
|
ty::deref_or_dont(datum_ty),
|
|
|
|
|t| ty::mk_rptr(tcx,
|
|
|
|
ty::ReStatic,
|
|
|
|
ty::mt{
|
|
|
|
ty: t,
|
|
|
|
mutbl: ast::MutImmutable
|
|
|
|
}));
|
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 07:20:11 -05:00
|
|
|
into_fat_ptr(bcx, expr, datum, dest_ty, base, info)
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
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 07:20:11 -05:00
|
|
|
let tcx = bcx.tcx();
|
|
|
|
let dest_ty = ty::close_type(tcx, datum.ty);
|
|
|
|
let base = |bcx, val| Load(bcx, get_dataptr(bcx, val));
|
|
|
|
let len = |bcx, val| Load(bcx, get_len(bcx, val));
|
|
|
|
into_fat_ptr(bcx, expr, datum, dest_ty, base, len)
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn into_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>,
|
2014-09-13 13:09:25 -05:00
|
|
|
dest_ty: Ty,
|
2014-09-06 11:13:04 -05:00
|
|
|
base: |Block<'blk, 'tcx>, ValueRef| -> ValueRef,
|
|
|
|
info: |Block<'blk, 'tcx>, ValueRef| -> ValueRef)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
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 07:20:11 -05:00
|
|
|
let mut bcx = bcx;
|
|
|
|
|
|
|
|
// Arrange cleanup
|
|
|
|
let lval = unpack_datum!(bcx,
|
|
|
|
datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
|
|
|
|
let base = base(bcx, lval.val);
|
|
|
|
let info = info(bcx, lval.val);
|
|
|
|
|
|
|
|
let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
|
|
|
|
Store(bcx, base, get_dataptr(bcx, scratch.val));
|
|
|
|
Store(bcx, info, get_len(bcx, scratch.val));
|
|
|
|
|
|
|
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>,
|
|
|
|
len: uint)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
2012-09-11 23:25:01 -05:00
|
|
|
let tcx = bcx.tcx();
|
2013-05-06 13:02:28 -05:00
|
|
|
|
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 07:20:11 -05:00
|
|
|
let datum_ty = datum.ty;
|
|
|
|
// Arrange cleanup
|
|
|
|
let lval = unpack_datum!(bcx,
|
|
|
|
datum.to_lvalue_datum(bcx, "unsize_unique_vec", expr.id));
|
|
|
|
|
|
|
|
let ll_len = C_uint(bcx.ccx(), len);
|
|
|
|
let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty));
|
|
|
|
let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None));
|
|
|
|
let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique");
|
|
|
|
|
2014-09-08 18:27:06 -05:00
|
|
|
let base = get_dataptr(bcx, scratch.val);
|
|
|
|
let base = PointerCast(bcx,
|
|
|
|
base,
|
|
|
|
type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
|
|
|
|
bcx = lval.store_to(bcx, base);
|
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 07:20:11 -05:00
|
|
|
|
|
|
|
Store(bcx, ll_len, get_len(bcx, scratch.val));
|
|
|
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>,
|
|
|
|
k: &ty::UnsizeKind)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
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 07:20:11 -05:00
|
|
|
let mut bcx = bcx;
|
|
|
|
let tcx = bcx.tcx();
|
|
|
|
|
|
|
|
let datum_ty = datum.ty;
|
|
|
|
let unboxed_ty = match ty::get(datum_ty).sty {
|
|
|
|
ty::ty_uniq(t) => t,
|
|
|
|
_ => bcx.sess().bug(format!("Expected ty_uniq, found {}",
|
2014-08-06 04:59:40 -05:00
|
|
|
bcx.ty_to_string(datum_ty)).as_slice())
|
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 07:20:11 -05:00
|
|
|
};
|
|
|
|
let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span));
|
|
|
|
|
|
|
|
let lval = unpack_datum!(bcx,
|
|
|
|
datum.to_lvalue_datum(bcx, "unsize_unique_expr", expr.id));
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2014-08-06 04:59:40 -05:00
|
|
|
let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr");
|
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 07:20:11 -05:00
|
|
|
let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty);
|
|
|
|
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
|
|
|
|
bcx = lval.store_to(bcx, base);
|
2012-09-11 23:25:01 -05:00
|
|
|
|
2014-08-06 04:59:40 -05:00
|
|
|
let info = unsized_info(bcx, k, expr.id, unboxed_ty, |t| ty::mk_uniq(tcx, t));
|
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 07:20:11 -05:00
|
|
|
Store(bcx, info, get_len(bcx, scratch.val));
|
2012-09-11 23:25:01 -05:00
|
|
|
|
2014-08-06 04:59:40 -05:00
|
|
|
let scratch = unpack_datum!(bcx,
|
|
|
|
scratch.to_expr_datum().to_lvalue_datum(bcx,
|
|
|
|
"fresh_uniq_fat_ptr",
|
|
|
|
expr.id));
|
|
|
|
|
2014-05-28 14:36:05 -05:00
|
|
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
2012-09-11 23:25:01 -05:00
|
|
|
}
|
2012-12-06 18:29:17 -06:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn add_env<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2013-02-27 18:28:37 -06:00
|
|
|
// This is not the most efficient thing possible; since closures
|
|
|
|
// are two words it'd be better if this were compiled in
|
|
|
|
// 'dest' mode, but I can't find a nice way to structure the
|
|
|
|
// code and keep it DRY that accommodates that use case at the
|
|
|
|
// moment.
|
|
|
|
|
|
|
|
let closure_ty = expr_ty_adjusted(bcx, expr);
|
2014-01-27 06:18:36 -06:00
|
|
|
let fn_ptr = datum.to_llscalarish(bcx);
|
|
|
|
let def = ty::resolve_expr(bcx.tcx(), expr);
|
|
|
|
closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
|
2013-02-27 18:28:37 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
name: &str)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Lvalue> {
|
2013-01-10 12:59:58 -06:00
|
|
|
/*!
|
2014-01-15 13:39:08 -06:00
|
|
|
* Translates an expression in "lvalue" mode -- meaning that it
|
|
|
|
* returns a reference to the memory that the expr represents.
|
|
|
|
*
|
|
|
|
* If this expression is an rvalue, this implies introducing a
|
|
|
|
* temporary. In other words, something like `x().f` is
|
|
|
|
* translated into roughly the equivalent of
|
2013-01-10 12:59:58 -06:00
|
|
|
*
|
2014-01-15 13:39:08 -06:00
|
|
|
* { tmp = x(); tmp.f }
|
|
|
|
*/
|
2013-01-10 12:59:58 -06:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
|
|
|
let datum = unpack_datum!(bcx, trans(bcx, expr));
|
|
|
|
return datum.to_lvalue_datum(bcx, name, expr.id);
|
2012-09-11 23:25:01 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2012-08-28 17:54:45 -05:00
|
|
|
/*!
|
2014-01-15 13:39:08 -06:00
|
|
|
* A version of `trans` that ignores adjustments. You almost
|
|
|
|
* certainly do not want to call this directly.
|
2013-06-20 14:23:52 -05:00
|
|
|
*/
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let mut bcx = bcx;
|
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
debug!("trans_unadjusted(expr={})", bcx.expr_to_string(expr));
|
2012-08-28 17:54:45 -05:00
|
|
|
let _indenter = indenter();
|
|
|
|
|
2013-08-19 11:23:43 -05:00
|
|
|
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-04-09 10:18:40 -05:00
|
|
|
return match ty::expr_kind(bcx.tcx(), expr) {
|
2014-01-15 13:39:08 -06:00
|
|
|
ty::LvalueExpr | ty::RvalueDatumExpr => {
|
2012-09-11 23:25:01 -05:00
|
|
|
let datum = unpack_datum!(bcx, {
|
2014-01-15 13:39:08 -06:00
|
|
|
trans_datum_unadjusted(bcx, expr)
|
2012-09-11 23:25:01 -05:00
|
|
|
});
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
DatumBlock {bcx: bcx, datum: datum}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ty::RvalueStmtExpr => {
|
2012-09-11 23:25:01 -05:00
|
|
|
bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
|
2014-01-15 13:39:08 -06:00
|
|
|
nil(bcx, expr_ty(bcx, expr))
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ty::RvalueDpsExpr => {
|
|
|
|
let ty = expr_ty(bcx, expr);
|
2014-01-16 18:10:17 -06:00
|
|
|
if type_is_zero_size(bcx.ccx(), ty) {
|
2012-09-11 23:25:01 -05:00
|
|
|
bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
|
2014-01-15 13:39:08 -06:00
|
|
|
nil(bcx, ty)
|
2012-08-28 17:54:45 -05:00
|
|
|
} else {
|
2014-01-15 13:39:08 -06:00
|
|
|
let scratch = rvalue_scratch_datum(bcx, ty, "");
|
2012-09-11 23:25:01 -05:00
|
|
|
bcx = trans_rvalue_dps_unadjusted(
|
|
|
|
bcx, expr, SaveIn(scratch.val));
|
2012-09-06 17:21:42 -05:00
|
|
|
|
|
|
|
// Note: this is not obviously a good idea. It causes
|
|
|
|
// immediate values to be loaded immediately after a
|
|
|
|
// return from a call or other similar expression,
|
|
|
|
// which in turn leads to alloca's having shorter
|
|
|
|
// lifetimes and hence larger stack frames. However,
|
|
|
|
// in turn it can lead to more register pressure.
|
|
|
|
// Still, in practice it seems to increase
|
|
|
|
// performance, since we have fewer problems with
|
|
|
|
// morestack churn.
|
2014-01-15 13:39:08 -06:00
|
|
|
let scratch = unpack_datum!(
|
|
|
|
bcx, scratch.to_appropriate_datum(bcx));
|
2012-09-06 17:21:42 -05:00
|
|
|
|
2014-05-28 14:36:05 -05:00
|
|
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-09-13 13:09:25 -05:00
|
|
|
fn nil<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty: Ty)
|
2014-09-06 11:13:04 -05:00
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-16 14:11:22 -06:00
|
|
|
let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
|
|
|
|
let datum = immediate_rvalue(llval, ty);
|
2014-05-28 14:36:05 -05:00
|
|
|
DatumBlock::new(bcx, datum.to_expr_datum())
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
|
|
|
let fcx = bcx.fcx;
|
|
|
|
let _icx = push_ctxt("trans_datum_unadjusted");
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
match expr.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprParen(ref e) => {
|
|
|
|
trans(bcx, &**e)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2014-01-27 06:18:36 -06:00
|
|
|
ast::ExprPath(_) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
trans_def(bcx, expr, bcx.def(expr.id))
|
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprField(ref base, ident, _) => {
|
2014-06-13 16:56:42 -05:00
|
|
|
trans_rec_field(bcx, &**base, ident.node)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2014-08-09 22:54:33 -05:00
|
|
|
ast::ExprTupField(ref base, idx, _) => {
|
|
|
|
trans_rec_tup_field(bcx, &**base, idx.node)
|
|
|
|
}
|
2014-08-06 04:59:40 -05:00
|
|
|
ast::ExprIndex(ref base, ref idx) => {
|
|
|
|
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
|
2013-02-27 18:28:37 -06:00
|
|
|
}
|
2014-09-15 03:48:58 -05:00
|
|
|
ast::ExprSlice(ref base, ref start, ref end, _) => {
|
|
|
|
let _icx = push_ctxt("trans_slice");
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
|
|
|
let method_call = MethodCall::expr(expr.id);
|
|
|
|
let method_ty = ccx.tcx()
|
|
|
|
.method_map
|
|
|
|
.borrow()
|
2014-11-06 11:25:16 -06:00
|
|
|
.get(&method_call)
|
2014-09-15 03:48:58 -05:00
|
|
|
.map(|method| method.ty);
|
|
|
|
let base_datum = unpack_datum!(bcx, trans(bcx, &**base));
|
|
|
|
|
|
|
|
let mut args = vec![];
|
|
|
|
start.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
|
|
|
|
end.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
|
|
|
|
|
2014-10-24 14:14:37 -05:00
|
|
|
let result_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty.unwrap())).unwrap();
|
2014-09-15 03:48:58 -05:00
|
|
|
let scratch = rvalue_scratch_datum(bcx, result_ty, "trans_slice");
|
|
|
|
|
|
|
|
unpack_result!(bcx,
|
|
|
|
trans_overloaded_op(bcx,
|
|
|
|
expr,
|
|
|
|
method_call,
|
|
|
|
base_datum,
|
|
|
|
args,
|
|
|
|
Some(SaveIn(scratch.val))));
|
|
|
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
|
|
|
}
|
2014-05-15 20:18:00 -05:00
|
|
|
ast::ExprBox(_, ref contents) => {
|
2014-09-30 17:26:04 -05:00
|
|
|
// Special case for `Box<T>`
|
2013-12-17 18:46:18 -06:00
|
|
|
let box_ty = expr_ty(bcx, expr);
|
2014-05-15 20:18:00 -05:00
|
|
|
let contents_ty = expr_ty(bcx, &**contents);
|
|
|
|
match ty::get(box_ty).sty {
|
|
|
|
ty::ty_uniq(..) => {
|
2014-09-12 02:08:48 -05:00
|
|
|
trans_uniq_expr(bcx, box_ty, &**contents, contents_ty)
|
2014-05-15 20:18:00 -05:00
|
|
|
}
|
|
|
|
_ => bcx.sess().span_bug(expr.span,
|
2014-09-30 17:26:04 -05:00
|
|
|
"expected unique box")
|
2014-05-15 20:18:00 -05:00
|
|
|
}
|
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 07:20:11 -05:00
|
|
|
|
2013-12-17 18:46:18 -06:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, &**lit),
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprBinary(op, ref lhs, ref rhs) => {
|
|
|
|
trans_binary(bcx, expr, op, &**lhs, &**rhs)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprUnary(op, ref x) => {
|
|
|
|
trans_unary(bcx, expr, op, &**x)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprAddrOf(_, ref x) => {
|
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 07:20:11 -05:00
|
|
|
match x.node {
|
|
|
|
ast::ExprRepeat(..) | ast::ExprVec(..) => {
|
|
|
|
// Special case for slices.
|
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 01:49:38 -05:00
|
|
|
let cleanup_debug_loc =
|
|
|
|
debuginfo::get_cleanup_debug_loc_for_ast_node(x.id, x.span, false);
|
|
|
|
fcx.push_ast_cleanup_scope(cleanup_debug_loc);
|
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 07:20:11 -05:00
|
|
|
let datum = unpack_datum!(
|
|
|
|
bcx, tvec::trans_slice_vec(bcx, expr, &**x));
|
|
|
|
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id);
|
|
|
|
DatumBlock::new(bcx, datum)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
trans_addr_of(bcx, expr, &**x)
|
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprCast(ref val, _) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
// Datum output mode means this is a scalar cast:
|
2014-05-16 12:15:33 -05:00
|
|
|
trans_imm_cast(bcx, &**val, expr.id)
|
2012-10-27 19:14:09 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => {
|
|
|
|
bcx.tcx().sess.span_bug(
|
|
|
|
expr.span,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("trans_rvalue_datum_unadjusted reached \
|
2014-10-15 01:25:34 -05:00
|
|
|
fall-through case: {}",
|
2014-05-16 12:45:16 -05:00
|
|
|
expr.node).as_slice());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-09 22:54:33 -05:00
|
|
|
fn trans_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
base: &ast::Expr,
|
|
|
|
get_idx: |&'blk ty::ctxt<'tcx>, &[ty::field]| -> uint)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
|
|
|
let _icx = push_ctxt("trans_rec_field");
|
|
|
|
|
|
|
|
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
|
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 07:20:11 -05:00
|
|
|
let bare_ty = ty::unopen_type(base_datum.ty);
|
|
|
|
let repr = adt::represent_type(bcx.ccx(), bare_ty);
|
|
|
|
with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| {
|
2014-08-09 22:54:33 -05:00
|
|
|
let ix = get_idx(bcx.tcx(), field_tys);
|
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 07:20:11 -05:00
|
|
|
let d = base_datum.get_element(
|
|
|
|
bcx,
|
|
|
|
field_tys[ix].mt.ty,
|
|
|
|
|srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
|
|
|
|
|
|
|
|
if ty::type_is_sized(bcx.tcx(), d.ty) {
|
2014-01-15 13:39:08 -06:00
|
|
|
DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
|
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 07:20:11 -05:00
|
|
|
} else {
|
|
|
|
let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), "");
|
|
|
|
Store(bcx, d.val, get_dataptr(bcx, scratch.val));
|
|
|
|
let info = Load(bcx, get_len(bcx, base_datum.val));
|
|
|
|
Store(bcx, info, get_len(bcx, scratch.val));
|
|
|
|
|
|
|
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
|
|
|
|
|
|
|
}
|
|
|
|
})
|
2014-08-09 22:54:33 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Translates `base.field`.
|
|
|
|
fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
base: &ast::Expr,
|
|
|
|
field: ast::Ident)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
|
|
|
trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field.name, field_tys))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Translates `base.<idx>`.
|
|
|
|
fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
base: &ast::Expr,
|
|
|
|
idx: uint)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
|
|
|
trans_field(bcx, base, |_, _| idx)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
index_expr: &ast::Expr,
|
|
|
|
base: &ast::Expr,
|
|
|
|
idx: &ast::Expr,
|
|
|
|
method_call: MethodCall)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
//! Translates `base[idx]`.
|
|
|
|
|
|
|
|
let _icx = push_ctxt("trans_index");
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let mut bcx = bcx;
|
|
|
|
|
2014-07-03 16:32:41 -05:00
|
|
|
// Check for overloaded index.
|
2014-09-05 11:18:53 -05:00
|
|
|
let method_ty = ccx.tcx()
|
2014-07-03 16:32:41 -05:00
|
|
|
.method_map
|
|
|
|
.borrow()
|
2014-11-06 11:25:16 -06:00
|
|
|
.get(&method_call)
|
2014-07-03 16:32:41 -05:00
|
|
|
.map(|method| method.ty);
|
|
|
|
let elt_datum = match method_ty {
|
|
|
|
Some(method_ty) => {
|
|
|
|
let base_datum = unpack_datum!(bcx, trans(bcx, base));
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2014-07-03 16:32:41 -05:00
|
|
|
// Translate index expression.
|
|
|
|
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2014-10-24 14:14:37 -05:00
|
|
|
let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty)).unwrap();
|
2014-07-03 16:32:41 -05:00
|
|
|
let elt_ty = match ty::deref(ref_ty, true) {
|
|
|
|
None => {
|
|
|
|
bcx.tcx().sess.span_bug(index_expr.span,
|
|
|
|
"index method didn't return a \
|
|
|
|
dereferenceable type?!")
|
|
|
|
}
|
|
|
|
Some(elt_tm) => elt_tm.ty,
|
|
|
|
};
|
2014-11-01 01:31:16 -05:00
|
|
|
|
|
|
|
// Overloaded. Evaluate `trans_overloaded_op`, which will
|
|
|
|
// invoke the user's index() method, which basically yields
|
|
|
|
// a `&T` pointer. We can then proceed down the normal
|
|
|
|
// path (below) to dereference that `&T`.
|
|
|
|
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt");
|
|
|
|
unpack_result!(bcx,
|
|
|
|
trans_overloaded_op(bcx,
|
|
|
|
index_expr,
|
|
|
|
method_call,
|
|
|
|
base_datum,
|
|
|
|
vec![(ix_datum, idx.id)],
|
|
|
|
Some(SaveIn(scratch.val))));
|
|
|
|
let datum = scratch.to_expr_datum();
|
|
|
|
if ty::type_is_sized(bcx.tcx(), elt_ty) {
|
|
|
|
Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
|
|
|
|
} else {
|
|
|
|
Datum::new(datum.val, ty::mk_open(bcx.tcx(), elt_ty), LvalueExpr)
|
|
|
|
}
|
2014-07-03 16:32:41 -05:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx,
|
|
|
|
base,
|
|
|
|
"index"));
|
|
|
|
|
|
|
|
// Translate index expression and cast to a suitable LLVM integer.
|
|
|
|
// Rust is less strict than LLVM in this regard.
|
|
|
|
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
|
|
|
|
let ix_val = ix_datum.to_llscalarish(bcx);
|
|
|
|
let ix_size = machine::llbitsize_of_real(bcx.ccx(),
|
|
|
|
val_ty(ix_val));
|
|
|
|
let int_size = machine::llbitsize_of_real(bcx.ccx(),
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.int_type());
|
2014-07-03 16:32:41 -05:00
|
|
|
let ix_val = {
|
|
|
|
if ix_size < int_size {
|
|
|
|
if ty::type_is_signed(expr_ty(bcx, idx)) {
|
2014-09-05 11:18:53 -05:00
|
|
|
SExt(bcx, ix_val, ccx.int_type())
|
|
|
|
} else { ZExt(bcx, ix_val, ccx.int_type()) }
|
2014-07-03 16:32:41 -05:00
|
|
|
} else if ix_size > int_size {
|
2014-09-05 11:18:53 -05:00
|
|
|
Trunc(bcx, ix_val, ccx.int_type())
|
2014-07-03 16:32:41 -05:00
|
|
|
} else {
|
|
|
|
ix_val
|
|
|
|
}
|
|
|
|
};
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2014-07-03 16:32:41 -05:00
|
|
|
let vt =
|
|
|
|
tvec::vec_types(bcx,
|
|
|
|
ty::sequence_element_type(bcx.tcx(),
|
|
|
|
base_datum.ty));
|
|
|
|
base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
|
|
|
|
|
|
|
|
let (base, len) = base_datum.get_vec_base_and_len(bcx);
|
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
debug!("trans_index: base {}", bcx.val_to_string(base));
|
|
|
|
debug!("trans_index: len {}", bcx.val_to_string(len));
|
2014-07-03 16:32:41 -05:00
|
|
|
|
2014-07-07 19:58:01 -05:00
|
|
|
let bounds_check = ICmp(bcx, llvm::IntUGE, ix_val, len);
|
2014-07-03 16:32:41 -05:00
|
|
|
let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
|
|
|
|
let expected = Call(bcx,
|
|
|
|
expect,
|
2014-11-17 02:39:01 -06:00
|
|
|
&[bounds_check, C_bool(ccx, false)],
|
2014-07-25 18:06:44 -05:00
|
|
|
None);
|
2014-07-03 16:32:41 -05:00
|
|
|
bcx = with_cond(bcx, expected, |bcx| {
|
|
|
|
controlflow::trans_fail_bounds_check(bcx,
|
|
|
|
index_expr.span,
|
|
|
|
ix_val,
|
|
|
|
len)
|
|
|
|
});
|
2014-11-17 02:39:01 -06:00
|
|
|
let elt = InBoundsGEP(bcx, base, &[ix_val]);
|
2014-07-03 16:32:41 -05:00
|
|
|
let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
|
|
|
|
Datum::new(elt, vt.unit_ty, LvalueExpr)
|
|
|
|
}
|
|
|
|
};
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2014-07-03 16:32:41 -05:00
|
|
|
DatumBlock::new(bcx, elt_datum)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
ref_expr: &ast::Expr,
|
|
|
|
def: def::Def)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
//! Translates a reference to a path.
|
|
|
|
|
|
|
|
let _icx = push_ctxt("trans_def_lvalue");
|
|
|
|
match def {
|
2014-10-28 21:59:20 -05:00
|
|
|
def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) |
|
2014-05-14 14:31:30 -05:00
|
|
|
def::DefStruct(_) | def::DefVariant(..) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
trans_def_fn_unadjusted(bcx, ref_expr, def)
|
|
|
|
}
|
2014-05-14 14:31:30 -05:00
|
|
|
def::DefStatic(did, _) => {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
// There are two things that may happen here:
|
2014-07-21 18:42:34 -05:00
|
|
|
// 1) If the static item is defined in this crate, it will be
|
|
|
|
// translated using `get_item_val`, and we return a pointer to
|
|
|
|
// the result.
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
// 2) If the static item is defined in another crate then we add
|
|
|
|
// (or reuse) a declaration of an external global, and return a
|
|
|
|
// pointer to that.
|
2014-01-15 13:39:08 -06:00
|
|
|
let const_ty = expr_ty(bcx, ref_expr);
|
|
|
|
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
fn get_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: ast::DefId,
|
2014-09-13 13:09:25 -05:00
|
|
|
const_ty: Ty) -> ValueRef {
|
2014-01-15 13:39:08 -06:00
|
|
|
// For external constants, we don't inline.
|
2014-02-05 15:15:24 -06:00
|
|
|
if did.krate == ast::LOCAL_CRATE {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
// Case 1.
|
2014-07-21 18:42:34 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// The LLVM global has the type of its initializer,
|
|
|
|
// which may not be equal to the enum's type for
|
|
|
|
// non-C-like enums.
|
|
|
|
let val = base::get_item_val(bcx.ccx(), did.node);
|
|
|
|
let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
|
|
|
|
PointerCast(bcx, val, pty)
|
|
|
|
} else {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
// Case 2.
|
|
|
|
base::get_extern_const(bcx.ccx(), did, const_ty)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let val = get_val(bcx, did, const_ty);
|
2014-05-28 14:36:05 -05:00
|
|
|
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr))
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
def::DefConst(did) => {
|
|
|
|
// First, inline any external constants into the local crate so we
|
|
|
|
// can be sure to get the LLVM value corresponding to it.
|
|
|
|
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
|
|
|
|
if did.krate != ast::LOCAL_CRATE {
|
|
|
|
bcx.tcx().sess.span_bug(ref_expr.span,
|
|
|
|
"cross crate constant could not \
|
|
|
|
be inlined");
|
|
|
|
}
|
|
|
|
let val = base::get_item_val(bcx.ccx(), did.node);
|
|
|
|
|
|
|
|
// Next, we need to crate a ByRef rvalue datum to return. We can't
|
|
|
|
// use the normal .to_ref_datum() function because the type of
|
|
|
|
// `val` is not actually the same as `const_ty`.
|
|
|
|
//
|
|
|
|
// To get around this, we make a custom alloca slot with the
|
|
|
|
// appropriate type (const_ty), and then we cast it to a pointer of
|
|
|
|
// typeof(val), store the value, and then hand this slot over to
|
|
|
|
// the datum infrastructure.
|
|
|
|
let const_ty = expr_ty(bcx, ref_expr);
|
|
|
|
let llty = type_of::type_of(bcx.ccx(), const_ty);
|
|
|
|
let slot = alloca(bcx, llty, "const");
|
|
|
|
let pty = Type::from_ref(unsafe { llvm::LLVMTypeOf(val) }).ptr_to();
|
|
|
|
Store(bcx, val, PointerCast(bcx, slot, pty));
|
|
|
|
|
|
|
|
let datum = Datum::new(slot, const_ty, Rvalue::new(ByRef));
|
|
|
|
DatumBlock::new(bcx, datum.to_expr_datum())
|
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
_ => {
|
2014-05-28 14:36:05 -05:00
|
|
|
DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut bcx = bcx;
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_rvalue_stmt");
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-12-18 16:54:42 -06:00
|
|
|
if bcx.unreachable.get() {
|
2013-05-21 15:15:48 -05:00
|
|
|
return 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 01:49:38 -05:00
|
|
|
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
match expr.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprParen(ref e) => {
|
|
|
|
trans_into(bcx, &**e, Ignore)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprBreak(label_opt) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
controlflow::trans_break(bcx, expr.id, label_opt)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprAgain(label_opt) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
controlflow::trans_cont(bcx, expr.id, label_opt)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ExprRet(ref ex) => {
|
|
|
|
controlflow::trans_ret(bcx, ex.as_ref().map(|e| &**e))
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-07-25 19:12:51 -05:00
|
|
|
ast::ExprWhile(ref cond, ref body, _) => {
|
2014-05-16 12:15:33 -05:00
|
|
|
controlflow::trans_while(bcx, expr.id, &**cond, &**body)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-07-21 22:54:28 -05:00
|
|
|
ast::ExprForLoop(ref pat, ref head, ref body, _) => {
|
|
|
|
controlflow::trans_for(bcx,
|
|
|
|
expr_info(expr),
|
2014-09-07 12:09:06 -05:00
|
|
|
&**pat,
|
2014-07-21 22:54:28 -05:00
|
|
|
&**head,
|
|
|
|
&**body)
|
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprLoop(ref body, _) => {
|
|
|
|
controlflow::trans_loop(bcx, expr.id, &**body)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprAssign(ref dst, ref src) => {
|
2014-10-22 14:23:26 -05:00
|
|
|
let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
|
2014-05-16 12:15:33 -05:00
|
|
|
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
|
|
|
|
// If there are destructors involved, make sure we
|
|
|
|
// are copying from an rvalue, since that cannot possible
|
|
|
|
// alias an lvalue. We are concerned about code like:
|
|
|
|
//
|
|
|
|
// a = a
|
|
|
|
//
|
|
|
|
// but also
|
|
|
|
//
|
|
|
|
// a = a.b
|
|
|
|
//
|
|
|
|
// where e.g. a : Option<Foo> and a.b :
|
|
|
|
// Option<Foo>. In that case, freeing `a` before the
|
|
|
|
// assignment may also free `a.b`!
|
|
|
|
//
|
|
|
|
// We could avoid this intermediary with some analysis
|
|
|
|
// to determine whether `dst` may possibly own `src`.
|
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 01:49:38 -05:00
|
|
|
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
|
2014-01-15 13:39:08 -06:00
|
|
|
let src_datum = unpack_datum!(
|
|
|
|
bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
|
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 01:49:38 -05:00
|
|
|
bcx = glue::drop_ty(bcx,
|
|
|
|
dst_datum.val,
|
|
|
|
dst_datum.ty,
|
|
|
|
Some(NodeInfo { id: expr.id, span: expr.span }));
|
2014-01-15 13:39:08 -06:00
|
|
|
src_datum.store_to(bcx, dst_datum.val)
|
|
|
|
} else {
|
2014-10-22 14:23:26 -05:00
|
|
|
src_datum.store_to(bcx, dst_datum.val)
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprAssignOp(op, ref dst, ref src) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
trans_assign_op(bcx, expr, op, &**dst, &**src)
|
2012-10-27 19:14:09 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprInlineAsm(ref a) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
asm::trans_inline_asm(bcx, a)
|
2013-03-12 19:53:25 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => {
|
|
|
|
bcx.tcx().sess.span_bug(
|
|
|
|
expr.span,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("trans_rvalue_stmt_unadjusted reached \
|
2014-10-15 01:25:34 -05:00
|
|
|
fall-through case: {}",
|
2014-05-16 12:45:16 -05:00
|
|
|
expr.node).as_slice());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
dest: Dest)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
let tcx = bcx.tcx();
|
|
|
|
|
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 01:49:38 -05:00
|
|
|
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
match expr.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprParen(ref e) => {
|
|
|
|
trans_into(bcx, &**e, dest)
|
2012-10-27 19:14:09 -05:00
|
|
|
}
|
2014-01-27 06:18:36 -06:00
|
|
|
ast::ExprPath(_) => {
|
|
|
|
trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ExprIf(ref cond, ref thn, ref els) => {
|
|
|
|
controlflow::trans_if(bcx, expr.id, &**cond, &**thn, els.as_ref().map(|e| &**e), dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-08-25 16:55:00 -05:00
|
|
|
ast::ExprMatch(ref discr, ref arms, _) => {
|
2014-05-16 12:15:33 -05:00
|
|
|
_match::trans_match(bcx, expr, &**discr, arms.as_slice(), dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprBlock(ref blk) => {
|
|
|
|
controlflow::trans_block(bcx, &**blk, dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ExprStruct(_, ref fields, ref base) => {
|
2014-08-14 21:16:35 -05:00
|
|
|
trans_struct(bcx,
|
|
|
|
fields.as_slice(),
|
2014-09-07 12:09:06 -05:00
|
|
|
base.as_ref().map(|e| &**e),
|
2014-08-14 21:16:35 -05:00
|
|
|
expr.span,
|
|
|
|
expr.id,
|
|
|
|
dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprTup(ref args) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
let numbered_fields: Vec<(uint, &ast::Expr)> =
|
|
|
|
args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
|
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 01:49:38 -05:00
|
|
|
trans_adt(bcx,
|
|
|
|
expr_ty(bcx, expr),
|
|
|
|
0,
|
|
|
|
numbered_fields.as_slice(),
|
|
|
|
None,
|
|
|
|
dest,
|
|
|
|
Some(NodeInfo { id: expr.id, span: expr.span }))
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ExprLit(ref lit) => {
|
2014-01-03 17:08:48 -06:00
|
|
|
match lit.node {
|
2014-01-10 16:02:36 -06:00
|
|
|
ast::LitStr(ref s, _) => {
|
|
|
|
tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
|
2014-01-03 17:08:48 -06:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
bcx.tcx()
|
|
|
|
.sess
|
|
|
|
.span_bug(expr.span,
|
|
|
|
"trans_rvalue_dps_unadjusted shouldn't be \
|
|
|
|
translating this type of literal")
|
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-11-28 14:22:53 -06:00
|
|
|
ast::ExprVec(..) | ast::ExprRepeat(..) => {
|
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 07:20:11 -05:00
|
|
|
tvec::trans_fixed_vstore(bcx, expr, dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-07-23 14:43:29 -05:00
|
|
|
ast::ExprFnBlock(_, ref decl, ref body) |
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprProc(ref decl, ref body) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
let expr_ty = expr_ty(bcx, expr);
|
2014-04-11 10:03:10 -05:00
|
|
|
let store = ty::ty_closure_store(expr_ty);
|
2013-10-28 17:22:49 -05:00
|
|
|
debug!("translating block function {} with type {}",
|
2014-06-21 05:39:03 -05:00
|
|
|
expr_to_string(expr), expr_ty.repr(tcx));
|
2014-05-16 12:15:33 -05:00
|
|
|
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ExprUnboxedFn(_, _, ref decl, ref body) => {
|
|
|
|
closure::trans_unboxed_closure(bcx, &**decl, &**body, expr.id, dest)
|
2014-05-29 00:26:56 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprCall(ref f, ref args) => {
|
2014-06-01 18:35:01 -05:00
|
|
|
if bcx.tcx().is_method_call(expr.id) {
|
|
|
|
trans_overloaded_call(bcx,
|
|
|
|
expr,
|
2014-09-07 12:09:06 -05:00
|
|
|
&**f,
|
2014-06-01 18:35:01 -05:00
|
|
|
args.as_slice(),
|
|
|
|
Some(dest))
|
|
|
|
} else {
|
|
|
|
callee::trans_call(bcx,
|
|
|
|
expr,
|
2014-05-16 12:15:33 -05:00
|
|
|
&**f,
|
2014-06-01 18:35:01 -05:00
|
|
|
callee::ArgExprs(args.as_slice()),
|
|
|
|
dest)
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-02-26 08:06:45 -06:00
|
|
|
ast::ExprMethodCall(_, _, ref args) => {
|
2014-02-28 17:25:15 -06:00
|
|
|
callee::trans_method_call(bcx,
|
|
|
|
expr,
|
2014-10-15 01:05:01 -05:00
|
|
|
&*args[0],
|
2014-02-28 17:25:15 -06:00
|
|
|
callee::ArgExprs(args.as_slice()),
|
|
|
|
dest)
|
2012-11-30 13:18:25 -06:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprBinary(_, ref lhs, ref rhs) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
// if not overloaded, would be RvalueDatumExpr
|
2014-05-16 12:15:33 -05:00
|
|
|
let lhs = unpack_datum!(bcx, trans(bcx, &**lhs));
|
|
|
|
let rhs_datum = unpack_datum!(bcx, trans(bcx, &**rhs));
|
2014-03-06 11:24:11 -06:00
|
|
|
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
|
2014-09-15 03:48:58 -05:00
|
|
|
vec![(rhs_datum, rhs.id)], Some(dest)).bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprUnary(_, ref subexpr) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
// if not overloaded, would be RvalueDatumExpr
|
2014-05-16 12:15:33 -05:00
|
|
|
let arg = unpack_datum!(bcx, trans(bcx, &**subexpr));
|
2014-03-06 11:24:11 -06:00
|
|
|
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
|
2014-09-15 03:48:58 -05:00
|
|
|
arg, Vec::new(), Some(dest)).bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprIndex(ref base, ref idx) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
// if not overloaded, would be RvalueDatumExpr
|
2014-05-16 12:15:33 -05:00
|
|
|
let base = unpack_datum!(bcx, trans(bcx, &**base));
|
|
|
|
let idx_datum = unpack_datum!(bcx, trans(bcx, &**idx));
|
2014-03-06 11:24:11 -06:00
|
|
|
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
|
2014-09-15 03:48:58 -05:00
|
|
|
vec![(idx_datum, idx.id)], Some(dest)).bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprCast(ref val, _) => {
|
2014-01-15 13:39:08 -06:00
|
|
|
// DPS output mode means this is a trait cast:
|
2014-06-11 00:18:57 -05:00
|
|
|
if ty::type_is_trait(node_id_type(bcx, expr.id)) {
|
2014-09-12 10:42:58 -05:00
|
|
|
let trait_ref =
|
|
|
|
bcx.tcx().object_cast_map.borrow()
|
2014-11-06 11:25:16 -06:00
|
|
|
.get(&expr.id)
|
2014-09-12 10:42:58 -05:00
|
|
|
.map(|t| (*t).clone())
|
|
|
|
.unwrap();
|
|
|
|
let trait_ref =
|
2014-11-15 15:50:34 -06:00
|
|
|
trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs.substs());
|
2014-06-11 00:18:57 -05:00
|
|
|
let datum = unpack_datum!(bcx, trans(bcx, &**val));
|
2014-09-12 10:42:58 -05:00
|
|
|
meth::trans_trait_cast(bcx, datum, expr.id,
|
|
|
|
trait_ref, dest)
|
2014-06-11 00:18:57 -05:00
|
|
|
} else {
|
|
|
|
bcx.tcx().sess.span_bug(expr.span,
|
|
|
|
"expr_cast of non-trait");
|
2012-10-31 17:09:26 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprAssignOp(op, ref dst, ref src) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
trans_assign_op(bcx, expr, op, &**dst, &**src)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
bcx.tcx().sess.span_bug(
|
|
|
|
expr.span,
|
2014-05-16 12:45:16 -05:00
|
|
|
format!("trans_rvalue_dps_unadjusted reached fall-through \
|
2014-10-15 01:25:34 -05:00
|
|
|
case: {}",
|
2014-05-16 12:45:16 -05:00
|
|
|
expr.node).as_slice());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
ref_expr: &ast::Expr,
|
|
|
|
def: def::Def,
|
|
|
|
dest: Dest)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_def_dps_unadjusted");
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let lldest = match dest {
|
|
|
|
SaveIn(lldest) => lldest,
|
|
|
|
Ignore => { return bcx; }
|
|
|
|
};
|
|
|
|
|
|
|
|
match def {
|
2014-05-14 14:31:30 -05:00
|
|
|
def::DefVariant(tid, vid, _) => {
|
2014-03-15 15:29:34 -05:00
|
|
|
let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
|
2013-02-06 17:08:33 -06:00
|
|
|
if variant_info.args.len() > 0u {
|
2012-08-28 17:54:45 -05:00
|
|
|
// N-ary variant.
|
2014-03-06 11:24:11 -06:00
|
|
|
let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id));
|
2014-01-27 06:18:36 -06:00
|
|
|
Store(bcx, llfn, lldest);
|
2013-02-27 18:28:37 -06:00
|
|
|
return bcx;
|
2013-01-07 05:42:49 -06:00
|
|
|
} else {
|
2013-02-24 13:08:30 -06:00
|
|
|
// Nullary variant.
|
|
|
|
let ty = expr_ty(bcx, ref_expr);
|
2014-03-15 15:29:34 -05:00
|
|
|
let repr = adt::represent_type(bcx.ccx(), ty);
|
2014-07-10 17:09:21 -05:00
|
|
|
adt::trans_set_discr(bcx, &*repr, lldest,
|
|
|
|
variant_info.disr_val);
|
2013-01-07 05:42:49 -06:00
|
|
|
return bcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
2014-05-14 14:31:30 -05:00
|
|
|
def::DefStruct(_) => {
|
2013-06-01 16:39:39 -05:00
|
|
|
let ty = expr_ty(bcx, ref_expr);
|
|
|
|
match ty::get(ty).sty {
|
2014-03-15 15:29:34 -05:00
|
|
|
ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
|
|
|
|
let repr = adt::represent_type(bcx.ccx(), ty);
|
2014-07-10 17:09:21 -05:00
|
|
|
adt::trans_set_discr(bcx, &*repr, lldest, 0);
|
2013-06-01 16:39:39 -05:00
|
|
|
}
|
2014-01-27 06:18:36 -06:00
|
|
|
_ => {}
|
2013-06-01 16:39:39 -05:00
|
|
|
}
|
2014-01-27 06:18:36 -06:00
|
|
|
bcx
|
2012-10-30 17:53:06 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => {
|
2013-09-28 00:38:08 -05:00
|
|
|
bcx.tcx().sess.span_bug(ref_expr.span, format!(
|
2014-10-15 01:25:34 -05:00
|
|
|
"Non-DPS def {} referened by {}",
|
2014-06-21 05:39:03 -05:00
|
|
|
def, bcx.node_id_to_string(ref_expr.id)).as_slice());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_def_fn_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
ref_expr: &ast::Expr,
|
|
|
|
def: def::Def)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_def_datum_unadjusted");
|
2013-02-27 18:28:37 -06:00
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
let llfn = match def {
|
2014-10-15 23:44:24 -05:00
|
|
|
def::DefFn(did, _) |
|
2014-05-14 14:31:30 -05:00
|
|
|
def::DefStruct(did) | def::DefVariant(_, did, _) |
|
2014-10-15 23:44:24 -05:00
|
|
|
def::DefStaticMethod(did, def::FromImpl(_)) |
|
2014-10-28 21:59:20 -05:00
|
|
|
def::DefMethod(did, _, def::FromImpl(_)) => {
|
2014-03-06 11:24:11 -06:00
|
|
|
callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id))
|
2013-02-27 18:28:37 -06:00
|
|
|
}
|
2014-10-15 23:44:24 -05:00
|
|
|
def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) |
|
2014-10-28 21:59:20 -05:00
|
|
|
def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
meth::trans_static_method_callee(bcx, impl_did,
|
|
|
|
trait_did, ref_expr.id)
|
2013-02-27 18:28:37 -06:00
|
|
|
}
|
|
|
|
_ => {
|
2013-09-28 00:38:08 -05:00
|
|
|
bcx.tcx().sess.span_bug(ref_expr.span, format!(
|
2014-10-15 01:25:34 -05:00
|
|
|
"trans_def_fn_unadjusted invoked on: {} for {}",
|
2014-01-15 13:39:08 -06:00
|
|
|
def,
|
2014-05-16 12:45:16 -05:00
|
|
|
ref_expr.repr(bcx.tcx())).as_slice());
|
2013-02-27 18:28:37 -06:00
|
|
|
}
|
2013-08-21 08:27:48 -05:00
|
|
|
};
|
2013-02-27 18:28:37 -06:00
|
|
|
|
2013-08-21 08:27:48 -05:00
|
|
|
let fn_ty = expr_ty(bcx, ref_expr);
|
2014-05-28 14:36:05 -05:00
|
|
|
DatumBlock::new(bcx, Datum::new(llfn, fn_ty, RvalueExpr(Rvalue::new(ByValue))))
|
2013-02-27 18:28:37 -06:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
def: def::Def)
|
|
|
|
-> Datum<Lvalue> {
|
2012-09-11 23:25:01 -05:00
|
|
|
/*!
|
2014-01-15 13:39:08 -06:00
|
|
|
* Translates a reference to a local variable or argument.
|
|
|
|
* This always results in an lvalue datum.
|
|
|
|
*/
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_local_var");
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-09-17 09:28:19 -05:00
|
|
|
match def {
|
2014-09-14 17:22:50 -05:00
|
|
|
def::DefUpvar(nid, _, _) => {
|
2013-01-10 12:59:58 -06:00
|
|
|
// Can't move upvars, so this is never a ZeroMemLastUse.
|
2012-08-28 17:54:45 -05:00
|
|
|
let local_ty = node_id_type(bcx, nid);
|
2014-11-06 11:25:16 -06:00
|
|
|
match bcx.fcx.llupvars.borrow().get(&nid) {
|
2014-05-28 14:36:05 -05:00
|
|
|
Some(&val) => Datum::new(val, local_ty, Lvalue),
|
2012-08-28 17:54:45 -05:00
|
|
|
None => {
|
2013-09-28 00:38:08 -05:00
|
|
|
bcx.sess().bug(format!(
|
2014-10-15 01:25:34 -05:00
|
|
|
"trans_local_var: no llval for upvar {} found",
|
2014-05-16 12:45:16 -05:00
|
|
|
nid).as_slice());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-17 10:17:09 -05:00
|
|
|
def::DefLocal(nid) => {
|
2014-11-06 11:25:16 -06:00
|
|
|
let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
|
2014-09-17 09:28:19 -05:00
|
|
|
Some(&v) => v,
|
|
|
|
None => {
|
|
|
|
bcx.sess().bug(format!(
|
2014-10-15 01:25:34 -05:00
|
|
|
"trans_local_var: no datum for local/arg {} found",
|
2014-09-17 09:28:19 -05:00
|
|
|
nid).as_slice());
|
|
|
|
}
|
|
|
|
};
|
2014-10-15 01:25:34 -05:00
|
|
|
debug!("take_local(nid={}, v={}, ty={})",
|
2014-09-17 09:28:19 -05:00
|
|
|
nid, bcx.val_to_string(datum.val), bcx.ty_to_string(datum.ty));
|
|
|
|
datum
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
_ => {
|
2013-09-28 00:38:08 -05:00
|
|
|
bcx.sess().unimpl(format!(
|
2014-10-15 01:25:34 -05:00
|
|
|
"unsupported def type in trans_local_var: {}",
|
2014-05-16 12:45:16 -05:00
|
|
|
def).as_slice());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-05 21:07:47 -06:00
|
|
|
pub fn with_field_tys<R>(tcx: &ty::ctxt,
|
2014-09-13 13:09:25 -05:00
|
|
|
ty: Ty,
|
2014-01-15 13:39:08 -06:00
|
|
|
node_id_opt: Option<ast::NodeId>,
|
|
|
|
op: |ty::Disr, (&[ty::field])| -> R)
|
|
|
|
-> R {
|
|
|
|
/*!
|
|
|
|
* Helper for enumerating the field types of structs, enums, or records.
|
|
|
|
* The optional node ID here is the node ID of the path identifying the enum
|
|
|
|
* variant in use. If none, this cannot possibly an enum variant (so, if it
|
2014-10-09 14:17:22 -05:00
|
|
|
* is and `node_id_opt` is none, this function panics).
|
2014-01-15 13:39:08 -06:00
|
|
|
*/
|
|
|
|
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(ty).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty::ty_struct(did, ref substs) => {
|
2014-03-08 14:36:22 -06:00
|
|
|
op(0, struct_fields(tcx, did, substs).as_slice())
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-08-09 22:54:33 -05:00
|
|
|
ty::ty_tup(ref v) => {
|
|
|
|
op(0, tup_fields(v.as_slice()).as_slice())
|
|
|
|
}
|
|
|
|
|
2012-10-23 17:56:40 -05:00
|
|
|
ty::ty_enum(_, ref substs) => {
|
|
|
|
// We want the *variant* ID here, not the enum ID.
|
|
|
|
match node_id_opt {
|
|
|
|
None => {
|
2013-09-28 00:38:08 -05:00
|
|
|
tcx.sess.bug(format!(
|
|
|
|
"cannot get field types from the enum type {} \
|
2012-10-23 17:56:40 -05:00
|
|
|
without a node ID",
|
2014-05-16 12:45:16 -05:00
|
|
|
ty.repr(tcx)).as_slice());
|
2012-10-23 17:56:40 -05:00
|
|
|
}
|
|
|
|
Some(node_id) => {
|
2014-11-07 13:35:18 -06:00
|
|
|
let def = tcx.def_map.borrow()[node_id].clone();
|
2014-03-20 21:49:20 -05:00
|
|
|
match def {
|
2014-05-14 14:31:30 -05:00
|
|
|
def::DefVariant(enum_id, variant_id, _) => {
|
2013-02-24 00:53:40 -06:00
|
|
|
let variant_info = ty::enum_variant_with_id(
|
|
|
|
tcx, enum_id, variant_id);
|
2013-05-03 20:51:58 -05:00
|
|
|
op(variant_info.disr_val,
|
2014-03-08 14:36:22 -06:00
|
|
|
struct_fields(tcx,
|
|
|
|
variant_id,
|
|
|
|
substs).as_slice())
|
2012-10-23 17:56:40 -05:00
|
|
|
}
|
|
|
|
_ => {
|
2013-05-19 00:07:44 -05:00
|
|
|
tcx.sess.bug("resolve didn't map this expr to a \
|
|
|
|
variant ID")
|
2012-10-23 17:56:40 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => {
|
2013-09-28 00:38:08 -05:00
|
|
|
tcx.sess.bug(format!(
|
|
|
|
"cannot get field types from the type {}",
|
2014-05-16 12:45:16 -05:00
|
|
|
ty.repr(tcx)).as_slice());
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
fields: &[ast::Field],
|
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 01:49:38 -05:00
|
|
|
base: Option<&ast::Expr>,
|
2014-09-06 11:13:04 -05:00
|
|
|
expr_span: codemap::Span,
|
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 01:49:38 -05:00
|
|
|
expr_id: ast::NodeId,
|
2014-09-06 11:13:04 -05:00
|
|
|
dest: Dest) -> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_rec");
|
2012-08-28 17:54:45 -05: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 01:49:38 -05:00
|
|
|
let ty = node_id_type(bcx, expr_id);
|
2012-08-28 17:54:45 -05:00
|
|
|
let tcx = bcx.tcx();
|
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 01:49:38 -05:00
|
|
|
with_field_tys(tcx, ty, Some(expr_id), |discr, field_tys| {
|
2014-04-17 17:59:07 -05:00
|
|
|
let mut need_base = Vec::from_elem(field_tys.len(), true);
|
2013-02-24 00:53:40 -06:00
|
|
|
|
2014-03-28 14:42:34 -05:00
|
|
|
let numbered_fields = fields.iter().map(|field| {
|
2013-07-12 00:58:14 -05:00
|
|
|
let opt_pos =
|
|
|
|
field_tys.iter().position(|field_ty|
|
2014-09-30 19:11:34 -05:00
|
|
|
field_ty.name == field.ident.node.name);
|
2013-03-02 16:03:41 -06:00
|
|
|
match opt_pos {
|
2013-02-24 00:53:40 -06:00
|
|
|
Some(i) => {
|
2014-10-23 10:42:21 -05:00
|
|
|
need_base[i] = false;
|
2014-09-07 12:09:06 -05:00
|
|
|
(i, &*field.expr)
|
2012-10-23 17:56:40 -05:00
|
|
|
}
|
2013-02-24 00:53:40 -06:00
|
|
|
None => {
|
|
|
|
tcx.sess.span_bug(field.span,
|
2013-05-02 11:28:53 -05:00
|
|
|
"Couldn't find field in struct type")
|
2012-10-23 17:56:40 -05:00
|
|
|
}
|
|
|
|
}
|
2014-03-28 14:42:34 -05:00
|
|
|
}).collect::<Vec<_>>();
|
2013-02-24 00:53:40 -06:00
|
|
|
let optbase = match base {
|
|
|
|
Some(base_expr) => {
|
2014-03-04 12:02:49 -06:00
|
|
|
let mut leftovers = Vec::new();
|
2013-08-03 11:45:23 -05:00
|
|
|
for (i, b) in need_base.iter().enumerate() {
|
2013-02-24 00:53:40 -06:00
|
|
|
if *b {
|
|
|
|
leftovers.push((i, field_tys[i].mt.ty))
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-02-24 00:53:40 -06:00
|
|
|
Some(StructBaseInfo {expr: base_expr,
|
|
|
|
fields: leftovers })
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-02-24 00:53:40 -06:00
|
|
|
None => {
|
2013-07-04 21:13:26 -05:00
|
|
|
if need_base.iter().any(|b| *b) {
|
2013-05-19 00:07:44 -05:00
|
|
|
tcx.sess.span_bug(expr_span, "missing fields and no base expr")
|
2013-02-24 00:53:40 -06:00
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
2012-08-28 17:54:45 -05: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 01:49:38 -05:00
|
|
|
trans_adt(bcx,
|
|
|
|
ty,
|
|
|
|
discr,
|
|
|
|
numbered_fields.as_slice(),
|
|
|
|
optbase,
|
|
|
|
dest,
|
|
|
|
Some(NodeInfo { id: expr_id, span: expr_span }))
|
2013-11-21 17:42:55 -06:00
|
|
|
})
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-03-02 16:03:41 -06:00
|
|
|
/**
|
|
|
|
* Information that `trans_adt` needs in order to fill in the fields
|
|
|
|
* of a struct copied from a base struct (e.g., from an expression
|
|
|
|
* like `Foo { a: b, ..base }`.
|
|
|
|
*
|
|
|
|
* Note that `fields` may be empty; the base expression must always be
|
|
|
|
* evaluated for side-effects.
|
|
|
|
*/
|
2014-09-07 12:09:06 -05:00
|
|
|
pub struct StructBaseInfo<'a> {
|
2013-03-02 16:03:41 -06:00
|
|
|
/// The base expression; will be evaluated after all explicit fields.
|
2014-09-07 12:09:06 -05:00
|
|
|
expr: &'a ast::Expr,
|
2013-03-02 16:03:41 -06:00
|
|
|
/// The indices of fields to copy paired with their types.
|
2014-09-13 13:09:25 -05:00
|
|
|
fields: Vec<(uint, Ty)>
|
2014-09-07 12:09:06 -05:00
|
|
|
}
|
2013-02-24 00:53:40 -06:00
|
|
|
|
2013-03-02 16:03:41 -06:00
|
|
|
/**
|
|
|
|
* Constructs an ADT instance:
|
|
|
|
*
|
|
|
|
* - `fields` should be a list of field indices paired with the
|
|
|
|
* expression to store into that field. The initializers will be
|
|
|
|
* evaluated in the order specified by `fields`.
|
|
|
|
*
|
|
|
|
* - `optbase` contains information on the base struct (if any) from
|
|
|
|
* which remaining fields are copied; see comments on `StructBaseInfo`.
|
|
|
|
*/
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_adt<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
2014-09-13 13:09:25 -05:00
|
|
|
ty: Ty,
|
2014-09-06 11:13:04 -05:00
|
|
|
discr: ty::Disr,
|
2014-09-07 12:09:06 -05:00
|
|
|
fields: &[(uint, &ast::Expr)],
|
2014-09-06 11:13:04 -05:00
|
|
|
optbase: Option<StructBaseInfo>,
|
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 01:49:38 -05:00
|
|
|
dest: Dest,
|
|
|
|
source_location: Option<NodeInfo>)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_adt");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
2014-08-14 21:45:57 -05:00
|
|
|
let repr = adt::represent_type(bcx.ccx(), ty);
|
|
|
|
|
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 01:49:38 -05:00
|
|
|
match source_location {
|
|
|
|
Some(src_loc) => debuginfo::set_source_location(bcx.fcx,
|
|
|
|
src_loc.id,
|
|
|
|
src_loc.span),
|
|
|
|
None => {}
|
|
|
|
};
|
|
|
|
|
2014-08-14 21:45:57 -05:00
|
|
|
// If we don't care about the result, just make a
|
|
|
|
// temporary stack slot
|
2012-08-28 17:54:45 -05:00
|
|
|
let addr = match dest {
|
2014-08-14 21:45:57 -05:00
|
|
|
SaveIn(pos) => pos,
|
|
|
|
Ignore => alloc_ty(bcx, ty, "temp"),
|
2012-08-28 17:54:45 -05:00
|
|
|
};
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
// This scope holds intermediates that must be cleaned should
|
2014-10-09 14:17:22 -05:00
|
|
|
// panic occur before the ADT as a whole is ready.
|
2014-01-15 13:39:08 -06:00
|
|
|
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
|
|
|
|
|
2014-08-14 21:16:35 -05:00
|
|
|
// First we trans the base, if we have one, to the dest
|
|
|
|
for base in optbase.iter() {
|
|
|
|
assert_eq!(discr, 0);
|
|
|
|
|
|
|
|
match ty::expr_kind(bcx.tcx(), &*base.expr) {
|
2014-09-16 13:11:16 -05:00
|
|
|
ty::RvalueDpsExpr | ty::RvalueDatumExpr if !ty::type_needs_drop(bcx.tcx(), ty) => {
|
|
|
|
bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
|
|
|
|
},
|
|
|
|
ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr"),
|
|
|
|
_ => {
|
2014-08-14 21:16:35 -05:00
|
|
|
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
|
|
|
|
for &(i, t) in base.fields.iter() {
|
|
|
|
let datum = base_datum.get_element(
|
2014-08-06 04:59:40 -05:00
|
|
|
bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
|
|
|
|
assert!(ty::type_is_sized(bcx.tcx(), datum.ty));
|
2014-08-14 21:45:57 -05:00
|
|
|
let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
|
2014-08-14 21:16:35 -05:00
|
|
|
bcx = datum.store_to(bcx, dest);
|
|
|
|
}
|
2014-09-16 13:11:16 -05:00
|
|
|
}
|
2014-08-14 21:16:35 -05: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 01:49:38 -05:00
|
|
|
match source_location {
|
|
|
|
Some(src_loc) => debuginfo::set_source_location(bcx.fcx,
|
|
|
|
src_loc.id,
|
|
|
|
src_loc.span),
|
|
|
|
None => {}
|
|
|
|
};
|
|
|
|
|
Translate SIMD construction as `insertelement`s and a single store.
This almost completely avoids GEPi's and pointer manipulation,
postponing it until the end with one big write of the whole vector. This
leads to a small speed-up in compilation, and makes it easier for LLVM
to work with the values, e.g. with `--opt-level=0`,
pub fn foo() -> f32x4 {
f32x4(0.,0.,0.,0.)
}
was previously compiled to
define <4 x float> @_ZN3foo20h74913e8b13d89666eaaE() unnamed_addr #0 {
entry-block:
%sret_slot = alloca <4 x float>
%0 = getelementptr inbounds <4 x float>* %sret_slot, i32 0, i32 0
store float 0.000000e+00, float* %0
%1 = getelementptr inbounds <4 x float>* %sret_slot, i32 0, i32 1
store float 0.000000e+00, float* %1
%2 = getelementptr inbounds <4 x float>* %sret_slot, i32 0, i32 2
store float 0.000000e+00, float* %2
%3 = getelementptr inbounds <4 x float>* %sret_slot, i32 0, i32 3
store float 0.000000e+00, float* %3
%4 = load <4 x float>* %sret_slot
ret <4 x float> %4
}
but now becomes
define <4 x float> @_ZN3foo20h74913e8b13d89666eaaE() unnamed_addr #0 {
entry-block:
ret <4 x float> zeroinitializer
}
2014-11-04 03:59:00 -06:00
|
|
|
if ty::type_is_simd(bcx.tcx(), ty) {
|
|
|
|
// This is the constructor of a SIMD type, such types are
|
|
|
|
// always primitive machine types and so do not have a
|
|
|
|
// destructor or require any clean-up.
|
|
|
|
let llty = type_of::type_of(bcx.ccx(), ty);
|
|
|
|
|
|
|
|
// keep a vector as a register, and running through the field
|
|
|
|
// `insertelement`ing them directly into that register
|
|
|
|
// (i.e. avoid GEPi and `store`s to an alloca) .
|
|
|
|
let mut vec_val = C_undef(llty);
|
|
|
|
|
|
|
|
for &(i, ref e) in fields.iter() {
|
|
|
|
let block_datum = trans(bcx, &**e);
|
|
|
|
bcx = block_datum.bcx;
|
|
|
|
let position = C_uint(bcx.ccx(), i);
|
|
|
|
let value = block_datum.datum.to_llscalarish(bcx);
|
|
|
|
vec_val = InsertElement(bcx, vec_val, value, position);
|
|
|
|
}
|
|
|
|
Store(bcx, vec_val, addr);
|
|
|
|
} else {
|
|
|
|
// Now, we just overwrite the fields we've explicitly specified
|
|
|
|
for &(i, ref e) in fields.iter() {
|
|
|
|
let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
|
|
|
|
let e_ty = expr_ty_adjusted(bcx, &**e);
|
|
|
|
bcx = trans_into(bcx, &**e, SaveIn(dest));
|
|
|
|
let scope = cleanup::CustomScope(custom_cleanup_scope);
|
|
|
|
fcx.schedule_lifetime_end(scope, dest);
|
|
|
|
fcx.schedule_drop_mem(scope, dest, e_ty);
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2014-08-14 21:45:57 -05:00
|
|
|
adt::trans_set_discr(bcx, &*repr, addr, discr);
|
2014-07-10 17:09:21 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
|
|
|
|
|
2014-08-14 21:45:57 -05:00
|
|
|
// If we don't care about the result drop the temporary we made
|
|
|
|
match dest {
|
|
|
|
SaveIn(_) => bcx,
|
|
|
|
Ignore => {
|
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 01:49:38 -05:00
|
|
|
bcx = glue::drop_ty(bcx, addr, ty, source_location);
|
2014-08-14 21:45:57 -05:00
|
|
|
base::call_lifetime_end(bcx, addr);
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-02-24 00:53:40 -06:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
2014-09-07 12:09:06 -05:00
|
|
|
lit: &ast::Lit)
|
2014-09-06 11:13:04 -05:00
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2012-08-28 17:54:45 -05:00
|
|
|
// must not be a string constant, that is a RvalueDpsExpr
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_immediate_lit");
|
2012-08-28 17:54:45 -05:00
|
|
|
let ty = expr_ty(bcx, expr);
|
2014-01-15 13:39:08 -06:00
|
|
|
let v = consts::const_lit(bcx.ccx(), expr, lit);
|
|
|
|
immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
op: ast::UnOp,
|
|
|
|
sub_expr: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-03-15 15:29:34 -05:00
|
|
|
let ccx = bcx.ccx();
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_unary_datum");
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-03-06 11:24:11 -06:00
|
|
|
let method_call = MethodCall::expr(expr.id);
|
2014-03-08 10:33:39 -06:00
|
|
|
|
|
|
|
// The only overloaded operator that is translated to a datum
|
|
|
|
// is an overloaded deref, since it is always yields a `&T`.
|
|
|
|
// Otherwise, we should be in the RvalueDpsExpr path.
|
|
|
|
assert!(
|
|
|
|
op == ast::UnDeref ||
|
2014-09-05 11:18:53 -05:00
|
|
|
!ccx.tcx().method_map.borrow().contains_key(&method_call));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-03-06 11:24:11 -06:00
|
|
|
let un_ty = expr_ty(bcx, expr);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-03-06 11:24:11 -06:00
|
|
|
match op {
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::UnNot => {
|
2014-01-15 13:39:08 -06:00
|
|
|
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
2014-07-05 14:43:47 -05:00
|
|
|
let llresult = Not(bcx, datum.to_llscalarish(bcx));
|
2014-01-15 13:39:08 -06:00
|
|
|
immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::UnNeg => {
|
2014-01-15 13:39:08 -06:00
|
|
|
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
|
|
|
let val = datum.to_llscalarish(bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
let llneg = {
|
|
|
|
if ty::type_is_fp(un_ty) {
|
|
|
|
FNeg(bcx, val)
|
|
|
|
} else {
|
|
|
|
Neg(bcx, val)
|
|
|
|
}
|
|
|
|
};
|
2014-01-15 13:39:08 -06:00
|
|
|
immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::UnUniq => {
|
2014-04-06 05:54:41 -05:00
|
|
|
trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::UnDeref => {
|
2014-03-06 11:24:11 -06:00
|
|
|
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
2014-06-11 17:01:48 -05:00
|
|
|
deref_once(bcx, expr, datum, method_call)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-03-06 11:24:11 -06:00
|
|
|
}
|
2013-12-17 18:46:18 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
2014-09-13 13:09:25 -05:00
|
|
|
box_ty: Ty,
|
2014-09-06 11:13:04 -05:00
|
|
|
contents: &ast::Expr,
|
2014-09-13 13:09:25 -05:00
|
|
|
contents_ty: Ty)
|
2014-09-06 11:13:04 -05:00
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-04-06 05:54:41 -05:00
|
|
|
let _icx = push_ctxt("trans_uniq_expr");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
2014-08-06 04:59:40 -05:00
|
|
|
assert!(ty::type_is_sized(bcx.tcx(), contents_ty));
|
2014-04-06 05:54:41 -05:00
|
|
|
let llty = type_of::type_of(bcx.ccx(), contents_ty);
|
|
|
|
let size = llsize_of(bcx.ccx(), llty);
|
2014-10-14 15:36:11 -05:00
|
|
|
let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
|
2014-04-24 22:14:52 -05:00
|
|
|
let llty_ptr = llty.ptr_to();
|
|
|
|
let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align);
|
2014-05-05 20:56:44 -05:00
|
|
|
// Unique boxes do not allocate for zero-size types. The standard library
|
|
|
|
// may assume that `free` is never called on the pointer returned for
|
|
|
|
// `Box<ZeroSizeType>`.
|
2014-04-06 05:54:41 -05:00
|
|
|
let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
|
|
|
|
trans_into(bcx, contents, SaveIn(val))
|
2013-12-17 18:46:18 -06:00
|
|
|
} else {
|
2014-01-15 13:39:08 -06:00
|
|
|
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
|
|
|
|
fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
|
2014-05-20 23:18:10 -05:00
|
|
|
val, cleanup::HeapExchange, contents_ty);
|
2014-04-06 05:54:41 -05:00
|
|
|
let bcx = trans_into(bcx, contents, SaveIn(val));
|
2014-01-15 13:39:08 -06:00
|
|
|
fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
|
2014-04-06 05:54:41 -05:00
|
|
|
bcx
|
|
|
|
};
|
|
|
|
immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
subexpr: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_addr_of");
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut bcx = bcx;
|
2014-01-15 13:39:08 -06:00
|
|
|
let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
|
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 07:20:11 -05:00
|
|
|
match ty::get(sub_datum.ty).sty {
|
|
|
|
ty::ty_open(_) => {
|
|
|
|
// Opened DST value, close to a fat pointer
|
2014-08-06 04:59:40 -05:00
|
|
|
debug!("Closing fat pointer {}", bcx.ty_to_string(sub_datum.ty));
|
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 07:20:11 -05:00
|
|
|
|
|
|
|
let scratch = rvalue_scratch_datum(bcx,
|
|
|
|
ty::close_type(bcx.tcx(), sub_datum.ty),
|
|
|
|
"fat_addr_of");
|
|
|
|
let base = Load(bcx, get_dataptr(bcx, sub_datum.val));
|
|
|
|
Store(bcx, base, get_dataptr(bcx, scratch.val));
|
|
|
|
|
|
|
|
let len = Load(bcx, get_len(bcx, sub_datum.val));
|
|
|
|
Store(bcx, len, get_len(bcx, scratch.val));
|
|
|
|
|
|
|
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// Sized value, ref to a thin pointer
|
|
|
|
let ty = expr_ty(bcx, expr);
|
|
|
|
immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
|
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Important to get types for both lhs and rhs, because one might be _|_
|
|
|
|
// and the other not.
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
binop_expr: &ast::Expr,
|
2014-09-13 13:09:25 -05:00
|
|
|
binop_ty: Ty,
|
2014-09-06 11:13:04 -05:00
|
|
|
op: ast::BinOp,
|
2014-09-13 13:09:25 -05:00
|
|
|
lhs_t: Ty,
|
2014-09-06 11:13:04 -05:00
|
|
|
lhs: ValueRef,
|
2014-09-13 13:09:25 -05:00
|
|
|
rhs_t: Ty,
|
2014-09-06 11:13:04 -05:00
|
|
|
rhs: ValueRef)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_eager_binop");
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-05-02 13:04:46 -05:00
|
|
|
let tcx = bcx.tcx();
|
|
|
|
let is_simd = ty::type_is_simd(tcx, lhs_t);
|
|
|
|
let intype = {
|
2014-10-24 14:14:37 -05:00
|
|
|
if is_simd { ty::simd_type(tcx, lhs_t) }
|
2012-08-28 17:54:45 -05:00
|
|
|
else { lhs_t }
|
|
|
|
};
|
|
|
|
let is_float = ty::type_is_fp(intype);
|
2014-05-02 13:04:46 -05:00
|
|
|
let is_signed = ty::type_is_signed(intype);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
|
|
|
|
|
|
|
|
let mut bcx = bcx;
|
|
|
|
let val = match op {
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiAdd => {
|
2012-08-28 17:54:45 -05:00
|
|
|
if is_float { FAdd(bcx, lhs, rhs) }
|
|
|
|
else { Add(bcx, lhs, rhs) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiSub => {
|
2012-08-28 17:54:45 -05:00
|
|
|
if is_float { FSub(bcx, lhs, rhs) }
|
|
|
|
else { Sub(bcx, lhs, rhs) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiMul => {
|
2012-08-28 17:54:45 -05:00
|
|
|
if is_float { FMul(bcx, lhs, rhs) }
|
|
|
|
else { Mul(bcx, lhs, rhs) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiDiv => {
|
2012-08-28 17:54:45 -05:00
|
|
|
if is_float {
|
|
|
|
FDiv(bcx, lhs, rhs)
|
|
|
|
} else {
|
|
|
|
// Only zero-check integers; fp /0 is NaN
|
2014-06-05 14:23:34 -05:00
|
|
|
bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
|
|
|
|
op, lhs, rhs, rhs_t);
|
2014-05-02 13:04:46 -05:00
|
|
|
if is_signed {
|
2012-08-28 17:54:45 -05:00
|
|
|
SDiv(bcx, lhs, rhs)
|
|
|
|
} else {
|
|
|
|
UDiv(bcx, lhs, rhs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiRem => {
|
2012-08-28 17:54:45 -05:00
|
|
|
if is_float {
|
|
|
|
FRem(bcx, lhs, rhs)
|
|
|
|
} else {
|
|
|
|
// Only zero-check integers; fp %0 is NaN
|
2014-06-05 14:23:34 -05:00
|
|
|
bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
|
|
|
|
op, lhs, rhs, rhs_t);
|
2014-05-02 13:04:46 -05:00
|
|
|
if is_signed {
|
2012-08-28 17:54:45 -05:00
|
|
|
SRem(bcx, lhs, rhs)
|
|
|
|
} else {
|
|
|
|
URem(bcx, lhs, rhs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiBitOr => Or(bcx, lhs, rhs),
|
|
|
|
ast::BiBitAnd => And(bcx, lhs, rhs),
|
|
|
|
ast::BiBitXor => Xor(bcx, lhs, rhs),
|
|
|
|
ast::BiShl => Shl(bcx, lhs, rhs),
|
|
|
|
ast::BiShr => {
|
2014-05-02 13:04:46 -05:00
|
|
|
if is_signed {
|
2012-08-28 17:54:45 -05:00
|
|
|
AShr(bcx, lhs, rhs)
|
|
|
|
} else { LShr(bcx, lhs, rhs) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
|
2014-10-24 14:14:37 -05:00
|
|
|
if ty::type_is_scalar(rhs_t) {
|
2014-03-16 03:29:05 -05:00
|
|
|
unpack_result!(bcx, base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op))
|
2014-05-02 13:04:46 -05:00
|
|
|
} else if is_simd {
|
|
|
|
base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
|
|
|
|
} else {
|
|
|
|
bcx.tcx().sess.span_bug(binop_expr.span, "comparison operator unsupported for type")
|
2012-09-07 20:53:14 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => {
|
2013-05-02 11:28:53 -05:00
|
|
|
bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// refinement types would obviate the need for this
|
2014-01-07 10:54:58 -06:00
|
|
|
enum lazy_binop_ty {
|
|
|
|
lazy_and,
|
|
|
|
lazy_or,
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
binop_expr: &ast::Expr,
|
|
|
|
op: lazy_binop_ty,
|
|
|
|
a: &ast::Expr,
|
|
|
|
b: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_lazy_binop");
|
2012-08-28 17:54:45 -05:00
|
|
|
let binop_ty = expr_ty(bcx, binop_expr);
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
|
|
|
|
let lhs = lhs.to_llscalarish(past_lhs);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-12-18 16:54:42 -06:00
|
|
|
if past_lhs.unreachable.get() {
|
2014-01-15 13:39:08 -06:00
|
|
|
return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let join = fcx.new_id_block("join", binop_expr.id);
|
|
|
|
let before_rhs = fcx.new_id_block("before_rhs", b.id);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
match op {
|
2014-03-16 03:29:05 -05:00
|
|
|
lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb),
|
|
|
|
lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-02-06 16:28:02 -06:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
|
|
|
|
let rhs = rhs.to_llscalarish(past_rhs);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-12-18 16:54:42 -06:00
|
|
|
if past_rhs.unreachable.get() {
|
2014-01-15 13:39:08 -06:00
|
|
|
return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Br(past_rhs, join.llbb);
|
2014-11-17 02:39:01 -06:00
|
|
|
let phi = Phi(join, Type::i1(bcx.ccx()), &[lhs, rhs],
|
|
|
|
&[past_lhs.llbb, past_rhs.llbb]);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
op: ast::BinOp,
|
|
|
|
lhs: &ast::Expr,
|
|
|
|
rhs: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_binary");
|
2014-01-15 13:39:08 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-03-06 11:24:11 -06:00
|
|
|
// if overloaded, would be RvalueDpsExpr
|
2014-09-05 11:18:53 -05:00
|
|
|
assert!(!ccx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
|
2014-03-06 11:24:11 -06:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
match op {
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiAnd => {
|
2014-03-06 11:24:11 -06:00
|
|
|
trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiOr => {
|
2014-03-06 11:24:11 -06:00
|
|
|
trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let mut bcx = bcx;
|
2014-01-15 13:39:08 -06:00
|
|
|
let lhs_datum = unpack_datum!(bcx, trans(bcx, lhs));
|
|
|
|
let rhs_datum = unpack_datum!(bcx, trans(bcx, rhs));
|
2014-03-06 11:24:11 -06:00
|
|
|
let binop_ty = expr_ty(bcx, expr);
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
debug!("trans_binary (expr {}): lhs_datum={}",
|
2014-03-06 11:24:11 -06:00
|
|
|
expr.id,
|
2014-06-21 05:39:03 -05:00
|
|
|
lhs_datum.to_string(ccx));
|
2014-01-15 13:39:08 -06:00
|
|
|
let lhs_ty = lhs_datum.ty;
|
|
|
|
let lhs = lhs_datum.to_llscalarish(bcx);
|
|
|
|
|
|
|
|
debug!("trans_binary (expr {}): rhs_datum={}",
|
2014-03-06 11:24:11 -06:00
|
|
|
expr.id,
|
2014-06-21 05:39:03 -05:00
|
|
|
rhs_datum.to_string(ccx));
|
2014-01-15 13:39:08 -06:00
|
|
|
let rhs_ty = rhs_datum.ty;
|
|
|
|
let rhs = rhs_datum.to_llscalarish(bcx);
|
2014-03-06 11:24:11 -06:00
|
|
|
trans_eager_binop(bcx, expr, binop_ty, op,
|
2014-01-15 13:39:08 -06:00
|
|
|
lhs_ty, lhs, rhs_ty, rhs)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
method_call: MethodCall,
|
|
|
|
lhs: Datum<Expr>,
|
2014-09-15 03:48:58 -05:00
|
|
|
rhs: Vec<(Datum<Expr>, ast::NodeId)>,
|
2014-09-06 11:13:04 -05:00
|
|
|
dest: Option<Dest>)
|
|
|
|
-> Result<'blk, 'tcx> {
|
2014-10-15 01:05:01 -05:00
|
|
|
let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty;
|
2013-04-18 17:53:29 -05:00
|
|
|
callee::trans_call_inner(bcx,
|
2014-01-15 13:39:08 -06:00
|
|
|
Some(expr_info(expr)),
|
2014-02-26 08:06:45 -06:00
|
|
|
monomorphize_type(bcx, method_ty),
|
2014-01-15 13:39:08 -06:00
|
|
|
|bcx, arg_cleanup_scope| {
|
2013-04-18 17:53:29 -05:00
|
|
|
meth::trans_method_callee(bcx,
|
2014-03-06 11:24:11 -06:00
|
|
|
method_call,
|
|
|
|
None,
|
2014-01-15 13:39:08 -06:00
|
|
|
arg_cleanup_scope)
|
2013-04-18 17:53:29 -05:00
|
|
|
},
|
2014-03-06 11:24:11 -06:00
|
|
|
callee::ArgOverloadedOp(lhs, rhs),
|
2014-03-04 16:26:51 -06:00
|
|
|
dest)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
callee: &'a ast::Expr,
|
|
|
|
args: &'a [P<ast::Expr>],
|
|
|
|
dest: Option<Dest>)
|
|
|
|
-> Block<'blk, 'tcx> {
|
2014-06-11 17:01:48 -05:00
|
|
|
let method_call = MethodCall::expr(expr.id);
|
2014-10-15 01:05:01 -05:00
|
|
|
let method_type = (*bcx.tcx()
|
|
|
|
.method_map
|
|
|
|
.borrow())[method_call]
|
|
|
|
.ty;
|
2014-05-29 00:26:56 -05:00
|
|
|
let mut all_args = vec!(callee);
|
2014-09-07 12:09:06 -05:00
|
|
|
all_args.extend(args.iter().map(|e| &**e));
|
2014-06-01 18:35:01 -05:00
|
|
|
unpack_result!(bcx,
|
|
|
|
callee::trans_call_inner(bcx,
|
|
|
|
Some(expr_info(expr)),
|
|
|
|
monomorphize_type(bcx,
|
|
|
|
method_type),
|
|
|
|
|bcx, arg_cleanup_scope| {
|
|
|
|
meth::trans_method_callee(
|
|
|
|
bcx,
|
|
|
|
method_call,
|
|
|
|
None,
|
|
|
|
arg_cleanup_scope)
|
|
|
|
},
|
2014-09-07 12:09:06 -05:00
|
|
|
callee::ArgOverloadedCall(all_args),
|
2014-06-01 18:35:01 -05:00
|
|
|
dest));
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn int_cast(bcx: Block,
|
2014-01-07 10:54:58 -06:00
|
|
|
lldsttype: Type,
|
|
|
|
llsrctype: Type,
|
|
|
|
llsrc: ValueRef,
|
|
|
|
signed: bool)
|
|
|
|
-> ValueRef {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("int_cast");
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-06-16 05:52:44 -05:00
|
|
|
let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
|
|
|
|
let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
|
2013-01-10 23:23:07 -06:00
|
|
|
return if dstsz == srcsz {
|
|
|
|
BitCast(bcx, llsrc, lldsttype)
|
|
|
|
} else if srcsz > dstsz {
|
|
|
|
TruncOrBitCast(bcx, llsrc, lldsttype)
|
|
|
|
} else if signed {
|
|
|
|
SExtOrBitCast(bcx, llsrc, lldsttype)
|
|
|
|
} else {
|
|
|
|
ZExtOrBitCast(bcx, llsrc, lldsttype)
|
|
|
|
};
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn float_cast(bcx: Block,
|
2014-01-07 10:54:58 -06:00
|
|
|
lldsttype: Type,
|
|
|
|
llsrctype: Type,
|
|
|
|
llsrc: ValueRef)
|
|
|
|
-> ValueRef {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("float_cast");
|
2013-06-16 05:52:44 -05:00
|
|
|
let srcsz = llsrctype.float_width();
|
|
|
|
let dstsz = lldsttype.float_width();
|
2012-08-28 17:54:45 -05:00
|
|
|
return if dstsz > srcsz {
|
|
|
|
FPExt(bcx, llsrc, lldsttype)
|
|
|
|
} else if srcsz > dstsz {
|
|
|
|
FPTrunc(bcx, llsrc, lldsttype)
|
|
|
|
} else { llsrc };
|
|
|
|
}
|
|
|
|
|
2014-10-15 01:25:34 -05:00
|
|
|
#[deriving(PartialEq, Show)]
|
2013-01-29 19:57:02 -06:00
|
|
|
pub enum cast_kind {
|
2012-08-28 17:54:45 -05:00
|
|
|
cast_pointer,
|
|
|
|
cast_integral,
|
|
|
|
cast_float,
|
|
|
|
cast_enum,
|
|
|
|
cast_other,
|
|
|
|
}
|
|
|
|
|
2014-09-13 13:09:25 -05:00
|
|
|
pub fn cast_type_kind(tcx: &ty::ctxt, t: Ty) -> cast_kind {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(t).sty {
|
2014-04-09 02:15:31 -05:00
|
|
|
ty::ty_char => cast_integral,
|
2013-11-28 14:22:53 -06:00
|
|
|
ty::ty_float(..) => cast_float,
|
2014-08-27 00:07:28 -05:00
|
|
|
ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => {
|
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 07:20:11 -05:00
|
|
|
if ty::type_is_sized(tcx, mt.ty) {
|
|
|
|
cast_pointer
|
|
|
|
} else {
|
|
|
|
cast_other
|
|
|
|
}
|
|
|
|
}
|
2013-11-28 14:22:53 -06:00
|
|
|
ty::ty_bare_fn(..) => cast_pointer,
|
|
|
|
ty::ty_int(..) => cast_integral,
|
|
|
|
ty::ty_uint(..) => cast_integral,
|
2014-04-09 02:15:31 -05:00
|
|
|
ty::ty_bool => cast_integral,
|
2013-11-28 14:22:53 -06:00
|
|
|
ty::ty_enum(..) => cast_enum,
|
2014-04-09 02:15:31 -05:00
|
|
|
_ => cast_other
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-13 13:09:25 -05:00
|
|
|
fn cast_is_noop(t_in: Ty, t_out: Ty) -> bool {
|
2014-09-02 21:09:07 -05:00
|
|
|
match (ty::deref(t_in, true), ty::deref(t_out, true)) {
|
|
|
|
(Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => {
|
|
|
|
t_in == t_out
|
|
|
|
}
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
id: ast::NodeId)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_cast");
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
|
|
|
let t_in = expr_ty(bcx, expr);
|
2014-01-15 13:39:08 -06:00
|
|
|
let t_out = node_id_type(bcx, id);
|
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 07:20:11 -05:00
|
|
|
let k_in = cast_type_kind(bcx.tcx(), t_in);
|
|
|
|
let k_out = cast_type_kind(bcx.tcx(), t_out);
|
2012-08-28 17:54:45 -05:00
|
|
|
let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
|
2014-07-05 14:47:14 -05:00
|
|
|
let ll_t_in = type_of::arg_type_of(ccx, t_in);
|
|
|
|
let ll_t_out = type_of::arg_type_of(ccx, t_out);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// Convert the value to be cast into a ValueRef, either by-ref or
|
|
|
|
// by-value as appropriate given its type:
|
2014-09-02 21:09:07 -05:00
|
|
|
let mut datum = unpack_datum!(bcx, trans(bcx, expr));
|
|
|
|
|
|
|
|
if cast_is_noop(datum.ty, t_out) {
|
|
|
|
datum.ty = t_out;
|
|
|
|
return DatumBlock::new(bcx, datum);
|
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let newval = match (k_in, k_out) {
|
|
|
|
(cast_integral, cast_integral) => {
|
|
|
|
let llexpr = datum.to_llscalarish(bcx);
|
|
|
|
int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
|
|
|
|
}
|
|
|
|
(cast_float, cast_float) => {
|
|
|
|
let llexpr = datum.to_llscalarish(bcx);
|
|
|
|
float_cast(bcx, ll_t_out, ll_t_in, llexpr)
|
|
|
|
}
|
|
|
|
(cast_integral, cast_float) => {
|
|
|
|
let llexpr = datum.to_llscalarish(bcx);
|
|
|
|
if s_in {
|
|
|
|
SIToFP(bcx, llexpr, ll_t_out)
|
|
|
|
} else { UIToFP(bcx, llexpr, ll_t_out) }
|
|
|
|
}
|
|
|
|
(cast_float, cast_integral) => {
|
|
|
|
let llexpr = datum.to_llscalarish(bcx);
|
|
|
|
if ty::type_is_signed(t_out) {
|
|
|
|
FPToSI(bcx, llexpr, ll_t_out)
|
|
|
|
} else { FPToUI(bcx, llexpr, ll_t_out) }
|
|
|
|
}
|
|
|
|
(cast_integral, cast_pointer) => {
|
|
|
|
let llexpr = datum.to_llscalarish(bcx);
|
|
|
|
IntToPtr(bcx, llexpr, ll_t_out)
|
|
|
|
}
|
|
|
|
(cast_pointer, cast_integral) => {
|
|
|
|
let llexpr = datum.to_llscalarish(bcx);
|
|
|
|
PtrToInt(bcx, llexpr, ll_t_out)
|
|
|
|
}
|
|
|
|
(cast_pointer, cast_pointer) => {
|
|
|
|
let llexpr = datum.to_llscalarish(bcx);
|
|
|
|
PointerCast(bcx, llexpr, ll_t_out)
|
|
|
|
}
|
|
|
|
(cast_enum, cast_integral) |
|
|
|
|
(cast_enum, cast_float) => {
|
|
|
|
let mut bcx = bcx;
|
|
|
|
let repr = adt::represent_type(ccx, t_in);
|
|
|
|
let datum = unpack_datum!(
|
|
|
|
bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
|
|
|
|
let llexpr_ptr = datum.to_llref();
|
|
|
|
let lldiscrim_a =
|
2014-04-21 19:03:02 -05:00
|
|
|
adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
|
2014-01-15 13:39:08 -06:00
|
|
|
match k_out {
|
|
|
|
cast_integral => int_cast(bcx, ll_t_out,
|
|
|
|
val_ty(lldiscrim_a),
|
|
|
|
lldiscrim_a, true),
|
|
|
|
cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
|
2014-05-16 12:45:16 -05:00
|
|
|
_ => {
|
|
|
|
ccx.sess().bug(format!("translating unsupported cast: \
|
2014-10-15 01:25:34 -05:00
|
|
|
{} ({}) -> {} ({})",
|
2014-05-16 12:45:16 -05:00
|
|
|
t_in.repr(bcx.tcx()),
|
|
|
|
k_in,
|
|
|
|
t_out.repr(bcx.tcx()),
|
|
|
|
k_out).as_slice())
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
2014-03-05 08:36:01 -06:00
|
|
|
_ => ccx.sess().bug(format!("translating unsupported cast: \
|
2014-10-15 01:25:34 -05:00
|
|
|
{} ({}) -> {} ({})",
|
2014-05-16 12:45:16 -05:00
|
|
|
t_in.repr(bcx.tcx()),
|
|
|
|
k_in,
|
|
|
|
t_out.repr(bcx.tcx()),
|
|
|
|
k_out).as_slice())
|
2014-01-15 13:39:08 -06:00
|
|
|
};
|
|
|
|
return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
op: ast::BinOp,
|
|
|
|
dst: &ast::Expr,
|
2014-09-07 12:09:06 -05:00
|
|
|
src: &ast::Expr)
|
2014-09-06 11:13:04 -05:00
|
|
|
-> Block<'blk, 'tcx> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_assign_op");
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut bcx = bcx;
|
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
debug!("trans_assign_op(expr={})", bcx.expr_to_string(expr));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// User-defined operator methods cannot be used with `+=` etc right now
|
2014-04-09 10:18:40 -05:00
|
|
|
assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// Evaluate LHS (destination), which should be an lvalue
|
|
|
|
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
|
|
|
|
assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
|
|
|
|
let dst_ty = dst_datum.ty;
|
2014-07-05 14:47:14 -05:00
|
|
|
let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// Evaluate RHS
|
2014-05-16 12:15:33 -05:00
|
|
|
let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
|
2014-01-15 13:39:08 -06:00
|
|
|
let rhs_ty = rhs_datum.ty;
|
|
|
|
let rhs = rhs_datum.to_llscalarish(bcx);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// Perform computation and store the result
|
2014-01-15 13:39:08 -06:00
|
|
|
let result_datum = unpack_datum!(
|
|
|
|
bcx, trans_eager_binop(bcx, expr, dst_datum.ty, op,
|
|
|
|
dst_ty, dst, rhs_ty, rhs));
|
|
|
|
return result_datum.store_to(bcx, dst_datum.val);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
datum: Datum<Expr>,
|
|
|
|
expr: &ast::Expr)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-03-06 11:24:11 -06:00
|
|
|
let mut bcx = bcx;
|
|
|
|
|
|
|
|
// Ensure cleanup of `datum` if not already scheduled and obtain
|
|
|
|
// a "by ref" pointer.
|
|
|
|
let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
|
|
|
|
|
|
|
|
// Compute final type. Note that we are loose with the region and
|
|
|
|
// mutability, since those things don't matter in trans.
|
|
|
|
let referent_ty = lv_datum.ty;
|
|
|
|
let ptr_ty = ty::mk_imm_rptr(bcx.tcx(), ty::ReStatic, referent_ty);
|
|
|
|
|
|
|
|
// Get the pointer.
|
|
|
|
let llref = lv_datum.to_llref();
|
|
|
|
|
|
|
|
// Construct the resulting datum, using what was the "by ref"
|
|
|
|
// ValueRef of type `referent_ty` to be the "by value" ValueRef
|
|
|
|
// of type `&referent_ty`.
|
2014-05-28 14:36:05 -05:00
|
|
|
DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(ByValue))))
|
2014-03-06 11:24:11 -06:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>,
|
|
|
|
times: uint)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
|
|
|
let mut datum = datum;
|
2014-06-11 17:01:48 -05:00
|
|
|
for i in range(0, times) {
|
|
|
|
let method_call = MethodCall::autoderef(expr.id, i);
|
|
|
|
datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
DatumBlock { bcx: bcx, datum: datum }
|
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>,
|
|
|
|
method_call: MethodCall)
|
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
2014-06-11 17:01:48 -05:00
|
|
|
debug!("deref_once(expr={}, datum={}, method_call={})",
|
2014-01-15 13:39:08 -06:00
|
|
|
expr.repr(bcx.tcx()),
|
2014-06-21 05:39:03 -05:00
|
|
|
datum.to_string(ccx),
|
2014-06-11 17:01:48 -05:00
|
|
|
method_call);
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
let mut bcx = bcx;
|
|
|
|
|
2014-03-08 10:33:39 -06:00
|
|
|
// Check for overloaded deref.
|
2014-09-05 11:18:53 -05:00
|
|
|
let method_ty = ccx.tcx().method_map.borrow()
|
2014-11-06 11:25:16 -06:00
|
|
|
.get(&method_call).map(|method| method.ty);
|
2014-03-06 11:24:11 -06:00
|
|
|
let datum = match method_ty {
|
|
|
|
Some(method_ty) => {
|
2014-03-08 10:33:39 -06:00
|
|
|
// Overloaded. Evaluate `trans_overloaded_op`, which will
|
|
|
|
// invoke the user's deref() method, which basically
|
2014-07-03 16:32:41 -05:00
|
|
|
// converts from the `Smaht<T>` pointer that we have into
|
2014-03-08 10:33:39 -06:00
|
|
|
// a `&T` pointer. We can then proceed down the normal
|
|
|
|
// path (below) to dereference that `&T`.
|
2014-06-11 17:01:48 -05:00
|
|
|
let datum = match method_call.adjustment {
|
|
|
|
// Always perform an AutoPtr when applying an overloaded auto-deref
|
|
|
|
typeck::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)),
|
|
|
|
_ => datum
|
2014-03-06 11:24:11 -06:00
|
|
|
};
|
2014-09-02 22:31:36 -05:00
|
|
|
|
2014-10-24 14:14:37 -05:00
|
|
|
let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty)).unwrap();
|
2014-09-02 22:31:36 -05:00
|
|
|
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
|
|
|
|
|
|
|
|
unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
|
2014-09-15 03:48:58 -05:00
|
|
|
datum, Vec::new(), Some(SaveIn(scratch.val))));
|
2014-09-02 22:31:36 -05:00
|
|
|
scratch.to_expr_datum()
|
2014-03-06 11:24:11 -06:00
|
|
|
}
|
2014-03-08 10:33:39 -06:00
|
|
|
None => {
|
|
|
|
// Not overloaded. We already have a pointer we know how to deref.
|
|
|
|
datum
|
|
|
|
}
|
2014-03-06 11:24:11 -06:00
|
|
|
};
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let r = match ty::get(datum.ty).sty {
|
|
|
|
ty::ty_uniq(content_ty) => {
|
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 07:20:11 -05:00
|
|
|
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
|
|
|
deref_owned_pointer(bcx, expr, datum, content_ty)
|
|
|
|
} else {
|
2014-08-31 23:14:56 -05:00
|
|
|
// A fat pointer and an opened DST value have the same
|
2014-10-25 22:10:16 -05:00
|
|
|
// representation just different types. Since there is no
|
2014-08-31 23:14:56 -05:00
|
|
|
// temporary for `*e` here (because it is unsized), we cannot
|
|
|
|
// emulate the sized object code path for running drop glue and
|
|
|
|
// free. Instead, we schedule cleanup for `e`, turning it into
|
|
|
|
// an lvalue.
|
|
|
|
let datum = unpack_datum!(
|
|
|
|
bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
|
|
|
|
|
|
|
|
let datum = Datum::new(datum.val, ty::mk_open(bcx.tcx(), content_ty), LvalueExpr);
|
|
|
|
DatumBlock::new(bcx, datum)
|
2014-04-09 02:15:31 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
|
|
|
|
ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
|
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 07:20:11 -05:00
|
|
|
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
|
|
|
let ptr = datum.to_llscalarish(bcx);
|
|
|
|
|
|
|
|
// Always generate an lvalue datum, even if datum.mode is
|
|
|
|
// an rvalue. This is because datum.mode is only an
|
|
|
|
// rvalue for non-owning pointers like &T or *T, in which
|
|
|
|
// case cleanup *is* scheduled elsewhere, by the true
|
|
|
|
// owner (or, in the case of *T, by the user).
|
|
|
|
DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
|
|
|
|
} else {
|
2014-10-25 22:10:16 -05:00
|
|
|
// A fat pointer and an opened DST value have the same representation
|
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 07:20:11 -05:00
|
|
|
// just different types.
|
|
|
|
DatumBlock::new(bcx, Datum::new(datum.val,
|
|
|
|
ty::mk_open(bcx.tcx(), content_ty),
|
2014-08-31 23:14:56 -05:00
|
|
|
LvalueExpr))
|
2014-04-09 02:15:31 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
bcx.tcx().sess.span_bug(
|
|
|
|
expr.span,
|
|
|
|
format!("deref invoked on expr of illegal type {}",
|
2014-05-16 12:45:16 -05:00
|
|
|
datum.ty.repr(bcx.tcx())).as_slice());
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-06-11 17:01:48 -05:00
|
|
|
debug!("deref_once(expr={}, method_call={}, result={})",
|
2014-06-21 05:39:03 -05:00
|
|
|
expr.id, method_call, r.datum.to_string(ccx));
|
2014-01-15 13:39:08 -06:00
|
|
|
|
|
|
|
return r;
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn deref_owned_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
datum: Datum<Expr>,
|
2014-09-13 13:09:25 -05:00
|
|
|
content_ty: Ty)
|
2014-09-06 11:13:04 -05:00
|
|
|
-> DatumBlock<'blk, 'tcx, Expr> {
|
2014-01-15 13:39:08 -06:00
|
|
|
/*!
|
|
|
|
* We microoptimize derefs of owned pointers a bit here.
|
|
|
|
* Basically, the idea is to make the deref of an rvalue
|
|
|
|
* result in an rvalue. This helps to avoid intermediate stack
|
|
|
|
* slots in the resulting LLVM. The idea here is that, if the
|
2014-05-05 20:56:44 -05:00
|
|
|
* `Box<T>` pointer is an rvalue, then we can schedule a *shallow*
|
|
|
|
* free of the `Box<T>` pointer, and then return a ByRef rvalue
|
2014-01-15 13:39:08 -06:00
|
|
|
* into the pointer. Because the free is shallow, it is legit
|
|
|
|
* to return an rvalue, because we know that the contents are
|
|
|
|
* not yet scheduled to be freed. The language rules ensure that the
|
|
|
|
* contents will be used (or moved) before the free occurs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
match datum.kind {
|
|
|
|
RvalueExpr(Rvalue { mode: ByRef }) => {
|
|
|
|
let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
|
|
|
|
let ptr = Load(bcx, datum.val);
|
2014-04-07 11:36:36 -05:00
|
|
|
if !type_is_zero_size(bcx.ccx(), content_ty) {
|
2014-05-20 23:18:10 -05:00
|
|
|
bcx.fcx.schedule_free_value(scope, ptr, cleanup::HeapExchange, content_ty);
|
2014-04-07 11:36:36 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
RvalueExpr(Rvalue { mode: ByValue }) => {
|
|
|
|
let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
|
2014-04-07 11:36:36 -05:00
|
|
|
if !type_is_zero_size(bcx.ccx(), content_ty) {
|
2014-05-20 23:18:10 -05:00
|
|
|
bcx.fcx.schedule_free_value(scope, datum.val, cleanup::HeapExchange,
|
|
|
|
content_ty);
|
2014-04-07 11:36:36 -05:00
|
|
|
}
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
LvalueExpr => { }
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we had an rvalue in, we produce an rvalue out.
|
|
|
|
let (llptr, kind) = match datum.kind {
|
|
|
|
LvalueExpr => {
|
|
|
|
(Load(bcx, datum.val), LvalueExpr)
|
|
|
|
}
|
|
|
|
RvalueExpr(Rvalue { mode: ByRef }) => {
|
2014-05-28 14:36:05 -05:00
|
|
|
(Load(bcx, datum.val), RvalueExpr(Rvalue::new(ByRef)))
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
RvalueExpr(Rvalue { mode: ByValue }) => {
|
2014-05-28 14:36:05 -05:00
|
|
|
(datum.val, RvalueExpr(Rvalue::new(ByRef)))
|
2014-01-15 13:39:08 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let datum = Datum { ty: content_ty, val: llptr, kind: kind };
|
|
|
|
DatumBlock { bcx: bcx, datum: datum }
|
|
|
|
}
|
2013-08-28 01:12:05 -05:00
|
|
|
}
|