Skip to content

Commit b9f7564

Browse files
committed
Do not ignore lifetime bounds in Copy impls
Closes #29149
1 parent fe7e1a4 commit b9f7564

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

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

+14-7
Original file line numberDiff line numberDiff line change
@@ -374,13 +374,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
374374
}
375375
};
376376
if let PlaceContext::Copy = context {
377-
let ty = place_ty.to_ty(self.tcx());
378-
if self.cx
379-
.infcx
380-
.type_moves_by_default(self.cx.param_env, ty, DUMMY_SP)
381-
{
382-
span_mirbug!(self, place, "attempted copy of non-Copy type ({:?})", ty);
383-
}
377+
let tcx = self.tcx();
378+
let trait_ref = ty::TraitRef {
379+
def_id: tcx.lang_items().copy_trait().unwrap(),
380+
substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
381+
};
382+
383+
// In order to have a Copy operand, the type T of the value must be Copy. Note that we
384+
// prove that T: Copy, rather than using the type_moves_by_default test. This is
385+
// important because type_moves_by_default ignores the resulting region obligations and
386+
// assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
387+
// (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
388+
// fully apply: in effect, the rule is that if a value of some type could implement
389+
// Copy, then it must.
390+
self.cx.prove_trait_ref(trait_ref, location);
384391
}
385392
place_ty
386393
}
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+
// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
12+
13+
#![feature(nll)]
14+
15+
#[derive(Clone)] struct Foo<'a>(&'a u32);
16+
impl Copy for Foo<'static> {}
17+
18+
fn main() {
19+
let s = 2;
20+
let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597]
21+
drop(a);
22+
drop(a);
23+
}

0 commit comments

Comments
 (0)