Rollup merge of #41232 - arielb1:mir-rvalues, r=eddyb
move rvalue checking to MIR
This commit is contained in:
commit
1dd9801fa5
@ -22,7 +22,8 @@ impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
|
||||
impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
|
||||
impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
|
||||
impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
|
||||
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info });
|
||||
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info,
|
||||
is_user_variable});
|
||||
impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
|
||||
impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
|
||||
impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind });
|
||||
|
@ -197,10 +197,10 @@ impl<'tcx> Mir<'tcx> {
|
||||
pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
|
||||
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
|
||||
let local = Local::new(index);
|
||||
if self.local_decls[local].source_info.is_none() {
|
||||
Some(local)
|
||||
} else {
|
||||
if self.local_decls[local].is_user_variable {
|
||||
None
|
||||
} else {
|
||||
Some(local)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -210,10 +210,10 @@ impl<'tcx> Mir<'tcx> {
|
||||
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
|
||||
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
|
||||
let local = Local::new(index);
|
||||
if self.local_decls[local].source_info.is_none() {
|
||||
None
|
||||
} else {
|
||||
if self.local_decls[local].is_user_variable {
|
||||
Some(local)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -370,6 +370,9 @@ pub struct LocalDecl<'tcx> {
|
||||
/// Temporaries and the return pointer are always mutable.
|
||||
pub mutability: Mutability,
|
||||
|
||||
/// True if this corresponds to a user-declared local variable.
|
||||
pub is_user_variable: bool,
|
||||
|
||||
/// Type of this local.
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
@ -379,24 +382,23 @@ pub struct LocalDecl<'tcx> {
|
||||
/// to generate better debuginfo.
|
||||
pub name: Option<Name>,
|
||||
|
||||
/// For user-declared variables, stores their source information.
|
||||
///
|
||||
/// For temporaries, this is `None`.
|
||||
///
|
||||
/// This is the primary way to differentiate between user-declared
|
||||
/// variables and compiler-generated temporaries.
|
||||
pub source_info: Option<SourceInfo>,
|
||||
/// Source info of the local.
|
||||
pub source_info: SourceInfo,
|
||||
}
|
||||
|
||||
impl<'tcx> LocalDecl<'tcx> {
|
||||
/// Create a new `LocalDecl` for a temporary.
|
||||
#[inline]
|
||||
pub fn new_temp(ty: Ty<'tcx>) -> Self {
|
||||
pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
|
||||
LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: ty,
|
||||
name: None,
|
||||
source_info: None,
|
||||
source_info: SourceInfo {
|
||||
span: span,
|
||||
scope: ARGUMENT_VISIBILITY_SCOPE
|
||||
},
|
||||
is_user_variable: false
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,12 +406,16 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
///
|
||||
/// This must be inserted into the `local_decls` list as the first local.
|
||||
#[inline]
|
||||
pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
|
||||
pub fn new_return_pointer(return_ty: Ty, span: Span) -> LocalDecl {
|
||||
LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: return_ty,
|
||||
source_info: None,
|
||||
source_info: SourceInfo {
|
||||
span: span,
|
||||
scope: ARGUMENT_VISIBILITY_SCOPE
|
||||
},
|
||||
name: None, // FIXME maybe we do want some name here?
|
||||
is_user_variable: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -630,12 +630,11 @@ macro_rules! make_mir_visitor {
|
||||
ref $($mutability)* ty,
|
||||
name: _,
|
||||
ref $($mutability)* source_info,
|
||||
is_user_variable: _,
|
||||
} = *local_decl;
|
||||
|
||||
self.visit_ty(ty);
|
||||
if let Some(ref $($mutability)* info) = *source_info {
|
||||
self.visit_source_info(info);
|
||||
}
|
||||
self.visit_source_info(source_info);
|
||||
}
|
||||
|
||||
fn super_visibility_scope(&mut self,
|
||||
|
@ -307,12 +307,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
data
|
||||
}
|
||||
|
||||
fn create_drop_flag(&mut self, index: MovePathIndex) {
|
||||
fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) {
|
||||
let tcx = self.tcx;
|
||||
let patch = &mut self.patch;
|
||||
debug!("create_drop_flag({:?})", self.mir.span);
|
||||
self.drop_flags.entry(index).or_insert_with(|| {
|
||||
patch.new_temp(tcx.types.bool)
|
||||
patch.new_temp(tcx.types.bool, span)
|
||||
});
|
||||
}
|
||||
|
||||
@ -374,7 +374,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
|
||||
child, location, path, (maybe_live, maybe_dead));
|
||||
if maybe_live && maybe_dead {
|
||||
self.create_drop_flag(child)
|
||||
self.create_drop_flag(child, terminator.source_info.span)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ use rustc_typeck as typeck;
|
||||
use rustc_privacy;
|
||||
use rustc_plugin::registry::Registry;
|
||||
use rustc_plugin as plugin;
|
||||
use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues,
|
||||
use rustc_passes::{ast_validation, no_asm, loops, consts,
|
||||
static_recursion, hir_stats, mir_stats};
|
||||
use rustc_const_eval::check_match;
|
||||
use super::Compilation;
|
||||
@ -958,10 +958,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
"liveness checking",
|
||||
|| middle::liveness::check_crate(tcx));
|
||||
|
||||
time(time_passes,
|
||||
"rvalue checking",
|
||||
|| rvalues::check_crate(tcx));
|
||||
|
||||
time(time_passes,
|
||||
"MIR dump",
|
||||
|| mir::mir_map::build_mir_for_crate(tcx));
|
||||
@ -977,8 +973,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
// in stage 4 below.
|
||||
passes.push_hook(box mir::transform::dump_mir::DumpMir);
|
||||
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
|
||||
passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
|
||||
passes.push_pass(box mir::transform::type_check::TypeckMir);
|
||||
passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
|
||||
passes.push_pass(
|
||||
box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
|
||||
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
|
||||
|
@ -62,7 +62,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let idx = unpack!(block = this.as_operand(block, None, index));
|
||||
|
||||
// bounds check:
|
||||
let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
|
||||
let (len, lt) = (this.temp(usize_ty.clone(), expr_span),
|
||||
this.temp(bool_ty, expr_span));
|
||||
this.cfg.push_assign(block, source_info, // len = len(slice)
|
||||
&len, Rvalue::Len(slice.clone()));
|
||||
this.cfg.push_assign(block, source_info, // lt = idx < len
|
||||
|
@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let bool_ty = this.hir.bool_ty();
|
||||
|
||||
let minval = this.minval_literal(expr_span, expr.ty);
|
||||
let is_min = this.temp(bool_ty);
|
||||
let is_min = this.temp(bool_ty, expr_span);
|
||||
|
||||
this.cfg.push_assign(block, source_info, &is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
|
||||
@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
ExprKind::Box { value, value_extents } => {
|
||||
let value = this.hir.mirror(value);
|
||||
let result = this.temp(expr.ty);
|
||||
let result = this.temp(expr.ty, expr_span);
|
||||
// to start, malloc some memory of suitable type (thus far, uninitialized):
|
||||
this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty));
|
||||
this.in_scope(value_extents, block, |this| {
|
||||
@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let bool_ty = self.hir.bool_ty();
|
||||
if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
|
||||
let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false);
|
||||
let result_value = self.temp(result_tup);
|
||||
let result_value = self.temp(result_tup, span);
|
||||
|
||||
self.cfg.push_assign(block, source_info,
|
||||
&result_value, Rvalue::CheckedBinaryOp(op,
|
||||
@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
// Check for / 0
|
||||
let is_zero = self.temp(bool_ty);
|
||||
let is_zero = self.temp(bool_ty, span);
|
||||
let zero = self.zero_literal(span, ty);
|
||||
self.cfg.push_assign(block, source_info, &is_zero,
|
||||
Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero));
|
||||
@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let neg_1 = self.neg_1_literal(span, ty);
|
||||
let min = self.minval_literal(span, ty);
|
||||
|
||||
let is_neg_1 = self.temp(bool_ty);
|
||||
let is_min = self.temp(bool_ty);
|
||||
let of = self.temp(bool_ty);
|
||||
let is_neg_1 = self.temp(bool_ty, span);
|
||||
let is_min = self.temp(bool_ty, span);
|
||||
let of = self.temp(bool_ty, span);
|
||||
|
||||
// this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
|
||||
|
||||
|
@ -44,8 +44,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
let expr_ty = expr.ty.clone();
|
||||
let temp = this.temp(expr_ty.clone());
|
||||
let expr_span = expr.span;
|
||||
let temp = this.temp(expr_ty.clone(), expr_span);
|
||||
let source_info = this.source_info(expr_span);
|
||||
|
||||
if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) {
|
||||
|
@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
_ => {
|
||||
let expr_ty = expr.ty;
|
||||
let temp = this.temp(expr.ty.clone());
|
||||
let temp = this.temp(expr.ty.clone(), expr_span);
|
||||
unpack!(block = this.into(&temp, block, expr));
|
||||
unpack!(block = this.build_drop(block, expr_span, temp, expr_ty));
|
||||
block.unit()
|
||||
|
@ -710,7 +710,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
mutability: mutability,
|
||||
ty: var_ty.clone(),
|
||||
name: Some(name),
|
||||
source_info: Some(source_info),
|
||||
source_info: source_info,
|
||||
is_user_variable: true,
|
||||
});
|
||||
self.var_indices.insert(var_id, var);
|
||||
|
||||
|
@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
|
||||
num_enum_variants, values, variants);
|
||||
let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
|
||||
let discr = self.temp(discr_ty);
|
||||
let discr = self.temp(discr_ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &discr,
|
||||
Rvalue::Discriminant(lvalue.clone()));
|
||||
assert_eq!(values.len() + 1, targets.len());
|
||||
@ -270,7 +270,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
if let ty::TyRef(region, mt) = ty.sty {
|
||||
if let ty::TyArray(_, _) = mt.ty.sty {
|
||||
ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
|
||||
let val_slice = self.temp(ty);
|
||||
let val_slice = self.temp(ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &val_slice,
|
||||
Rvalue::Cast(CastKind::Unsize, val, ty));
|
||||
val = Operand::Consume(val_slice);
|
||||
@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
value: value.clone()
|
||||
});
|
||||
|
||||
let slice = self.temp(ty);
|
||||
let slice = self.temp(ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &slice,
|
||||
Rvalue::Cast(CastKind::Unsize, array, ty));
|
||||
Operand::Consume(slice)
|
||||
@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
|
||||
|
||||
let bool_ty = self.hir.bool_ty();
|
||||
let eq_result = self.temp(bool_ty);
|
||||
let eq_result = self.temp(bool_ty, test.span);
|
||||
let eq_block = self.cfg.start_new_block();
|
||||
let cleanup = self.diverge_cleanup();
|
||||
self.cfg.terminate(block, source_info, TerminatorKind::Call {
|
||||
@ -349,7 +349,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
TestKind::Len { len, op } => {
|
||||
let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty());
|
||||
let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
|
||||
let (actual, result) = (self.temp(usize_ty, test.span),
|
||||
self.temp(bool_ty, test.span));
|
||||
|
||||
// actual = len(lvalue)
|
||||
self.cfg.push_assign(block, source_info,
|
||||
@ -383,7 +384,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
left: Operand<'tcx>,
|
||||
right: Operand<'tcx>) -> BasicBlock {
|
||||
let bool_ty = self.hir.bool_ty();
|
||||
let result = self.temp(bool_ty);
|
||||
let result = self.temp(bool_ty, span);
|
||||
|
||||
// result = op(left, right)
|
||||
let source_info = self.source_info(span);
|
||||
|
@ -27,8 +27,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
///
|
||||
/// NB: **No cleanup is scheduled for this temporary.** You should
|
||||
/// call `schedule_drop` once the temporary is initialized.
|
||||
pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
|
||||
let temp = self.local_decls.push(LocalDecl::new_temp(ty));
|
||||
pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Lvalue<'tcx> {
|
||||
let temp = self.local_decls.push(LocalDecl::new_temp(ty, span));
|
||||
let lvalue = Lvalue::Local(temp);
|
||||
debug!("temp: created temp {:?} with type {:?}",
|
||||
lvalue, self.local_decls[temp].ty);
|
||||
@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
value: u64)
|
||||
-> Lvalue<'tcx> {
|
||||
let usize_ty = self.hir.usize_ty();
|
||||
let temp = self.temp(usize_ty);
|
||||
let temp = self.temp(usize_ty, source_info.span);
|
||||
self.cfg.push_assign_constant(
|
||||
block, source_info, &temp,
|
||||
Constant {
|
||||
|
@ -249,7 +249,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
visibility_scopes: IndexVec::new(),
|
||||
visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
|
||||
breakable_scopes: vec![],
|
||||
local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
|
||||
local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty,
|
||||
span), 1),
|
||||
var_indices: NodeMap(),
|
||||
unit_temp: None,
|
||||
cached_resume_block: None,
|
||||
@ -304,8 +305,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
self.local_decls.push(LocalDecl {
|
||||
mutability: Mutability::Not,
|
||||
ty: ty,
|
||||
source_info: None,
|
||||
source_info: SourceInfo {
|
||||
scope: ARGUMENT_VISIBILITY_SCOPE,
|
||||
span: pattern.map_or(self.fn_span, |pat| pat.span)
|
||||
},
|
||||
name: name,
|
||||
is_user_variable: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -341,7 +346,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Some(ref tmp) => tmp.clone(),
|
||||
None => {
|
||||
let ty = self.hir.unit_ty();
|
||||
let tmp = self.temp(ty);
|
||||
let fn_span = self.fn_span;
|
||||
let tmp = self.temp(ty, fn_span);
|
||||
self.unit_temp = Some(tmp.clone());
|
||||
tmp
|
||||
}
|
||||
|
@ -244,6 +244,39 @@ let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) };
|
||||
```
|
||||
"##,
|
||||
|
||||
E0161: r##"
|
||||
A value was moved. However, its size was not known at compile time, and only
|
||||
values of a known size can be moved.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<[isize]> = box *array;
|
||||
// error: cannot move a value of type [isize]: the size of [isize] cannot
|
||||
// be statically determined
|
||||
}
|
||||
```
|
||||
|
||||
In Rust, you can only move a value when its size is known at compile time.
|
||||
|
||||
To work around this restriction, consider "hiding" the value behind a reference:
|
||||
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
|
||||
it around as usual. Example:
|
||||
|
||||
```
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<&[isize]> = box array; // ok!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0396: r##"
|
||||
The value behind a raw pointer can't be determined at compile-time
|
||||
(or even link-time), which means it can't be used in a constant
|
||||
|
@ -137,16 +137,20 @@ enum CallKind {
|
||||
Direct(DefId),
|
||||
}
|
||||
|
||||
fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl {
|
||||
LocalDecl { mutability, ty, name: None, source_info: None }
|
||||
fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
|
||||
LocalDecl {
|
||||
mutability, ty, name: None,
|
||||
source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span },
|
||||
is_user_variable: false
|
||||
}
|
||||
}
|
||||
|
||||
fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
|
||||
fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span)
|
||||
-> IndexVec<Local, LocalDecl<'tcx>>
|
||||
{
|
||||
iter::once(temp_decl(Mutability::Mut, sig.output()))
|
||||
iter::once(temp_decl(Mutability::Mut, sig.output(), span))
|
||||
.chain(sig.inputs().iter().map(
|
||||
|ity| temp_decl(Mutability::Not, ity)))
|
||||
|ity| temp_decl(Mutability::Not, ity, span)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -188,7 +192,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
|
||||
),
|
||||
IndexVec::new(),
|
||||
sig.output(),
|
||||
local_decls_for_sig(&sig),
|
||||
local_decls_for_sig(&sig, span),
|
||||
sig.inputs().len(),
|
||||
vec![],
|
||||
span
|
||||
@ -297,7 +301,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
debug!("build_call_shim: sig={:?}", sig);
|
||||
|
||||
let mut local_decls = local_decls_for_sig(&sig);
|
||||
let mut local_decls = local_decls_for_sig(&sig, span);
|
||||
let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
|
||||
|
||||
let rcvr_arg = Local::new(1+0);
|
||||
@ -317,7 +321,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tcx.mk_ref(re_erased, ty::TypeAndMut {
|
||||
ty: sig.inputs()[0],
|
||||
mutbl: hir::Mutability::MutMutable
|
||||
})
|
||||
}),
|
||||
span
|
||||
));
|
||||
statements.push(Statement {
|
||||
source_info: source_info,
|
||||
@ -442,7 +447,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
||||
|
||||
debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
|
||||
|
||||
let local_decls = local_decls_for_sig(&sig);
|
||||
let local_decls = local_decls_for_sig(&sig, span);
|
||||
|
||||
let source_info = SourceInfo {
|
||||
span: span,
|
||||
|
@ -461,11 +461,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
for loc in callee_mir.vars_and_temps_iter() {
|
||||
let mut local = callee_mir.local_decls[loc].clone();
|
||||
|
||||
if let Some(ref mut source_info) = local.source_info {
|
||||
source_info.scope = scope_map[source_info.scope];
|
||||
|
||||
source_info.span = callsite.location.span;
|
||||
}
|
||||
local.source_info.scope = scope_map[local.source_info.scope];
|
||||
local.source_info.span = callsite.location.span;
|
||||
|
||||
let idx = caller_mir.local_decls.push(local);
|
||||
local_map.push(idx);
|
||||
@ -506,7 +503,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
|
||||
let ty = dest.ty(caller_mir, self.tcx);
|
||||
|
||||
let temp = LocalDecl::new_temp(ty);
|
||||
let temp = LocalDecl::new_temp(ty, callsite.location.span);
|
||||
|
||||
let tmp = caller_mir.local_decls.push(temp);
|
||||
let tmp = Lvalue::Local(tmp);
|
||||
@ -590,7 +587,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
arg.deref());
|
||||
|
||||
let ty = arg.ty(caller_mir, self.tcx);
|
||||
let ref_tmp = LocalDecl::new_temp(ty);
|
||||
let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span);
|
||||
let ref_tmp = caller_mir.local_decls.push(ref_tmp);
|
||||
let ref_tmp = Lvalue::Local(ref_tmp);
|
||||
|
||||
@ -611,7 +608,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
|
||||
let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty);
|
||||
|
||||
let cast_tmp = LocalDecl::new_temp(ptr_ty);
|
||||
let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span);
|
||||
let cast_tmp = caller_mir.local_decls.push(cast_tmp);
|
||||
let cast_tmp = Lvalue::Local(cast_tmp);
|
||||
|
||||
@ -645,7 +642,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
|
||||
let ty = arg.ty(caller_mir, tcx);
|
||||
|
||||
let arg_tmp = LocalDecl::new_temp(ty);
|
||||
let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span);
|
||||
let arg_tmp = caller_mir.local_decls.push(arg_tmp);
|
||||
let arg_tmp = Lvalue::Local(arg_tmp);
|
||||
|
||||
|
@ -208,7 +208,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
|
||||
let no_stmts = self.source[loc.block].statements.len();
|
||||
let new_temp = self.promoted.local_decls.push(
|
||||
LocalDecl::new_temp(self.source.local_decls[temp].ty));
|
||||
LocalDecl::new_temp(self.source.local_decls[temp].ty,
|
||||
self.source.local_decls[temp].source_info.span));
|
||||
|
||||
debug!("promote({:?} @ {:?}/{:?}, {:?})",
|
||||
temp, loc, no_stmts, self.keep_original);
|
||||
@ -379,7 +380,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
};
|
||||
|
||||
// Declare return pointer local
|
||||
let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect();
|
||||
let initial_locals = iter::once(LocalDecl::new_return_pointer(ty, span))
|
||||
.collect();
|
||||
|
||||
let mut promoter = Promoter {
|
||||
promoted: Mir::new(
|
||||
|
@ -881,7 +881,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
// Avoid a generic error for other uses of arguments.
|
||||
if self.qualif.intersects(Qualif::FN_ARGUMENT) {
|
||||
let decl = &self.mir.local_decls[index];
|
||||
span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
|
||||
span_err!(self.tcx.sess, decl.source_info.span, E0022,
|
||||
"arguments of constant functions can only \
|
||||
be immutable by-value bindings");
|
||||
return;
|
||||
|
@ -24,6 +24,7 @@ use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
|
||||
@ -87,6 +88,11 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
self.sanitize_type(rvalue, rval_ty);
|
||||
}
|
||||
|
||||
fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) {
|
||||
self.super_local_decl(local_decl);
|
||||
self.sanitize_type(local_decl, local_decl.ty);
|
||||
}
|
||||
|
||||
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
|
||||
self.sanitize_type(&"return type", mir.return_ty);
|
||||
for local_decl in &mir.local_decls {
|
||||
@ -317,6 +323,7 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
fulfillment_cx: traits::FulfillmentContext<'tcx>,
|
||||
last_span: Span,
|
||||
body_id: ast::NodeId,
|
||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
@ -326,6 +333,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
fulfillment_cx: traits::FulfillmentContext::new(),
|
||||
last_span: DUMMY_SP,
|
||||
body_id: body_id,
|
||||
reported_errors: FxHashSet(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -641,9 +649,43 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
|
||||
fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) {
|
||||
match mir.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||
// return values of normal functions are required to be
|
||||
// sized by typeck, but return values of ADT constructors are
|
||||
// not because we don't include a `Self: Sized` bounds on them.
|
||||
//
|
||||
// Unbound parts of arguments were never required to be Sized
|
||||
// - maybe we should make that a warning.
|
||||
return
|
||||
}
|
||||
LocalKind::Var | LocalKind::Temp => {}
|
||||
}
|
||||
|
||||
let span = local_decl.source_info.span;
|
||||
let ty = local_decl.ty;
|
||||
if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
|
||||
// in current MIR construction, all non-control-flow rvalue
|
||||
// expressions evaluate through `as_temp` or `into` a return
|
||||
// slot or local, so to find all unsized rvalues it is enough
|
||||
// to check all temps, return slots and locals.
|
||||
if let None = self.reported_errors.replace((ty, span)) {
|
||||
span_err!(self.tcx().sess, span, E0161,
|
||||
"cannot move a value of type {0}: the size of {0} \
|
||||
cannot be statically determined", ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
|
||||
self.last_span = mir.span;
|
||||
debug!("run_on_mir: {:?}", mir.span);
|
||||
|
||||
for (local, local_decl) in mir.local_decls.iter_enumerated() {
|
||||
self.check_local(mir, local, local_decl);
|
||||
}
|
||||
|
||||
for block in mir.basic_blocks() {
|
||||
for stmt in &block.statements {
|
||||
if stmt.source_info.span != DUMMY_SP {
|
||||
@ -698,16 +740,18 @@ impl TypeckMir {
|
||||
impl<'tcx> MirPass<'tcx> for TypeckMir {
|
||||
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
src: MirSource, mir: &mut Mir<'tcx>) {
|
||||
debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
|
||||
let item_id = src.item_id();
|
||||
let def_id = tcx.hir.local_def_id(item_id);
|
||||
debug!("run_pass: {}", tcx.item_path_str(def_id));
|
||||
|
||||
if tcx.sess.err_count() > 0 {
|
||||
// compiling a broken program can obviously result in a
|
||||
// broken MIR, so try not to report duplicate errors.
|
||||
return;
|
||||
}
|
||||
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
|
||||
let param_env = ty::ParameterEnvironment::for_item(tcx, item_id);
|
||||
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
|
||||
let mut checker = TypeChecker::new(&infcx, src.item_id());
|
||||
let mut checker = TypeChecker::new(&infcx, item_id);
|
||||
{
|
||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
||||
verifier.visit_mir(mir);
|
||||
|
@ -686,7 +686,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
}
|
||||
|
||||
fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
|
||||
self.elaborator.patch().new_temp(ty)
|
||||
self.elaborator.patch().new_temp(ty, self.source_info.span)
|
||||
}
|
||||
|
||||
fn terminator_loc(&mut self, bb: BasicBlock) -> Location {
|
||||
|
@ -11,6 +11,7 @@
|
||||
use rustc::ty::Ty;
|
||||
use rustc::mir::*;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use syntax_pos::Span;
|
||||
|
||||
/// This struct represents a patch to MIR, which can add
|
||||
/// new statements and basic blocks and patch over block
|
||||
@ -92,10 +93,10 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
|
||||
pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
|
||||
let index = self.next_local;
|
||||
self.next_local += 1;
|
||||
self.new_locals.push(LocalDecl::new_temp(ty));
|
||||
self.new_locals.push(LocalDecl::new_temp(ty, span));
|
||||
Local::new(index as usize)
|
||||
}
|
||||
|
||||
|
@ -196,8 +196,8 @@ fn write_scope_tree(tcx: TyCtxt,
|
||||
// User variable types (including the user's name in a comment).
|
||||
for local in mir.vars_iter() {
|
||||
let var = &mir.local_decls[local];
|
||||
let (name, source_info) = if var.source_info.unwrap().scope == child {
|
||||
(var.name.unwrap(), var.source_info.unwrap())
|
||||
let (name, source_info) = if var.source_info.scope == child {
|
||||
(var.name.unwrap(), var.source_info)
|
||||
} else {
|
||||
// Not a variable or not declared in this scope.
|
||||
continue;
|
||||
|
@ -82,39 +82,6 @@ extern {
|
||||
```
|
||||
"##,
|
||||
|
||||
E0161: r##"
|
||||
A value was moved. However, its size was not known at compile time, and only
|
||||
values of a known size can be moved.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<[isize]> = box *array;
|
||||
// error: cannot move a value of type [isize]: the size of [isize] cannot
|
||||
// be statically determined
|
||||
}
|
||||
```
|
||||
|
||||
In Rust, you can only move a value when its size is known at compile time.
|
||||
|
||||
To work around this restriction, consider "hiding" the value behind a reference:
|
||||
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
|
||||
it around as usual. Example:
|
||||
|
||||
```
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let array: &[isize] = &[1, 2, 3];
|
||||
let _x: Box<&[isize]> = box array; // ok!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0265: r##"
|
||||
This error indicates that a static or constant references itself.
|
||||
All statics and constants need to resolve to a value in an acyclic manner.
|
||||
|
@ -47,5 +47,4 @@ pub mod hir_stats;
|
||||
pub mod loops;
|
||||
pub mod mir_stats;
|
||||
pub mod no_asm;
|
||||
pub mod rvalues;
|
||||
pub mod static_recursion;
|
||||
|
@ -1,103 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// 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.
|
||||
|
||||
// Checks that all rvalues in a crate have statically known size. check_crate
|
||||
// is the public starting point.
|
||||
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::middle::expr_use_visitor as euv;
|
||||
use rustc::middle::mem_categorization as mc;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::traits::Reveal;
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
let mut rvcx = RvalueContext { tcx: tcx };
|
||||
tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor());
|
||||
}
|
||||
|
||||
struct RvalueContext<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
|
||||
let body = self.tcx.hir.body(body_id);
|
||||
self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
|
||||
let mut delegate = RvalueContextDelegate {
|
||||
tcx: infcx.tcx,
|
||||
param_env: &infcx.parameter_environment
|
||||
};
|
||||
euv::ExprUseVisitor::new(&mut delegate, &infcx).consume_body(body);
|
||||
});
|
||||
self.visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
struct RvalueContextDelegate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: &'a ty::ParameterEnvironment<'gcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tcx> {
|
||||
fn consume(&mut self,
|
||||
_: ast::NodeId,
|
||||
span: Span,
|
||||
cmt: mc::cmt<'tcx>,
|
||||
_: euv::ConsumeMode) {
|
||||
debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
|
||||
let ty = self.tcx.lift_to_global(&cmt.ty).unwrap();
|
||||
if !ty.is_sized(self.tcx.global_tcx(), self.param_env, span) {
|
||||
span_err!(self.tcx.sess, span, E0161,
|
||||
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
|
||||
ty);
|
||||
}
|
||||
}
|
||||
|
||||
fn matched_pat(&mut self,
|
||||
_matched_pat: &hir::Pat,
|
||||
_cmt: mc::cmt,
|
||||
_mode: euv::MatchMode) {}
|
||||
|
||||
fn consume_pat(&mut self,
|
||||
_consume_pat: &hir::Pat,
|
||||
_cmt: mc::cmt,
|
||||
_mode: euv::ConsumeMode) {
|
||||
}
|
||||
|
||||
fn borrow(&mut self,
|
||||
_borrow_id: ast::NodeId,
|
||||
_borrow_span: Span,
|
||||
_cmt: mc::cmt,
|
||||
_loan_region: &'tcx ty::Region,
|
||||
_bk: ty::BorrowKind,
|
||||
_loan_cause: euv::LoanCause) {
|
||||
}
|
||||
|
||||
fn decl_without_init(&mut self,
|
||||
_id: ast::NodeId,
|
||||
_span: Span) {
|
||||
}
|
||||
|
||||
fn mutate(&mut self,
|
||||
_assignment_id: ast::NodeId,
|
||||
_assignment_span: Span,
|
||||
_assignee_cmt: mc::cmt,
|
||||
_mode: euv::MutateMode) {
|
||||
}
|
||||
}
|
@ -65,7 +65,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
|
||||
let mut has_variables = BitVector::new(mir.visibility_scopes.len());
|
||||
for var in mir.vars_iter() {
|
||||
let decl = &mir.local_decls[var];
|
||||
has_variables.insert(decl.source_info.unwrap().scope.index());
|
||||
has_variables.insert(decl.source_info.scope.index());
|
||||
}
|
||||
|
||||
// Instantiate all scopes.
|
||||
|
@ -255,8 +255,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
|
||||
|
||||
if let Some(name) = decl.name {
|
||||
// User variable
|
||||
let source_info = decl.source_info.unwrap();
|
||||
let debug_scope = mircx.scopes[source_info.scope];
|
||||
let debug_scope = mircx.scopes[decl.source_info.scope];
|
||||
let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
|
||||
|
||||
if !lvalue_locals.contains(local.index()) && !dbg {
|
||||
@ -268,7 +267,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
|
||||
assert!(!ty.has_erasable_regions());
|
||||
let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
|
||||
if dbg {
|
||||
let (scope, span) = mircx.debug_loc(source_info);
|
||||
let (scope, span) = mircx.debug_loc(decl.source_info);
|
||||
declare_local(&bcx, &mircx.debug_context, name, ty, scope,
|
||||
VariableAccess::DirectVariable { alloca: lvalue.llval },
|
||||
VariableKind::LocalVariable, span);
|
||||
|
18
src/test/compile-fail/issue-41139.rs
Normal file
18
src/test/compile-fail/issue-41139.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// 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.
|
||||
|
||||
trait Trait {}
|
||||
|
||||
fn get_function<'a>() -> &'a Fn() -> Trait { panic!("") }
|
||||
|
||||
fn main() {
|
||||
let t : &Trait = &get_function()();
|
||||
//~^ ERROR cannot move a value of type Trait + 'static
|
||||
}
|
Loading…
Reference in New Issue
Block a user