-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #24021 - pnkfelix:fn-params-outlive-body, r=nikomatsakis
Encode more precise scoping rules for function params Function params outlive everything in the body (incl temporaries). Thus if we assign them their own `CodeExtent`, the region inference can properly show that it is sound to have temporaries with destructors that reference the parameters (because such temporaries will be dropped before the parameters are dropped). Fix #23338
- Loading branch information
Showing
7 changed files
with
301 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright 2015 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. | ||
|
||
// This is just checking that we still reject code where temp values | ||
// are borrowing values for longer than they will be around. | ||
// | ||
// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs | ||
|
||
use std::cell::RefCell; | ||
|
||
fn foo(x: RefCell<String>) -> String { | ||
let y = x; | ||
y.borrow().clone() //~ ERROR `y` does not live long enough | ||
} | ||
|
||
fn foo2(x: RefCell<String>) -> String { | ||
let ret = { | ||
let y = x; | ||
y.borrow().clone() //~ ERROR `y` does not live long enough | ||
}; | ||
ret | ||
} | ||
|
||
fn main() { | ||
let r = RefCell::new(format!("data")); | ||
assert_eq!(foo(r), "data"); | ||
let r = RefCell::new(format!("data")); | ||
assert_eq!(foo2(r), "data"); | ||
} |
171 changes: 171 additions & 0 deletions
171
src/test/run-pass/issue-23338-ensure-param-drop-order.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
// Copyright 2015 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. | ||
|
||
// ignore-pretty : (#23623) problems when ending with // comments | ||
|
||
// This test is ensuring that parameters are indeed dropped after | ||
// temporaries in a fn body. | ||
|
||
use std::cell::RefCell; | ||
|
||
use self::d::D; | ||
|
||
pub fn main() { | ||
let log = RefCell::new(vec![]); | ||
d::println(&format!("created empty log")); | ||
test(&log); | ||
|
||
assert_eq!(&log.borrow()[..], | ||
[ | ||
// created empty log | ||
// +-- Make D(da_0, 0) | ||
// | +-- Make D(de_1, 1) | ||
// | | calling foo | ||
// | | entered foo | ||
// | | +-- Make D(de_2, 2) | ||
// | | | +-- Make D(da_1, 3) | ||
// | | | | +-- Make D(de_3, 4) | ||
// | | | | | +-- Make D(de_4, 5) | ||
3, // | | | +-- Drop D(da_1, 3) | ||
// | | | | | | ||
4, // | | | +-- Drop D(de_3, 4) | ||
// | | | | | ||
// | | | | eval tail of foo | ||
// | | | +-- Make D(de_5, 6) | ||
// | | | | +-- Make D(de_6, 7) | ||
6, // | | | +-- Drop D(de_5, 6) | ||
// | | | | | | ||
5, // | | | | +-- Drop D(de_4, 5) | ||
// | | | | | ||
2, // | | +-- Drop D(de_2, 2) | ||
// | | | | ||
1, // | +-- Drop D(de_1, 1) | ||
// | | | ||
0, // +-- Drop D(da_0, 0) | ||
// | | ||
// | result D(de_6, 7) | ||
7 // +-- Drop D(de_6, 7) | ||
|
||
]); | ||
} | ||
|
||
fn test<'a>(log: d::Log<'a>) { | ||
let da = D::new("da", 0, log); | ||
let de = D::new("de", 1, log); | ||
d::println(&format!("calling foo")); | ||
let result = foo(da, de); | ||
d::println(&format!("result {}", result)); | ||
} | ||
|
||
fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> { | ||
d::println(&format!("entered foo")); | ||
let de2 = de1.incr(); // creates D(de_2, 2) | ||
let de4 = { | ||
let _da1 = da0.incr(); // creates D(da_1, 3) | ||
de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) | ||
}; | ||
d::println(&format!("eval tail of foo")); | ||
de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) | ||
} | ||
|
||
// This module provides simultaneous printouts of the dynamic extents | ||
// of all of the D values, in addition to logging the order that each | ||
// is dropped. | ||
|
||
const PREF_INDENT: u32 = 16; | ||
|
||
pub mod d { | ||
#![allow(unused_parens)] | ||
use std::fmt; | ||
use std::mem; | ||
use std::cell::RefCell; | ||
|
||
static mut counter: u32 = 0; | ||
static mut trails: u64 = 0; | ||
|
||
pub type Log<'a> = &'a RefCell<Vec<u32>>; | ||
|
||
pub fn current_width() -> u32 { | ||
unsafe { max_width() - trails.leading_zeros() } | ||
} | ||
|
||
pub fn max_width() -> u32 { | ||
unsafe { | ||
(mem::size_of_val(&trails)*8) as u32 | ||
} | ||
} | ||
|
||
pub fn indent_println(my_trails: u32, s: &str) { | ||
let mut indent: String = String::new(); | ||
for i in 0..my_trails { | ||
unsafe { | ||
if trails & (1 << i) != 0 { | ||
indent = indent + "| "; | ||
} else { | ||
indent = indent + " "; | ||
} | ||
} | ||
} | ||
println!("{}{}", indent, s); | ||
} | ||
|
||
pub fn println(s: &str) { | ||
indent_println(super::PREF_INDENT, s); | ||
} | ||
|
||
fn first_avail() -> u32 { | ||
unsafe { | ||
for i in 0..64 { | ||
if trails & (1 << i) == 0 { | ||
return i; | ||
} | ||
} | ||
} | ||
panic!("exhausted trails"); | ||
} | ||
|
||
pub struct D<'a> { | ||
name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a> | ||
} | ||
|
||
impl<'a> fmt::Display for D<'a> { | ||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { | ||
write!(w, "D({}_{}, {})", self.name, self.i, self.uid) | ||
} | ||
} | ||
|
||
impl<'a> D<'a> { | ||
pub fn new(name: &'static str, i: u32, log: Log<'a>) -> D<'a> { | ||
unsafe { | ||
let trail = first_avail(); | ||
let ctr = counter; | ||
counter += 1; | ||
trails |= (1 << trail); | ||
let ret = D { | ||
name: name, i: i, log: log, uid: ctr, trail: trail | ||
}; | ||
indent_println(trail, &format!("+-- Make {}", ret)); | ||
ret | ||
} | ||
} | ||
pub fn incr(&self) -> D<'a> { | ||
D::new(self.name, self.i + 1, self.log) | ||
} | ||
} | ||
|
||
impl<'a> Drop for D<'a> { | ||
fn drop(&mut self) { | ||
unsafe { trails &= !(1 << self.trail); }; | ||
self.log.borrow_mut().push(self.uid); | ||
indent_println(self.trail, &format!("+-- Drop {}", self)); | ||
indent_println(::PREF_INDENT, ""); | ||
} | ||
} | ||
} |
Oops, something went wrong.