Skip to content

Commit 0e06f71

Browse files
committed
auto merge of #18234 : pnkfelix/rust/fsk-type-fragments-for-needsdrop-2, r=nikomatsakis
Code to fragment paths into pieces based on subparts being moved around, e.g. moving `x.1` out of a tuple `(A,B,C)` leaves behind the fragments `x.0: A` and `x.2: C`. Further discussion in borrowck/doc.rs. Includes differentiation between assigned_fragments and moved_fragments, support for all-but-one array fragments, and instrumentation to print out the moved/assigned/unmmoved/parents for each function, factored out into a separate submodule. These fragments can then be used by `trans` to inject stack-local dynamic drop flags. (They also can be hooked up with dataflow to reduce the expected number of injected flags.)
2 parents 48ca6d1 + 5fbe0ca commit 0e06f71

32 files changed

+2189
-255
lines changed

src/compiletest/errors.rs

+56-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
10+
use self::WhichLine::*;
1011

1112
use std::ascii::AsciiExt;
1213
use std::io::{BufferedReader, File};
@@ -18,28 +19,74 @@ pub struct ExpectedError {
1819
pub msg: String,
1920
}
2021

21-
pub static EXPECTED_PATTERN : &'static str = r"//~(?P<adjusts>\^*)\s*(?P<kind>\S*)\s*(?P<msg>.*)";
22+
/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
23+
/// The former is a "follow" that inherits its target from the preceding line;
24+
/// the latter is an "adjusts" that goes that many lines up.
25+
///
26+
/// Goal is to enable tests both like: //~^^^ ERROR go up three
27+
/// and also //~^ ERROR message one for the preceding line, and
28+
/// //~| ERROR message two for that same line.
29+
30+
pub static EXPECTED_PATTERN : &'static str =
31+
r"//~(?P<follow>\|)?(?P<adjusts>\^*)\s*(?P<kind>\S*)\s*(?P<msg>.*)";
32+
33+
#[deriving(PartialEq, Show)]
34+
enum WhichLine { ThisLine, FollowPrevious(uint), AdjustBackward(uint) }
2235

2336
// Load any test directives embedded in the file
2437
pub fn load_errors(re: &Regex, testfile: &Path) -> Vec<ExpectedError> {
2538
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
2639

40+
// `last_nonfollow_error` tracks the most recently seen
41+
// line with an error template that did not use the
42+
// follow-syntax, "//~| ...".
43+
//
44+
// (pnkfelix could not find an easy way to compose Iterator::scan
45+
// and Iterator::filter_map to pass along this information into
46+
// `parse_expected`. So instead I am storing that state here and
47+
// updating it in the map callback below.)
48+
let mut last_nonfollow_error = None;
49+
2750
rdr.lines().enumerate().filter_map(|(line_no, ln)| {
28-
parse_expected(line_no + 1, ln.unwrap().as_slice(), re)
51+
parse_expected(last_nonfollow_error,
52+
line_no + 1,
53+
ln.unwrap().as_slice(), re)
54+
.map(|(which, error)| {
55+
match which {
56+
FollowPrevious(_) => {}
57+
_ => last_nonfollow_error = Some(error.line),
58+
}
59+
error
60+
})
2961
}).collect()
3062
}
3163

32-
fn parse_expected(line_num: uint, line: &str, re: &Regex) -> Option<ExpectedError> {
64+
fn parse_expected(last_nonfollow_error: Option<uint>,
65+
line_num: uint,
66+
line: &str,
67+
re: &Regex) -> Option<(WhichLine, ExpectedError)> {
3368
re.captures(line).and_then(|caps| {
3469
let adjusts = caps.name("adjusts").len();
3570
let kind = caps.name("kind").to_ascii_lower();
3671
let msg = caps.name("msg").trim().to_string();
72+
let follow = caps.name("follow").len() > 0;
73+
74+
let (which, line) = if follow {
75+
assert!(adjusts == 0, "use either //~| or //~^, not both.");
76+
let line = last_nonfollow_error.unwrap_or_else(|| {
77+
panic!("encountered //~| without preceding //~^ line.")
78+
});
79+
(FollowPrevious(line), line)
80+
} else {
81+
let which =
82+
if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine };
83+
let line = line_num - adjusts;
84+
(which, line)
85+
};
3786

38-
debug!("line={} kind={} msg={}", line_num, kind, msg);
39-
Some(ExpectedError {
40-
line: line_num - adjusts,
41-
kind: kind,
42-
msg: msg,
43-
})
87+
debug!("line={} which={} kind={} msg={}", line_num, which, kind, msg);
88+
Some((which, ExpectedError { line: line,
89+
kind: kind,
90+
msg: msg, }))
4491
})
4592
}

