Skip to content

Commit cd494c1

Browse files
committed
Auto merge of #51139 - vakaras:issue-50716, r=nikomatsakis
Fix NLL issue 50716 and add a regression test. Fix for NLL issue #50716. r? @nikomatsakis
2 parents 23b5516 + 03ecd98 commit cd494c1

File tree

8 files changed

+117
-7
lines changed

8 files changed

+117
-7
lines changed

src/librustc/ty/util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
522522
self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr
523523
}
524524

525+
/// True if this def-id refers to the implicit constructor for
526+
/// a tuple struct like `struct Foo(u32)`.
527+
pub fn is_struct_constructor(self, def_id: DefId) -> bool {
528+
self.def_key(def_id).disambiguated_data.data == DefPathData::StructCtor
529+
}
530+
525531
/// Given the `DefId` of a fn or closure, returns the `DefId` of
526532
/// the innermost fn item that the closure is contained within.
527533
/// This is a significant def-id because, when we do

src/librustc_mir/borrow_check/mod.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,37 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC
7676
let input_mir = tcx.mir_validated(def_id);
7777
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
7878

79-
if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck() {
79+
let mut return_early;
80+
81+
// Return early if we are not supposed to use MIR borrow checker for this function.
82+
return_early = !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck();
83+
84+
if tcx.is_struct_constructor(def_id) {
85+
// We are not borrow checking the automatically generated struct constructors
86+
// because we want to accept structs such as this (taken from the `linked-hash-map`
87+
// crate):
88+
// ```rust
89+
// struct Qey<Q: ?Sized>(Q);
90+
// ```
91+
// MIR of this struct constructor looks something like this:
92+
// ```rust
93+
// fn Qey(_1: Q) -> Qey<Q>{
94+
// let mut _0: Qey<Q>; // return place
95+
//
96+
// bb0: {
97+
// (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
98+
// return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
99+
// }
100+
// }
101+
// ```
102+
// The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
103+
// of statically known size, which is not known to be true because of the
104+
// `Q: ?Sized` constraint. However, it is true because the constructor can be
105+
// called only when `Q` is of statically known size.
106+
return_early = true;
107+
}
108+
109+
if return_early {
80110
return BorrowCheckResult {
81111
closure_requirements: None,
82112
used_mut_upvars: SmallVec::new(),

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
873873
);
874874
}
875875
self.check_rvalue(mir, rv, location);
876+
let trait_ref = ty::TraitRef {
877+
def_id: tcx.lang_items().sized_trait().unwrap(),
878+
substs: tcx.mk_substs_trait(place_ty, &[]),
879+
};
880+
self.prove_trait_ref(trait_ref, location);
876881
}
877882
StatementKind::SetDiscriminant {
878883
ref place,
@@ -1720,6 +1725,14 @@ impl MirPass for TypeckMir {
17201725
// broken MIR, so try not to report duplicate errors.
17211726
return;
17221727
}
1728+
1729+
if tcx.is_struct_constructor(def_id) {
1730+
// We just assume that the automatically generated struct constructors are
1731+
// correct. See the comment in the `mir_borrowck` implementation for an
1732+
// explanation why we need this.
1733+
return;
1734+
}
1735+
17231736
let param_env = tcx.param_env(def_id);
17241737
tcx.infer_ctxt().enter(|infcx| {
17251738
let _ = type_check_internal(

src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr

+4-3
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@ LL | | });
2424
= note: where '_#1r: '_#0r
2525

2626
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`
27-
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
27+
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47
2828
|
29-
LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
29+
LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
30+
| _______________________________________________^
3031
LL | | //~^ ERROR does not outlive free region
3132
LL | |
3233
LL | | // Only works if 'x: 'y:
3334
LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
3435
LL | | });
35-
| |______^
36+
| |_____^
3637

3738
note: No external requirements
3839
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1

src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr

+4-3
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@ LL | | });
2424
= note: where '_#1r: '_#0r
2525

2626
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`
27-
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
27+
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47
2828
|
29-
LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
29+
LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
30+
| _______________________________________________^
3031
LL | | //~^ ERROR does not outlive free region
3132
LL | | // Only works if 'x: 'y:
3233
LL | | demand_y(x, y, x.get())
3334
LL | | //~^ WARNING not reporting region error due to nll
3435
LL | | });
35-
| |______^
36+
| |_____^
3637

3738
note: No external requirements
3839
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1

src/test/ui/nll/issue-50716-1.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2012 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+
// An additional regression test for the issue #50716 “NLL ignores lifetimes
12+
// bounds derived from `Sized` requirements” that checks that the fixed compiler
13+
// accepts this code fragment with both AST and MIR borrow checkers.
14+
//
15+
// revisions: ast mir
16+
//
17+
// compile-pass
18+
19+
#![cfg_attr(mir, feature(nll))]
20+
21+
struct Qey<Q: ?Sized>(Q);
22+
23+
fn main() {}

src/test/ui/nll/issue-50716.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2012 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+
// Regression test for the issue #50716: NLL ignores lifetimes bounds
12+
// derived from `Sized` requirements
13+
14+
#![feature(nll)]
15+
16+
trait A {
17+
type X: ?Sized;
18+
}
19+
20+
fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
21+
where
22+
for<'b> &'b T: A,
23+
<&'static T as A>::X: Sized
24+
{
25+
let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static`
26+
}
27+
28+
fn main() {}

src/test/ui/nll/issue-50716.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: free region `'a` does not outlive free region `'static`
2+
--> $DIR/issue-50716.rs:25:14
3+
|
4+
LL | let _x = *s; //~ ERROR free region `'a` does not outlive free region `'static`
5+
| ^^
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)