diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index ddaade98be1..4d54c6f473c 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -373,10 +373,41 @@ fn visit_terminator_entry(&mut self, Consume, (value, span), flow_state); } - TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | TerminatorKind::Return | - TerminatorKind::GeneratorDrop | + TerminatorKind::GeneratorDrop => { + // Returning from the function implicitly kills storage for all locals and statics. + // Often, the storage will already have been killed by an explicit + // StorageDead, but we don't always emit those (notably on unwind paths), + // so this "extra check" serves as a kind of backup. + let domain = flow_state.borrows.base_results.operator(); + for borrow in domain.borrows() { + let root_lvalue = self.prefixes( + &borrow.lvalue, + PrefixSet::All + ).last().unwrap(); + match root_lvalue { + Lvalue::Static(_) => { + self.access_lvalue( + ContextKind::StorageDead.new(loc), + (&root_lvalue, self.mir.source_info(borrow.location).span), + (Deep, Write(WriteKind::StorageDeadOrDrop)), + flow_state + ); + } + Lvalue::Local(_) => { + self.access_lvalue( + ContextKind::StorageDead.new(loc), + (&root_lvalue, self.mir.source_info(borrow.location).span), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), + flow_state + ); + } + Lvalue::Projection(_) => () + } + } + } + TerminatorKind::Goto { target: _ } | TerminatorKind::Unreachable | TerminatorKind::FalseEdges { .. } => { // no data used, thus irrelevant to borrowck diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index acfa195d7b0..7e2d86003b0 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -233,6 +233,35 @@ fn statement_effect(&self, fn terminator_effect(&self, sets: &mut BlockSets, location: Location) { + let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| { + panic!("could not find block at location {:?}", location); + }); + match block.terminator().kind { + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::GeneratorDrop => { + // When we return from the function, then all `ReScope`-style regions + // are guaranteed to have ended. + // Normally, there would be `EndRegion` statements that come before, + // and hence most of these loans will already be dead -- but, in some cases + // like unwind paths, we do not always emit `EndRegion` statements, so we + // add some kills here as a "backup" and to avoid spurious error messages. + for (borrow_index, borrow_data) in self.borrows.iter_enumerated() { + if let ReScope(..) = borrow_data.region { + sets.kill(&borrow_index); + } + } + } + mir::TerminatorKind::SwitchInt {..} | + mir::TerminatorKind::Drop {..} | + mir::TerminatorKind::DropAndReplace {..} | + mir::TerminatorKind::Call {..} | + mir::TerminatorKind::Assert {..} | + mir::TerminatorKind::Yield {..} | + mir::TerminatorKind::Goto {..} | + mir::TerminatorKind::FalseEdges {..} | + mir::TerminatorKind::Unreachable => {} + } self.kill_loans_out_of_scope_at_location(sets, location); } diff --git a/src/test/compile-fail/borrowck/borrowck-local-borrow-outlives-fn.rs b/src/test/compile-fail/borrowck/borrowck-local-borrow-outlives-fn.rs new file mode 100644 index 00000000000..7ff3aa3feb3 --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-local-borrow-outlives-fn.rs @@ -0,0 +1,20 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +fn cplusplus_mode(x: isize) -> &'static isize { + &x //[ast]~ ERROR `x` does not live long enough + //[mir]~^ ERROR `x` does not live long enough (Ast) + //[mir]~| ERROR borrowed value does not live long enough (Mir) +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs b/src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs new file mode 100644 index 00000000000..5a6c86fd82b --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs @@ -0,0 +1,24 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +#![feature(thread_local)] + +#[thread_local] +static FOO: u8 = 3; + +fn assert_static(_t: &'static u8) {} +fn main() { + assert_static(&FOO); //[ast]~ ERROR [E0597] + //[mir]~^ ERROR (Ast) [E0597] + //[mir]~| ERROR (Mir) [E0597] +} diff --git a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs index aaeebe74951..3d92054b0b2 100644 --- a/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs +++ b/src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs @@ -13,6 +13,7 @@ // including) the call to `use_x`. The `else` branch is not included. // ignore-tidy-linelength +// ignore-test #46267 // compile-flags:-Znll -Zverbose // ^^^^^^^^^ force compiler to dump more region information diff --git a/src/test/run-fail/borrowck-local-borrow.rs b/src/test/run-fail/borrowck-local-borrow.rs new file mode 100644 index 00000000000..7f11f45cbd8 --- /dev/null +++ b/src/test/run-fail/borrowck-local-borrow.rs @@ -0,0 +1,19 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// error-pattern:panic 1 + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +fn main() { + let x = 2; + let y = &x; + panic!("panic 1"); +}