Skip to content

Commit 0144613

Browse files
committed
Move rvalue checking to MIR
Fixes #41139.
1 parent 384ec80 commit 0144613

File tree

7 files changed

+97
-147
lines changed

7 files changed

+97
-147
lines changed

src/librustc_driver/driver.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use rustc_typeck as typeck;
3535
use rustc_privacy;
3636
use rustc_plugin::registry::Registry;
3737
use rustc_plugin as plugin;
38-
use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues,
38+
use rustc_passes::{ast_validation, no_asm, loops, consts,
3939
static_recursion, hir_stats, mir_stats};
4040
use rustc_const_eval::check_match;
4141
use super::Compilation;
@@ -957,10 +957,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
957957
"liveness checking",
958958
|| middle::liveness::check_crate(tcx));
959959

960-
time(time_passes,
961-
"rvalue checking",
962-
|| rvalues::check_crate(tcx));
963-
964960
time(time_passes,
965961
"MIR dump",
966962
|| 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,
976972
// in stage 4 below.
977973
passes.push_hook(box mir::transform::dump_mir::DumpMir);
978974
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
979-
passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
980975
passes.push_pass(box mir::transform::type_check::TypeckMir);
976+
passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
981977
passes.push_pass(
982978
box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
983979
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts"));

src/librustc_mir/diagnostics.rs

+33
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,39 @@ let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) };
244244
```
245245
"##,
246246

247+
E0161: r##"
248+
A value was moved. However, its size was not known at compile time, and only
249+
values of a known size can be moved.
250+
251+
Erroneous code example:
252+
253+
```compile_fail
254+
#![feature(box_syntax)]
255+
256+
fn main() {
257+
let array: &[isize] = &[1, 2, 3];
258+
let _x: Box<[isize]> = box *array;
259+
// error: cannot move a value of type [isize]: the size of [isize] cannot
260+
// be statically determined
261+
}
262+
```
263+
264+
In Rust, you can only move a value when its size is known at compile time.
265+
266+
To work around this restriction, consider "hiding" the value behind a reference:
267+
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
268+
it around as usual. Example:
269+
270+
```
271+
#![feature(box_syntax)]
272+
273+
fn main() {
274+
let array: &[isize] = &[1, 2, 3];
275+
let _x: Box<&[isize]> = box array; // ok!
276+
}
277+
```
278+
"##,
279+
247280
E0396: r##"
248281
The value behind a raw pointer can't be determined at compile-time
249282
(or even link-time), which means it can't be used in a constant

src/librustc_mir/transform/type_check.rs

+44-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use std::fmt;
2424
use syntax::ast;
2525
use syntax_pos::{Span, DUMMY_SP};
2626

27+
use rustc_data_structures::fx::FxHashSet;
2728
use rustc_data_structures::indexed_vec::Idx;
2829

2930
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> {
8788
self.sanitize_type(rvalue, rval_ty);
8889
}
8990

91+
fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) {
92+
self.super_local_decl(local_decl);
93+
self.sanitize_type(local_decl, local_decl.ty);
94+
}
95+
9096
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
9197
self.sanitize_type(&"return type", mir.return_ty);
9298
for local_decl in &mir.local_decls {
@@ -317,6 +323,7 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
317323
fulfillment_cx: traits::FulfillmentContext<'tcx>,
318324
last_span: Span,
319325
body_id: ast::NodeId,
326+
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
320327
}
321328

322329
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
@@ -326,6 +333,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
326333
fulfillment_cx: traits::FulfillmentContext::new(),
327334
last_span: DUMMY_SP,
328335
body_id: body_id,
336+
reported_errors: FxHashSet(),
329337
}
330338
}
331339

@@ -641,9 +649,39 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
641649
}
642650
}
643651

644-
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
652+
fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) {
653+
match mir.local_kind(local) {
654+
LocalKind::ReturnPointer | LocalKind::Arg => {
655+
// return values of normal functions are required to be
656+
// sized by typeck, but return values of ADT constructors are
657+
// not because we don't include a `Self: Sized` bounds on them.
658+
//
659+
// Unbound parts of arguments were never required to be Sized
660+
// - maybe we should make that a warning.
661+
return
662+
}
663+
LocalKind::Var | LocalKind::Temp => {}
664+
}
665+
666+
let span = local_decl.source_info.span;
667+
let ty = local_decl.ty;
668+
if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
669+
if let None = self.reported_errors.replace((ty, span)) {
670+
span_err!(self.tcx().sess, span, E0161,
671+
"cannot move a value of type {0}: the size of {0} \
672+
cannot be statically determined", ty);
673+
}
674+
}
675+
}
676+
677+
fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
645678
self.last_span = mir.span;
646679
debug!("run_on_mir: {:?}", mir.span);
680+
681+
for (local, local_decl) in mir.local_decls.iter_enumerated() {
682+
self.check_local(mir, local, local_decl);
683+
}
684+
647685
for block in mir.basic_blocks() {
648686
for stmt in &block.statements {
649687
if stmt.source_info.span != DUMMY_SP {
@@ -698,16 +736,18 @@ impl TypeckMir {
698736
impl<'tcx> MirPass<'tcx> for TypeckMir {
699737
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
700738
src: MirSource, mir: &mut Mir<'tcx>) {
701-
debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
739+
let item_id = src.item_id();
740+
let def_id = tcx.hir.local_def_id(item_id);
741+
debug!("run_pass: {}", tcx.item_path_str(def_id));
702742

703743
if tcx.sess.err_count() > 0 {
704744
// compiling a broken program can obviously result in a
705745
// broken MIR, so try not to report duplicate errors.
706746
return;
707747
}
708-
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
748+
let param_env = ty::ParameterEnvironment::for_item(tcx, item_id);
709749
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
710-
let mut checker = TypeChecker::new(&infcx, src.item_id());
750+
let mut checker = TypeChecker::new(&infcx, item_id);
711751
{
712752
let mut verifier = TypeVerifier::new(&mut checker, mir);
713753
verifier.visit_mir(mir);

src/librustc_passes/diagnostics.rs

-33
Original file line numberDiff line numberDiff line change
@@ -82,39 +82,6 @@ extern {
8282
```
8383
"##,
8484

