From 612eeb1df7a2fb062a7bbfe23fb95b72b92de286 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 28 May 2018 15:21:47 +0200 Subject: [PATCH 1/4] Fix NLL issue 50716 and add a regression test. --- .../borrow_check/nll/type_check/mod.rs | 5 ++++ src/test/compile-fail/nll/issue-50716.rs | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/test/compile-fail/nll/issue-50716.rs diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index d25cec7979140..0c5e4f40531f2 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -873,6 +873,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); } self.check_rvalue(mir, rv, location); + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().sized_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty, &[]), + }; + self.prove_trait_ref(trait_ref, location); } StatementKind::SetDiscriminant { ref place, diff --git a/src/test/compile-fail/nll/issue-50716.rs b/src/test/compile-fail/nll/issue-50716.rs new file mode 100644 index 0000000000000..7e3e98a851bd5 --- /dev/null +++ b/src/test/compile-fail/nll/issue-50716.rs @@ -0,0 +1,26 @@ +// Copyright 2012 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. +// +// Regression test for the issue #50716: NLL ignores lifetimes bounds +// derived from `Sized` requirements + +trait A { + type X: ?Sized; +} + +fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) +where + for<'b> &'b T: A, + <&'static T as A>::X: Sized +{ + let _x = *s; //~ ERROR mismatched types [E0308] +} + +fn main() {} From 8b1ea842650ac8313148d66409a538a6fdd334e5 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 29 May 2018 09:13:49 +0200 Subject: [PATCH 2/4] Fix the regression test for issue 50716. --- src/test/compile-fail/nll/issue-50716.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/nll/issue-50716.rs b/src/test/compile-fail/nll/issue-50716.rs index 7e3e98a851bd5..310600aaf9ac8 100644 --- a/src/test/compile-fail/nll/issue-50716.rs +++ b/src/test/compile-fail/nll/issue-50716.rs @@ -11,6 +11,8 @@ // Regression test for the issue #50716: NLL ignores lifetimes bounds // derived from `Sized` requirements +#![feature(nll)] + trait A { type X: ?Sized; } @@ -20,7 +22,7 @@ where for<'b> &'b T: A, <&'static T as A>::X: Sized { - let _x = *s; //~ ERROR mismatched types [E0308] + let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static` } fn main() {} From f288b87c23c955850d03fc59040b3b54b4f3bab9 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 30 May 2018 16:23:54 +0200 Subject: [PATCH 3/4] Move regression test from `compile-fail/` to `ui/` test directory. --- src/test/{compile-fail => ui}/nll/issue-50716.rs | 0 src/test/ui/nll/issue-50716.stderr | 8 ++++++++ 2 files changed, 8 insertions(+) rename src/test/{compile-fail => ui}/nll/issue-50716.rs (100%) create mode 100644 src/test/ui/nll/issue-50716.stderr diff --git a/src/test/compile-fail/nll/issue-50716.rs b/src/test/ui/nll/issue-50716.rs similarity index 100% rename from src/test/compile-fail/nll/issue-50716.rs rename to src/test/ui/nll/issue-50716.rs diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr new file mode 100644 index 0000000000000..20b03d648d9b6 --- /dev/null +++ b/src/test/ui/nll/issue-50716.stderr @@ -0,0 +1,8 @@ +error: free region `'a` does not outlive free region `'static` + --> $DIR/issue-50716.rs:25:14 + | +LL | let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static` + | ^^ + +error: aborting due to previous error + From 03ecd982bf0b3d673dbe759dadfaff9eaaaa95d3 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 26 Jun 2018 17:00:39 +0200 Subject: [PATCH 4/4] Fix the error of selecting obligation by not running the borrow checker. --- src/librustc/ty/util.rs | 6 ++++ src/librustc_mir/borrow_check/mod.rs | 32 ++++++++++++++++++- .../borrow_check/nll/type_check/mod.rs | 8 +++++ ...oximated-shorter-to-static-no-bound.stderr | 7 ++-- ...mated-shorter-to-static-wrong-bound.stderr | 7 ++-- src/test/ui/nll/issue-50716-1.rs | 23 +++++++++++++ 6 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/nll/issue-50716-1.rs diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 024885420f619..4e281231a4105 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -522,6 +522,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr } + /// True if this def-id refers to the implicit constructor for + /// a tuple struct like `struct Foo(u32)`. + pub fn is_struct_constructor(self, def_id: DefId) -> bool { + self.def_key(def_id).disambiguated_data.data == DefPathData::StructCtor + } + /// Given the `DefId` of a fn or closure, returns the `DefId` of /// the innermost fn item that the closure is contained within. /// This is a significant def-id because, when we do diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 6d77364aae02a..ca0c259fb6772 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -76,7 +76,37 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC let input_mir = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); - if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck() { + let mut return_early; + + // Return early if we are not supposed to use MIR borrow checker for this function. + return_early = !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck(); + + if tcx.is_struct_constructor(def_id) { + // We are not borrow checking the automatically generated struct constructors + // because we want to accept structs such as this (taken from the `linked-hash-map` + // crate): + // ```rust + // struct Qey(Q); + // ``` + // MIR of this struct constructor looks something like this: + // ```rust + // fn Qey(_1: Q) -> Qey{ + // let mut _0: Qey; // return place + // + // bb0: { + // (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26 + // return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26 + // } + // } + // ``` + // The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is + // of statically known size, which is not known to be true because of the + // `Q: ?Sized` constraint. However, it is true because the constructor can be + // called only when `Q` is of statically known size. + return_early = true; + } + + if return_early { return BorrowCheckResult { closure_requirements: None, used_mut_upvars: SmallVec::new(), diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 0c5e4f40531f2..0e5597b036ba2 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1725,6 +1725,14 @@ impl MirPass for TypeckMir { // broken MIR, so try not to report duplicate errors. return; } + + if tcx.is_struct_constructor(def_id) { + // We just assume that the automatically generated struct constructors are + // correct. See the comment in the `mir_borrowck` implementation for an + // explanation why we need this. + return; + } + let param_env = tcx.param_env(def_id); tcx.infer_ctxt().enter(|infcx| { let _ = type_check_internal( diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 93a7c1a0c6c33..122e393f97a53 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -24,15 +24,16 @@ LL | | }); = note: where '_#1r: '_#0r error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic` - --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5 + --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47 | -LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { +LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { + | _______________________________________________^ LL | | //~^ ERROR does not outlive free region LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll LL | | }); - | |______^ + | |_____^ note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index c62f62efda361..8cdbc26458150 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -24,15 +24,16 @@ LL | | }); = note: where '_#1r: '_#0r error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic` - --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5 + --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47 | -LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { +LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { + | _______________________________________________^ LL | | //~^ ERROR does not outlive free region LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | //~^ WARNING not reporting region error due to nll LL | | }); - | |______^ + | |_____^ note: No external requirements --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1 diff --git a/src/test/ui/nll/issue-50716-1.rs b/src/test/ui/nll/issue-50716-1.rs new file mode 100644 index 0000000000000..ced9b1cde6483 --- /dev/null +++ b/src/test/ui/nll/issue-50716-1.rs @@ -0,0 +1,23 @@ +// Copyright 2012 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. +// +// An additional regression test for the issue #50716 “NLL ignores lifetimes +// bounds derived from `Sized` requirements” that checks that the fixed compiler +// accepts this code fragment with both AST and MIR borrow checkers. +// +// revisions: ast mir +// +// compile-pass + +#![cfg_attr(mir, feature(nll))] + +struct Qey(Q); + +fn main() {}