From 279fe0fa76ea1db3173c2b1d43a65dddf3126332 Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Fri, 24 Jan 2014 20:48:10 +0100 Subject: [PATCH 1/2] Treat unary struct and enum variants as rvalues Closes #11681 --- src/librustc/middle/mem_categorization.rs | 36 ++++++++++--------- ...ions-lifetime-of-struct-or-enum-variant.rs | 32 +++++++++++++++++ 2 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b6271b68046ad..bad1391ce6b89 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -356,7 +356,7 @@ impl mem_categorization_ctxt { // Convert a bare fn to a closure by adding NULL env. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue_node(expr, expr_ty) + self.cat_rvalue_node(expr.id(), expr.span(), expr_ty) } ty::AutoDerefRef(ty::AutoDerefRef { @@ -365,7 +365,7 @@ impl mem_categorization_ctxt { // Equivalent to &*expr or something similar. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue_node(expr, expr_ty) + self.cat_rvalue_node(expr.id(), expr.span(), expr_ty) } ty::AutoDerefRef(ty::AutoDerefRef { @@ -398,7 +398,7 @@ impl mem_categorization_ctxt { ast::ExprUnary(_, ast::UnDeref, e_base) => { let method_map = self.method_map.borrow(); if method_map.get().contains_key(&expr.id) { - return self.cat_rvalue_node(expr, expr_ty); + return self.cat_rvalue_node(expr.id(), expr.span(), expr_ty); } let base_cmt = self.cat_expr(e_base); @@ -418,7 +418,7 @@ impl mem_categorization_ctxt { ast::ExprIndex(_, base, _) => { let method_map = self.method_map.borrow(); if method_map.get().contains_key(&expr.id) { - return self.cat_rvalue_node(expr, expr_ty); + return self.cat_rvalue_node(expr.id(), expr.span(), expr_ty); } let base_cmt = self.cat_expr(base); @@ -444,7 +444,7 @@ impl mem_categorization_ctxt { ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) | ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprInlineAsm(..) | ast::ExprBox(..) => { - return self.cat_rvalue_node(expr, expr_ty); + return self.cat_rvalue_node(expr.id(), expr.span(), expr_ty); } ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop") @@ -457,13 +457,18 @@ impl mem_categorization_ctxt { expr_ty: ty::t, def: ast::Def) -> cmt { + debug!("cat_def: id={} expr={}", + id, ty_to_str(self.tcx, expr_ty)); + + match def { + ast::DefStruct(..) | ast::DefVariant(..) => { + self.cat_rvalue_node(id, span, expr_ty) + } ast::DefFn(..) | ast::DefStaticMethod(..) | ast::DefMod(_) | ast::DefForeignMod(_) | ast::DefStatic(_, false) | - ast::DefUse(_) | ast::DefVariant(..) | - ast::DefTrait(_) | ast::DefTy(_) | ast::DefPrimTy(_) | - ast::DefTyParam(..) | ast::DefStruct(..) | - ast::DefTyParamBinder(..) | ast::DefRegion(_) | + ast::DefUse(_) | ast::DefTrait(_) | ast::DefTy(_) | ast::DefPrimTy(_) | + ast::DefTyParam(..) | ast::DefTyParamBinder(..) | ast::DefRegion(_) | ast::DefLabel(_) | ast::DefSelfTy(..) | ast::DefMethod(..) => { @cmt_ { id:id, @@ -571,16 +576,13 @@ impl mem_categorization_ctxt { } } - pub fn cat_rvalue_node(&self, - node: &N, - expr_ty: ty::t) -> cmt { - match self.tcx.region_maps.temporary_scope(node.id()) { + pub fn cat_rvalue_node(&self, id: ast::NodeId, span: Span, expr_ty: ty::t) -> cmt { + match self.tcx.region_maps.temporary_scope(id) { Some(scope) => { - self.cat_rvalue(node.id(), node.span(), - ty::ReScope(scope), expr_ty) + self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty) } None => { - self.cat_rvalue(node.id(), node.span(), ty::ReStatic, expr_ty) + self.cat_rvalue(id, span, ty::ReStatic, expr_ty) } } } @@ -986,7 +988,7 @@ impl mem_categorization_ctxt { } for &slice_pat in slice.iter() { let slice_ty = self.pat_ty(slice_pat); - let slice_cmt = self.cat_rvalue_node(pat, slice_ty); + let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty); self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y)); } for &after_pat in after.iter() { diff --git a/src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs b/src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs new file mode 100644 index 0000000000000..c266952f08f08 --- /dev/null +++ b/src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs @@ -0,0 +1,32 @@ +// 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. + +// This tests verifies that unary structs and enum variants +// are treated as rvalues and their lifetime is not bounded to +// the static scope. + +struct Test; + +enum MyEnum { + Variant1 +} + +fn structLifetime() -> &Test { + let testValue = &Test; //~ ERROR borrowed value does not live long enough + testValue +} + +fn variantLifetime() -> &MyEnum { + let testValue = &Variant1; //~ ERROR borrowed value does not live long enough + testValue +} + + +fn main() {} From cb5d7236f14209209e637e475bcefece935a6b56 Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Mon, 27 Jan 2014 23:09:57 +0100 Subject: [PATCH 2/2] Fixes temporary lifetime computation for static items closes: #11854 --- src/librustc/middle/region.rs | 9 ++++++++- ...gions-lifetime-static-items-enclosing-scopes.rs} | 13 ++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) rename src/test/{compile-fail/issue-511.rs => run-pass/regions-lifetime-static-items-enclosing-scopes.rs} (66%) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4ebbd097f2922..9c11b89bb7e7d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -172,7 +172,14 @@ impl RegionMaps { } // else, locate the innermost terminating scope - let mut id = self.encl_scope(expr_id); + // if there's one. Static items, for instance, won't + // have an enclusing scope, hence no scope will be + // returned. + let mut id = match self.opt_encl_scope(expr_id) { + Some(i) => i, + None => { return None; } + }; + let terminating_scopes = self.terminating_scopes.borrow(); while !terminating_scopes.get().contains(&id) { match self.opt_encl_scope(id) { diff --git a/src/test/compile-fail/issue-511.rs b/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs similarity index 66% rename from src/test/compile-fail/issue-511.rs rename to src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs index ed2eede76c670..e20717553c4c4 100644 --- a/src/test/compile-fail/issue-511.rs +++ b/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// This test verifies that temporary lifetime is correctly computed +// for static objects in enclosing scopes. + extern mod extra; use std::cmp::Eq; @@ -15,7 +18,11 @@ fn f(o: &mut Option) { assert!(*o == None); } -fn main() { +pub fn main() { + mod t { + enum E {V=1, A=0} + static C: E = V; + } + f::(&mut None); - //~^ ERROR cannot borrow }