src/librustc/middle/borrowck/check_loans.rs

+56-41
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use self::UseError::*;
2020

2121
use middle::borrowck::*;
22+
use middle::borrowck::LoanPathElem::*;
23+
use middle::borrowck::LoanPathKind::*;
2224
use middle::expr_use_visitor as euv;
2325
use middle::mem_categorization as mc;
2426
use middle::region;
@@ -33,49 +35,51 @@ use std::rc::Rc;
3335
// be less precise in its handling of Box while still allowing moves out of a
3436
// Box. They should be removed when OwnedPtr is removed from LoanPath.
3537

36-
fn owned_ptr_base_path<'a>(loan_path: &'a LoanPath) -> &'a LoanPath {
38+
fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<'tcx> {
3739
//! Returns the base of the leftmost dereference of an OwnedPtr in
3840
//! `loan_path`. If there is no dereference of an OwnedPtr in `loan_path`,
3941
//! then it just returns `loan_path` itself.
4042
41-
return match owned_ptr_base_path_helper(loan_path) {
43+
return match helper(loan_path) {
4244
Some(new_loan_path) => new_loan_path,
4345
None => loan_path.clone()
4446
};
4547

46-
fn owned_ptr_base_path_helper<'a>(loan_path: &'a LoanPath) -> Option<&'a LoanPath> {
47-
match *loan_path {
48+
fn helper<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> Option<&'a LoanPath<'tcx>> {
49+
match loan_path.kind {
4850
LpVar(_) | LpUpvar(_) => None,
4951
LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => {
50-
match owned_ptr_base_path_helper(&**lp_base) {
52+
match helper(&**lp_base) {
5153
v @ Some(_) => v,
5254
None => Some(&**lp_base)
5355
}
5456
}
55-
LpExtend(ref lp_base, _, _) => owned_ptr_base_path_helper(&**lp_base)
57+
LpDowncast(ref lp_base, _) |
58+
LpExtend(ref lp_base, _, _) => helper(&**lp_base)
5659
}
5760
}
5861
}
5962

60-
fn owned_ptr_base_path_rc(loan_path: &Rc<LoanPath>) -> Rc<LoanPath> {
63+
fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Rc<LoanPath<'tcx>> {
6164
//! The equivalent of `owned_ptr_base_path` for an &Rc<LoanPath> rather than
6265
//! a &LoanPath.
6366
64-
return match owned_ptr_base_path_helper(loan_path) {
67+
return match helper(loan_path) {
6568
Some(new_loan_path) => new_loan_path,
6669
None => loan_path.clone()
6770
};
6871

69-
fn owned_ptr_base_path_helper(loan_path: &Rc<LoanPath>) -> Option<Rc<LoanPath>> {
70-
match **loan_path {
72+
fn helper<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Option<Rc<LoanPath<'tcx>>> {
73+
match loan_path.kind {
7174
LpVar(_) | LpUpvar(_) => None,
7275
LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => {
73-
match owned_ptr_base_path_helper(lp_base) {
76+
match helper(lp_base) {
7477
v @ Some(_) => v,
7578
None => Some(lp_base.clone())
7679
}
7780
}
78-
LpExtend(ref lp_base, _, _) => owned_ptr_base_path_helper(lp_base)
81+
LpDowncast(ref lp_base, _) |
82+
LpExtend(ref lp_base, _, _) => helper(lp_base)
7983
}
8084
}
8185
}
@@ -84,7 +88,7 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> {
8488
bccx: &'a BorrowckCtxt<'a, 'tcx>,
8589
dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
8690
move_data: move_data::FlowedMoveData<'a, 'tcx>,
87-
all_loans: &'a [Loan],
91+
all_loans: &'a [Loan<'tcx>],
8892
}
8993

9094
impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
@@ -99,6 +103,11 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
99103
self.consume_common(consume_id, consume_span, cmt, mode);
100104
}
101105

106+
fn matched_pat(&mut self,
107+
_matched_pat: &ast::Pat,
108+
_cmt: mc::cmt,
109+
_mode: euv::MatchMode) { }
110+
102111
fn consume_pat(&mut self,
103112
consume_pat: &ast::Pat,
104113
cmt: mc::cmt<'tcx>,
@@ -183,7 +192,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
183192
pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
184193
dfcx_loans: &LoanDataFlow<'b, 'tcx>,
185194
move_data: move_data::FlowedMoveData<'c, 'tcx>,
186-
all_loans: &[Loan],
195+
all_loans: &[Loan<'tcx>],
187196
decl: &ast::FnDecl,
188197
body: &ast::Block) {
189198
debug!("check_loans(body id={})", body.id);
@@ -202,9 +211,9 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
202211
}
203212

204213
#[deriving(PartialEq)]
205-
enum UseError {
214+
enum UseError<'tcx> {
206215
UseOk,
207-
UseWhileBorrowed(/*loan*/Rc<LoanPath>, /*loan*/Span)
216+
UseWhileBorrowed(/*loan*/Rc<LoanPath<'tcx>>, /*loan*/Span)
208217
}
209218

210219
fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
@@ -216,7 +225,7 @@ fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
216225
impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
217226
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.bccx.tcx }
218227

219-
pub fn each_issued_loan(&self, scope: region::CodeExtent, op: |&Loan| -> bool)
228+
pub fn each_issued_loan(&self, scope: region::CodeExtent, op: |&Loan<'tcx>| -> bool)
220229
-> bool {
221230
//! Iterates over each loan that has been issued
222231
//! on entrance to `scope`, regardless of whether it is
@@ -232,7 +241,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
232241

233242
pub fn each_in_scope_loan(&self,
234243
scope: region::CodeExtent,
235-
op: |&Loan| -> bool)
244+
op: |&Loan<'tcx>| -> bool)
236245
-> bool {
237246
//! Like `each_issued_loan()`, but only considers loans that are
238247
//! currently in scope.
@@ -249,8 +258,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
249258

250259
fn each_in_scope_loan_affecting_path(&self,
251260
scope: region::CodeExtent,
252-
loan_path: &LoanPath,
253-
op: |&Loan| -> bool)
261+
loan_path: &LoanPath<'tcx>,
262+
op: |&Loan<'tcx>| -> bool)
254263
-> bool {
255264
//! Iterates through all of the in-scope loans affecting `loan_path`,
256265
//! calling `op`, and ceasing iteration if `false` is returned.
@@ -294,10 +303,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
294303

295304
let mut loan_path = loan_path;
296305
loop {
297-
match *loan_path {
306+
match loan_path.kind {
298307
LpVar(_) | LpUpvar(_) => {
299308
break;
300309
}
310+
LpDowncast(ref lp_base, _) |
301311
LpExtend(ref lp_base, _, _) => {
302312
loan_path = &**lp_base;
303313
}
@@ -363,8 +373,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
363373
}
364374

365375
pub fn report_error_if_loans_conflict(&self,
366-
old_loan: &Loan,
367-
new_loan: &Loan) {
376+
old_loan: &Loan<'tcx>,
377+
new_loan: &Loan<'tcx>) {
368378
//! Checks whether `old_loan` and `new_loan` can safely be issued
369379
//! simultaneously.
370380
@@ -383,10 +393,10 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
383393
}
384394

385395
pub fn report_error_if_loan_conflicts_with_restriction(&self,
386-
loan1: &Loan,
387-
loan2: &Loan,
388-
old_loan: &Loan,
389-
new_loan: &Loan)
396+
loan1: &Loan<'tcx>,
397+
loan2: &Loan<'tcx>,
398+
old_loan: &Loan<'tcx>,
399+
new_loan: &Loan<'tcx>)
390400
-> bool {
391401
//! Checks whether the restrictions introduced by `loan1` would
392402
//! prohibit `loan2`. Returns false if an error is reported.
@@ -549,7 +559,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
549559
true
550560
}
551561

552-
fn is_local_variable_or_arg(&self, cmt: mc::cmt) -> bool {
562+
fn is_local_variable_or_arg(&self, cmt: mc::cmt<'tcx>) -> bool {
553563
match cmt.cat {
554564
mc::cat_local(_) => true,
555565
_ => false
@@ -559,7 +569,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
559569
fn consume_common(&self,
560570
id: ast::NodeId,
561571
span: Span,
562-
cmt: mc::cmt,
572+
cmt: mc::cmt<'tcx>,
563573
mode: euv::ConsumeMode) {
564574
match opt_loan_path(&cmt) {
565575
Some(lp) => {
@@ -600,7 +610,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
600610
fn check_for_copy_of_frozen_path(&self,
601611
id: ast::NodeId,
602612
span: Span,
603-
copy_path: &LoanPath) {
613+
copy_path: &LoanPath<'tcx>) {
604614
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
605615
UseOk => { }
606616
UseWhileBorrowed(loan_path, loan_span) => {
@@ -621,7 +631,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
621631
fn check_for_move_of_borrowed_path(&self,
622632
id: ast::NodeId,
623633
span: Span,
624-
move_path: &LoanPath,
634+
move_path: &LoanPath<'tcx>,
625635
move_kind: move_data::MoveKind) {
626636
// We want to detect if there are any loans at all, so we search for
627637
// any loans incompatible with MutBorrrow, since all other kinds of
@@ -652,9 +662,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
652662

653663
pub fn analyze_restrictions_on_use(&self,
654664
expr_id: ast::NodeId,
655-
use_path: &LoanPath,
665+
use_path: &LoanPath<'tcx>,
656666
borrow_kind: ty::BorrowKind)
657-
-> UseError {
667+
-> UseError<'tcx> {
658668
debug!("analyze_restrictions_on_use(expr_id={}, use_path={})",
659669
self.tcx().map.node_to_string(expr_id),
660670
use_path.repr(self.tcx()));
@@ -678,7 +688,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
678688
id: ast::NodeId,
679689
span: Span,
680690
use_kind: MovedValueUseKind,
681-
lp: &Rc<LoanPath>) {
691+
lp: &Rc<LoanPath<'tcx>>) {
682692
/*!
683693
* Reports an error if `expr` (which should be a path)
684694
* is using a moved/uninitialized value
@@ -702,7 +712,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
702712
id: ast::NodeId,
703713
span: Span,
704714
use_kind: MovedValueUseKind,
705-
lp: &Rc<LoanPath>)
715+
lp: &Rc<LoanPath<'tcx>>)
706716
{
707717
/*!
708718
* Reports an error if assigning to `lp` will use a
@@ -722,10 +732,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
722732
* (*p).x = 22; // not ok, p is uninitialized, can't deref
723733
*/
724734

725-
match **lp {
735+
match lp.kind {
726736
LpVar(_) | LpUpvar(_) => {
727737
// assigning to `x` does not require that `x` is initialized
728738
}
739+
LpDowncast(ref lp_base, _) => {
740+
// assigning to `(P->Variant).f` is ok if assigning to `P` is ok
741+
self.check_if_assigned_path_is_moved(id, span,
742+
use_kind, lp_base);
743+
}
729744
LpExtend(ref lp_base, _, LpInterior(_)) => {
730745
// assigning to `P.f` is ok if assigning to `P` is ok
731746
self.check_if_assigned_path_is_moved(id, span,
@@ -864,7 +879,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
864879
cmt = b;
865880
}
866881

867-
mc::cat_downcast(b) |
882+
mc::cat_downcast(b, _) |
868883
mc::cat_interior(b, _) => {
869884
assert_eq!(cmt.mutbl, mc::McInherited);
870885
cmt = b;
@@ -915,11 +930,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
915930
}
916931
}
917932

918-
fn check_for_assignment_to_borrowed_path(
919-
this: &CheckLoanCtxt,
933+
fn check_for_assignment_to_borrowed_path<'a, 'tcx>(
934+
this: &CheckLoanCtxt<'a, 'tcx>,
920935
assignment_id: ast::NodeId,
921936
assignment_span: Span,
922-
assignee_cmt: mc::cmt)
937+
assignee_cmt: mc::cmt<'tcx>)
923938
{
924939
//! Check for assignments that violate the terms of an
925940
//! outstanding loan.
@@ -939,7 +954,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
939954

940955
pub fn report_illegal_mutation(&self,
941956
span: Span,
942-
loan_path: &LoanPath,
957+
loan_path: &LoanPath<'tcx>,
943958
loan: &Loan) {
944959
self.bccx.span_err(
945960
span,

0 commit comments

Comments
 (0)