Constrain operands to outlive the operation. Fixes #21422.

This commit is contained in:
Niko Matsakis 2015-02-12 12:48:54 -05:00
parent 801bc48939
commit f2529ac10d
4 changed files with 60 additions and 0 deletions

View File

@ -675,6 +675,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
sup,
"");
}
infer::Operand(span) => {
self.tcx.sess.span_err(
span,
"lifetime of operand does not outlive \
the operation");
note_and_explain_region(
self.tcx,
"the operand is only valid for ",
sup,
"");
}
infer::AddrOf(span) => {
self.tcx.sess.span_err(
span,
@ -1593,6 +1604,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
span,
"...so that return value is valid for the call");
}
infer::Operand(span) => {
self.tcx.sess.span_err(
span,
"...so that operand is valid for operation");
}
infer::AddrOf(span) => {
self.tcx.sess.span_note(
span,

View File

@ -210,6 +210,9 @@ pub enum SubregionOrigin<'tcx> {
// Region in return type of invoked fn must enclose call
CallReturn(Span),
// Operands must be in scope
Operand(Span),
// Region resulting from a `&` expr must enclose the `&` expr
AddrOf(Span),
@ -1195,6 +1198,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
CallRcvr(a) => a,
CallArg(a) => a,
CallReturn(a) => a,
Operand(a) => a,
AddrOf(a) => a,
AutoBorrow(a) => a,
SafeDestructor(a) => a,
@ -1258,6 +1262,7 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)),
CallArg(a) => format!("CallArg({})", a.repr(tcx)),
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
Operand(a) => format!("Operand({})", a.repr(tcx)),
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)),

View File

@ -610,6 +610,20 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
visit::walk_expr(rcx, expr);
}
ast::ExprBinary(_, ref lhs, ref rhs) => {
// If you do `x OP y`, then the types of `x` and `y` must
// outlive the operation you are performing.
let lhs_ty = rcx.resolve_expr_type_adjusted(&**lhs);
let rhs_ty = rcx.resolve_expr_type_adjusted(&**rhs);
for &ty in [lhs_ty, rhs_ty].iter() {
type_must_outlive(rcx,
infer::Operand(expr.span),
ty,
ty::ReScope(CodeExtent::from_node_id(expr.id)));
}
visit::walk_expr(rcx, expr);
}
ast::ExprUnary(op, ref lhs) if has_method_map => {
let implicitly_ref_args = !ast_util::is_by_value_unop(op);

View File

@ -0,0 +1,25 @@
// Copyright 2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Regression test for issue #21422, which was related to failing to
// add inference constraints that the operands of a binary operator
// should outlive the binary operation itself.
pub struct P<'a> {
_ptr: *const &'a u8,
}
impl <'a> PartialEq for P<'a> {
fn eq(&self, other: &P<'a>) -> bool {
(self as *const _) == (other as *const _)
}
}
fn main() {}