diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index c8613fd70652e..7de8921ae2265 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -419,24 +419,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { infer::AutoBorrow(expr.span)); } } - ty::AutoObject(ast::BorrowedSigil, Some(trait_region), _, _, _, _) => { - // Determine if we are casting `expr` to an trait - // instance. If so, we have to be sure that the type of - // the source obeys the trait's region bound. - // - // Note: there is a subtle point here concerning type - // parameters. It is possible that the type of `source` - // contains type parameters, which in turn may contain - // regions that are not visible to us (only the caller - // knows about them). The kind checker is ultimately - // responsible for guaranteeing region safety in that - // particular case. There is an extensive comment on the - // function check_cast_for_escaping_regions() in kind.rs - // explaining how it goes about doing that. - - let source_ty = rcx.fcx.expr_ty(expr); - constrain_regions_in_type(rcx, trait_region, - infer::RelateObjectBound(expr.span), source_ty); + ty::AutoObject(_, maybe_region, _, _, _, ref substs) => { + let source_ty = rcx.resolve_node_type(expr.id); + constrain_trait_cast(rcx, expr, maybe_region, substs, source_ty); } _ => {} } @@ -540,13 +525,15 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // explaining how it goes about doing that. let target_ty = rcx.resolve_node_type(expr.id); match ty::get(target_ty).sty { - ty::ty_trait(~ty::TyTrait { store: ty::RegionTraitStore(trait_region), .. }) => { + ty::ty_trait(~ty::TyTrait { store: trait_store, substs: ref substs, .. }) => { let source_ty = rcx.resolve_expr_type_adjusted(source); - constrain_regions_in_type( - rcx, - trait_region, - infer::RelateObjectBound(expr.span), - source_ty); + + let trait_region = match trait_store { + ty::RegionTraitStore(r) => Some(r), + ty::UniqTraitStore => None + }; + + constrain_trait_cast(rcx, expr, trait_region, substs, source_ty); } _ => () } @@ -933,6 +920,56 @@ fn constrain_index(rcx: &mut Rcx, } } +fn constrain_trait_cast(rcx: &mut Rcx, + expr: &ast::Expr, + trait_region: Option, + trait_substs: &ty::substs, + source_ty: ty::t) { + // If we are casting `source` to a trait + // instance, we have to be sure that the type of + // the source obeys the trait's region bound. + // + // Note: there is a subtle point here concerning type + // parameters. It is possible that the type of `source` + // contains type parameters, which in turn may contain + // regions that are not visible to us (only the caller + // knows about them). The kind checker is ultimately + // responsible for guaranteeing region safety in that + // particular case. There is an extensive comment on the + // function check_cast_for_escaping_regions() in kind.rs + // explaining how it goes about doing that. + + debug!("constrain_trait_cast(expr={:?}, trait_region={:?}, trait_substs={:?}, source_ty={:?}", + expr, trait_region, trait_substs, ty::get(source_ty)); + + let mut regions = Vec::new(); + + match trait_substs.regions { + ty::NonerasedRegions(ref regs) => { + for r in regs.iter() { + regions.push(*r); + } + } + ty::ErasedRegions => () + } + + match trait_region { + Some(region) => { + regions.push(region); + } + None => { + // casting to owned trait with no lifetime params in trait def + if regions.is_empty() { + regions.push(ty::ReStatic); + } + } + } + + for r in regions.iter() { + constrain_regions_in_type(rcx, *r, infer::RelateObjectBound(expr.span), source_ty); + } +} + fn constrain_regions_in_type_of_node( rcx: &mut Rcx, id: ast::NodeId, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 7ff7792313251..2818192be0ed3 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -98,20 +98,20 @@ pub type IdentMacroExpanderFn = pub type MacroCrateRegistrationFun = fn(|ast::Name, SyntaxExtension|); -pub trait AnyMacro { +pub trait AnyMacro<'a> { fn make_expr(&self) -> @ast::Expr; fn make_items(&self) -> SmallVector<@ast::Item>; fn make_stmt(&self) -> @ast::Stmt; } -pub enum MacResult { +pub enum MacResult<'a> { MRExpr(@ast::Expr), MRItem(@ast::Item), - MRAny(~AnyMacro:), + MRAny(~AnyMacro<'a>:), MRDef(MacroDef), } -impl MacResult { +impl<'a> MacResult<'a> { /// Create an empty expression MacResult; useful for satisfying /// type signatures after emitting a non-fatal error (which stop /// compilation well before the validity (or otherwise)) of the @@ -123,7 +123,7 @@ impl MacResult { span: sp, } } - pub fn dummy_expr(sp: codemap::Span) -> MacResult { + pub fn dummy_expr(sp: codemap::Span) -> MacResult<'a> { MRExpr(MacResult::raw_dummy_expr(sp)) } pub fn dummy_any(sp: codemap::Span) -> MacResult { @@ -133,7 +133,7 @@ impl MacResult { struct DummyMacResult { sp: codemap::Span } -impl AnyMacro for DummyMacResult { +impl<'a> AnyMacro<'a> for DummyMacResult { fn make_expr(&self) -> @ast::Expr { MacResult::raw_dummy_expr(self.sp) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index d4a883a63ebbf..edfc17a1fc5a3 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -57,7 +57,7 @@ impl<'a> ParserAnyMacro<'a> { } } -impl<'a> AnyMacro for ParserAnyMacro<'a> { +impl<'a> AnyMacro<'a> for ParserAnyMacro<'a> { fn make_expr(&self) -> @ast::Expr { let ret = self.parser.borrow_mut().parse_expr(); self.ensure_complete_parse(true); @@ -106,7 +106,7 @@ impl MacroExpander for MacroRulesMacroExpander { } // Given `lhses` and `rhses`, this is the new macro we create -fn generic_extension(cx: &ExtCtxt, +fn generic_extension<'a>(cx: &'a ExtCtxt, sp: Span, name: Ident, arg: &[ast::TokenTree], diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 23d7cc0af97e4..697dff10a1c99 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -24,7 +24,7 @@ use std::str; pub use ext::tt::transcribe::{TtReader, new_tt_reader}; -pub trait Reader { +pub trait Reader<'a> { fn is_eof(&self) -> bool; fn next_token(&mut self) -> TokenAndSpan; fn fatal(&self, ~str) -> !; @@ -89,7 +89,7 @@ pub fn new_low_level_string_reader<'a>(span_diagnostic: &'a SpanHandler, r } -impl<'a> Reader for StringReader<'a> { +impl<'a> Reader<'a> for StringReader<'a> { fn is_eof(&self) -> bool { is_eof(self) } // return the next token. EFFECT: advances the string_reader. fn next_token(&mut self) -> TokenAndSpan { @@ -113,7 +113,7 @@ impl<'a> Reader for StringReader<'a> { } } -impl<'a> Reader for TtReader<'a> { +impl<'a> Reader<'a> for TtReader<'a> { fn is_eof(&self) -> bool { self.cur_tok == token::EOF } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 62ce0f1e11399..106c3639ba22f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -272,7 +272,7 @@ struct ParsedItemsAndViewItems { /* ident is handled by common.rs */ -pub fn Parser<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, mut rdr: ~Reader:) +pub fn Parser<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, mut rdr: ~Reader<'a>:) -> Parser<'a> { let tok0 = rdr.next_token(); let span = tok0.sp; @@ -324,7 +324,7 @@ pub struct Parser<'a> { pub tokens_consumed: uint, pub restriction: restriction, pub quote_depth: uint, // not (yet) related to the quasiquoter - pub reader: ~Reader:, + pub reader: ~Reader<'a>:, pub interner: Rc, /// The set of seen errors about obsolete syntax. Used to suppress /// extra detail when the same error is seen twice diff --git a/src/test/compile-fail/owned-ptr-static-bound.rs b/src/test/compile-fail/owned-ptr-static-bound.rs index 508633d294146..7cc2193bf52a8 100644 --- a/src/test/compile-fail/owned-ptr-static-bound.rs +++ b/src/test/compile-fail/owned-ptr-static-bound.rs @@ -11,19 +11,19 @@ trait A {} struct B<'a, T>(&'a A); -trait X {} -impl<'a, T> X for B<'a, T> {} +trait X<'a> {} +impl<'a, T> X<'a> for B<'a, T> {} -fn f<'a, T, U>(v: ~A) -> ~X: { - ~B(v) as ~X: //~ ERROR value may contain references; add `'static` bound to `T` +fn f<'a, T, U>(v: &'a A) -> ~X<'a>: { + ~B(v) as ~X<'a>: //~ ERROR value may contain references; add `'static` bound to `T` } -fn g<'a, T, U>(v: ~A) -> ~X: { - ~B(v) as ~X: //~ ERROR value may contain references; add `'static` bound to `U` +fn g<'a, T, U>(v: &'a A) -> ~X<'a>: { + ~B(v) as ~X<'a>: //~ ERROR value may contain references; add `'static` bound to `U` } -fn h<'a, T: 'static>(v: ~A) -> ~X: { - ~B(v) as ~X: // ok +fn h<'a, T: 'static>(v: &'a A) -> ~X<'a>: { + ~B(v) as ~X<'a>: // ok } fn main() {} diff --git a/src/test/compile-fail/regionck-uniq-trait-cast-fail.rs b/src/test/compile-fail/regionck-uniq-trait-cast-fail.rs new file mode 100644 index 0000000000000..c60fe98a6b3cf --- /dev/null +++ b/src/test/compile-fail/regionck-uniq-trait-cast-fail.rs @@ -0,0 +1,22 @@ +// Copyright 2014 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. + +// Test that lifetimes can't escape through owned trait casts + +trait X {} +impl<'a> X for &'a X {} + +fn foo(x: &X) -> ~X: { + ~x as ~X: + //~^ ERROR lifetime of the source pointer does not outlive lifetime bound of the object type +} + +fn main() { +} \ No newline at end of file diff --git a/src/test/compile-fail/regionck-uniq-trait-coerce-fail.rs b/src/test/compile-fail/regionck-uniq-trait-coerce-fail.rs new file mode 100644 index 0000000000000..43acd475e4602 --- /dev/null +++ b/src/test/compile-fail/regionck-uniq-trait-coerce-fail.rs @@ -0,0 +1,27 @@ +// Copyright 2014 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. + +// Test that lifetimes can't escape through owned trait coercions + +trait A {} +impl<'a> A for &'a A {} + +struct B; +impl A for B {} +impl<'a> A for &'a B {} + +fn main() { + let _tmp = { + let bb = B; + let pb = ~&bb; //~ ERROR `bb` does not live long enough + let aa: ~A: = pb; + aa + }; +} diff --git a/src/test/run-pass/regionck-uniq-trait-cast-pass.rs b/src/test/run-pass/regionck-uniq-trait-cast-pass.rs new file mode 100644 index 0000000000000..05856b48bb487 --- /dev/null +++ b/src/test/run-pass/regionck-uniq-trait-cast-pass.rs @@ -0,0 +1,22 @@ +// Copyright 2014 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. + +// Test that trait lifetime params aren't constrained to static lifetime +// when casting something to owned trait + +trait X<'a> {} +impl<'a> X<'a> for &'a X<'a> {} + +fn foo<'a>(x: &'a X<'a>) -> ~X<'a>: { + ~x as ~X<'a>: +} + +pub fn main() { +} \ No newline at end of file diff --git a/src/test/run-pass/regionck-uniq-trait-coerce-pass.rs b/src/test/run-pass/regionck-uniq-trait-coerce-pass.rs new file mode 100644 index 0000000000000..cf9ae1d9f6d7b --- /dev/null +++ b/src/test/run-pass/regionck-uniq-trait-coerce-pass.rs @@ -0,0 +1,28 @@ +// Copyright 2014 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. + +// Test that trait lifetime params aren't constrained to static lifetime +// when coercing something to owned trait + +trait A<'a> {} +impl<'a> A<'a> for &'a A<'a> {} + +struct B; +impl<'a> A<'a> for B {} +impl<'a> A<'a> for &'a B {} + +pub fn main() { + let bb = B; + let _tmp = { + let pb = ~&bb; + let aa: ~A: = pb; + aa + }; +}