85-
E0161: r##"
86-
A value was moved. However, its size was not known at compile time, and only
87-
values of a known size can be moved.
88-
89-
Erroneous code example:
90-
91-
```compile_fail
92-
#![feature(box_syntax)]
93-
94-
fn main() {
95-
let array: &[isize] = &[1, 2, 3];
96-
let _x: Box<[isize]> = box *array;
97-
// error: cannot move a value of type [isize]: the size of [isize] cannot
98-
// be statically determined
99-
}
100-
```
101-
102-
In Rust, you can only move a value when its size is known at compile time.
103-
104-
To work around this restriction, consider "hiding" the value behind a reference:
105-
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
106-
it around as usual. Example:
107-
108-
```
109-
#![feature(box_syntax)]
110-
111-
fn main() {
112-
let array: &[isize] = &[1, 2, 3];
113-
let _x: Box<&[isize]> = box array; // ok!
114-
}
115-
```
116-
"##,
117-
11885
E0265: r##"
11986
This error indicates that a static or constant references itself.
12087
All statics and constants need to resolve to a value in an acyclic manner.

src/librustc_passes/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,4 @@ pub mod hir_stats;
4747
pub mod loops;
4848
pub mod mir_stats;
4949
pub mod no_asm;
50-
pub mod rvalues;
5150
pub mod static_recursion;

src/librustc_passes/rvalues.rs

-103
This file was deleted.

src/test/compile-fail/issue-41139.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Trait {}
12+
13+
fn get_function<'a>() -> &'a Fn() -> Trait { panic!("") }
14+
15+
fn main() {
16+
let t : &Trait = &get_function()();
17+
//~^ ERROR cannot move a value of type Trait + 'static
18+
}

0 commit comments

Comments
 (0)