Skip to content

Commit 4d77945

Browse files
committed
rustc: fixed regionck for owned trait casts.
Regionck didn't do any checks for casts/coercions to an owned trait, which resulted in lifetimes of the source pointer to be ignored in the result of such cast. This fix constraints all regions of the source type of the cast/coercion to be superregions of each region of the target type (if target trait definition has some lifetime params), or of 'static lifetime (if there're no lifetime params in target trait's definition). Closes rust-lang#5723 Closes rust-lang#9745 Closes rust-lang#11971
1 parent e415c25 commit 4d77945

10 files changed

+181
-45
lines changed

src/librustc/middle/typeck/check/regionck.rs

+61-24
Original file line numberDiff line numberDiff line change
@@ -419,24 +419,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
419419
infer::AutoBorrow(expr.span));
420420
}
421421
}
422-
ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => {
423-
// Determine if we are casting `expr` to an trait
424-
// instance. If so, we have to be sure that the type of
425-
// the source obeys the trait's region bound.
426-
//
427-
// Note: there is a subtle point here concerning type
428-
// parameters. It is possible that the type of `source`
429-
// contains type parameters, which in turn may contain
430-
// regions that are not visible to us (only the caller
431-
// knows about them). The kind checker is ultimately
432-
// responsible for guaranteeing region safety in that
433-
// particular case. There is an extensive comment on the
434-
// function check_cast_for_escaping_regions() in kind.rs
435-
// explaining how it goes about doing that.
436-
437-
let source_ty = rcx.fcx.expr_ty(expr);
438-
constrain_regions_in_type(rcx, trait_region,
439-
infer::RelateObjectBound(expr.span), source_ty);
422+
ty::AutoObject(_, maybe_region, _, _, _, ref substs) => {
423+
let source_ty = rcx.resolve_node_type(expr.id);
424+
constrain_trait_cast(rcx, expr, maybe_region, substs, source_ty);
440425
}
441426
_ => {}
442427
}
@@ -540,13 +525,15 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
540525
// explaining how it goes about doing that.
541526
let target_ty = rcx.resolve_node_type(expr.id);
542527
match ty::get(target_ty).sty {
543-
ty::ty_trait(~ty::TyTrait { store: ty::RegionTraitStore(trait_region), .. }) => {
528+
ty::ty_trait(~ty::TyTrait { store: trait_store, substs: ref substs, .. }) => {
544529
let source_ty = rcx.resolve_expr_type_adjusted(source);
545-
constrain_regions_in_type(
546-
rcx,
547-
trait_region,
548-
infer::RelateObjectBound(expr.span),
549-
source_ty);
530+
531+
let trait_region = match trait_store {
532+
ty::RegionTraitStore(r) => Some(r),
533+
ty::UniqTraitStore => None
534+
};
535+
536+
constrain_trait_cast(rcx, expr, trait_region, substs, source_ty);
550537
}
551538
_ => ()
552539
}
@@ -933,6 +920,56 @@ fn constrain_index(rcx: &mut Rcx,
933920
}
934921
}
935922

