mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 17:24:06 +00:00
parent
384ec80d2b
commit
0144613078
@ -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;
|
||||
@ -957,10 +957,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));
|
||||
@ -976,8 +972,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"));
|
||||
|
@ -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
|
||||
|
@ -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,39 @@ 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) {
|
||||
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 +736,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);
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
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