923+
fn constrain_trait_cast(rcx: &mut Rcx,
924+
expr: &ast::Expr,
925+
trait_region: Option<ty::Region>,
926+
trait_substs: &ty::substs,
927+
source_ty: ty::t) {
928+
// If we are casting `source` to a trait
929+
// instance, we have to be sure that the type of
930+
// the source obeys the trait's region bound.
931+
//
932+
// Note: there is a subtle point here concerning type
933+
// parameters. It is possible that the type of `source`
934+
// contains type parameters, which in turn may contain
935+
// regions that are not visible to us (only the caller
936+
// knows about them). The kind checker is ultimately
937+
// responsible for guaranteeing region safety in that
938+
// particular case. There is an extensive comment on the
939+
// function check_cast_for_escaping_regions() in kind.rs
940+
// explaining how it goes about doing that.
941+
942+
debug!("constrain_trait_cast(expr={:?}, trait_region={:?}, trait_substs={:?}, source_ty={:?}",
943+
expr, trait_region, trait_substs, ty::get(source_ty));
944+
945+
let mut regions = Vec::new();
946+
947+
match trait_substs.regions {
948+
ty::NonerasedRegions(ref regs) => {
949+
for r in regs.iter() {
950+
regions.push(*r);
951+
}
952+
}
953+
ty::ErasedRegions => ()
954+
}
955+
956+
match trait_region {
957+
Some(region) => {
958+
regions.push(region);
959+
}
960+
None => {
961+
// casting to owned trait with no lifetime params in trait def
962+
if regions.is_empty() {
963+
regions.push(ty::ReStatic);
964+
}
965+
}
966+
}
967+
968+
for r in regions.iter() {
969+
constrain_regions_in_type(rcx, *r, infer::RelateObjectBound(expr.span), source_ty);
970+
}
971+
}
972+
936973
fn constrain_regions_in_type_of_node(
937974
rcx: &mut Rcx,
938975
id: ast::NodeId,

src/libsyntax/ext/base.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,20 @@ pub type IdentMacroExpanderFn =
9898
pub type MacroCrateRegistrationFun =
9999
fn(|ast::Name, SyntaxExtension|);
100100

101-
pub trait AnyMacro {
101+
pub trait AnyMacro<'a> {
102102
fn make_expr(&self) -> @ast::Expr;
103103
fn make_items(&self) -> SmallVector<@ast::Item>;
104104
fn make_stmt(&self) -> @ast::Stmt;
105105
}
106106

107107

108-
pub enum MacResult {
108+
pub enum MacResult<'a> {
109109
MRExpr(@ast::Expr),
110110
MRItem(@ast::Item),
111-
MRAny(~AnyMacro:),
111+
MRAny(~AnyMacro<'a>:),
112112
MRDef(MacroDef),
113113
}
114-
impl MacResult {
114+
impl<'a> MacResult<'a> {
115115
/// Create an empty expression MacResult; useful for satisfying
116116
/// type signatures after emitting a non-fatal error (which stop
117117
/// compilation well before the validity (or otherwise)) of the
@@ -123,7 +123,7 @@ impl MacResult {
123123
span: sp,
124124
}
125125
}
126-
pub fn dummy_expr(sp: codemap::Span) -> MacResult {
126+
pub fn dummy_expr(sp: codemap::Span) -> MacResult<'a> {
127127
MRExpr(MacResult::raw_dummy_expr(sp))
128128
}
129129
pub fn dummy_any(sp: codemap::Span) -> MacResult {
@@ -133,7 +133,7 @@ impl MacResult {
133133
struct DummyMacResult {
134134
sp: codemap::Span
135135
}
136-
impl AnyMacro for DummyMacResult {
136+
impl<'a> AnyMacro<'a> for DummyMacResult {
137137
fn make_expr(&self) -> @ast::Expr {
138138
MacResult::raw_dummy_expr(self.sp)
139139
}

src/libsyntax/ext/tt/macro_rules.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl<'a> ParserAnyMacro<'a> {
5757
}
5858
}
5959

60-
impl<'a> AnyMacro for ParserAnyMacro<'a> {
60+
impl<'a> AnyMacro<'a> for ParserAnyMacro<'a> {
6161
fn make_expr(&self) -> @ast::Expr {
6262
let ret = self.parser.borrow_mut().parse_expr();
6363
self.ensure_complete_parse(true);
@@ -106,7 +106,7 @@ impl MacroExpander for MacroRulesMacroExpander {
106106
}
107107

108108
// Given `lhses` and `rhses`, this is the new macro we create
109-
fn generic_extension(cx: &ExtCtxt,
109+
fn generic_extension<'a>(cx: &'a ExtCtxt,
110110
sp: Span,
111111
name: Ident,
112112
arg: &[ast::TokenTree],

src/libsyntax/parse/lexer.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use std::str;
2424

2525
pub use ext::tt::transcribe::{TtReader, new_tt_reader};
2626

27-
pub trait Reader {
27+
pub trait Reader<'a> {
2828
fn is_eof(&self) -> bool;
2929
fn next_token(&mut self) -> TokenAndSpan;
3030
fn fatal(&self, ~str) -> !;
@@ -89,7 +89,7 @@ pub fn new_low_level_string_reader<'a>(span_diagnostic: &'a SpanHandler,
8989
r
9090
}
9191

92-
impl<'a> Reader for StringReader<'a> {
92+
impl<'a> Reader<'a> for StringReader<'a> {
9393
fn is_eof(&self) -> bool { is_eof(self) }
9494
// return the next token. EFFECT: advances the string_reader.
9595
fn next_token(&mut self) -> TokenAndSpan {
@@ -113,7 +113,7 @@ impl<'a> Reader for StringReader<'a> {
113113
}
114114
}
115115

116-
impl<'a> Reader for TtReader<'a> {
116+
impl<'a> Reader<'a> for TtReader<'a> {
117117
fn is_eof(&self) -> bool {
118118
self.cur_tok == token::EOF
119119
}

src/libsyntax/parse/parser.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ struct ParsedItemsAndViewItems {
272272

273273
/* ident is handled by common.rs */
274274

275-
pub fn Parser<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, mut rdr: ~Reader:)
275+
pub fn Parser<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, mut rdr: ~Reader<'a>:)
276276
-> Parser<'a> {
277277
let tok0 = rdr.next_token();
278278
let span = tok0.sp;
@@ -324,7 +324,7 @@ pub struct Parser<'a> {
324324
pub tokens_consumed: uint,
325325
pub restriction: restriction,
326326
pub quote_depth: uint, // not (yet) related to the quasiquoter
327-
pub reader: ~Reader:,
327+
pub reader: ~Reader<'a>:,
328328
pub interner: Rc<token::IdentInterner>,
329329
/// The set of seen errors about obsolete syntax. Used to suppress
330330
/// extra detail when the same error is seen twice

src/test/compile-fail/owned-ptr-static-bound.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@
1111
trait A<T> {}
1212
struct B<'a, T>(&'a A<T>);
1313

14-
trait X {}
15-
impl<'a, T> X for B<'a, T> {}
14+
trait X<'a> {}
15+
impl<'a, T> X<'a> for B<'a, T> {}
1616

17-
fn f<'a, T, U>(v: ~A<T>) -> ~X: {
18-
~B(v) as ~X: //~ ERROR value may contain references; add `'static` bound to `T`
17+
fn f<'a, T, U>(v: &'a A<T>) -> ~X<'a>: {
18+
~B(v) as ~X<'a>: //~ ERROR value may contain references; add `'static` bound to `T`
1919
}
2020

21-
fn g<'a, T, U>(v: ~A<U>) -> ~X: {
22-
~B(v) as ~X: //~ ERROR value may contain references; add `'static` bound to `U`
21+
fn g<'a, T, U>(v: &'a A<U>) -> ~X<'a>: {
22+
~B(v) as ~X<'a>: //~ ERROR value may contain references; add `'static` bound to `U`
2323
}
2424

25-
fn h<'a, T: 'static>(v: ~A<T>) -> ~X: {
26-
~B(v) as ~X: // ok
25+
fn h<'a, T: 'static>(v: &'a A<T>) -> ~X<'a>: {
26+
~B(v) as ~X<'a>: // ok
2727
}
2828

2929
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 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 lifetimes can't escape through owned trait casts
12+
13+
trait X {}
14+
impl<'a> X for &'a X {}
15+
16+
fn foo(x: &X) -> ~X: {
17+
~x as ~X:
18+
//~^ ERROR lifetime of the source pointer does not outlive lifetime bound of the object type
19+
}
20+
21+
fn main() {
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2014 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 lifetimes can't escape through owned trait coercions
12+
13+
trait A {}
14+
impl<'a> A for &'a A {}
15+
16+
struct B;
17+
impl A for B {}
18+
impl<'a> A for &'a B {}
19+
20+
fn main() {
21+
let _tmp = {
22+
let bb = B;
23+
let pb = ~&bb; //~ ERROR `bb` does not live long enough
24+
let aa: ~A: = pb;
25+
aa
26+
};
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 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 trait lifetime params aren't constrained to static lifetime
12+
// when casting something to owned trait
13+
14+
trait X<'a> {}
15+
impl<'a> X<'a> for &'a X<'a> {}
16+
17+
fn foo<'a>(x: &'a X<'a>) -> ~X<'a>: {
18+
~x as ~X<'a>:
19+
}
20+
21+
pub fn main() {
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2014 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 trait lifetime params aren't constrained to static lifetime
12+
// when coercing something to owned trait
13+
14+
trait A<'a> {}
15+
impl<'a> A<'a> for &'a A<'a> {}
16+
17+
struct B;
18+
impl<'a> A<'a> for B {}
19+
impl<'a> A<'a> for &'a B {}
20+
21+
pub fn main() {
22+
let bb = B;
23+
let _tmp = {
24+
let pb = ~&bb;
25+
let aa: ~A: = pb;
26+
aa
27+
};
28+
}

0 commit comments

Comments
 (0)