mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-13 16:22:57 +00:00
Constrain operands to outlive the operation. Fixes #21422.
This commit is contained in:
parent
801bc48939
commit
f2529ac10d
@ -675,6 +675,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
|||||||
sup,
|
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) => {
|
infer::AddrOf(span) => {
|
||||||
self.tcx.sess.span_err(
|
self.tcx.sess.span_err(
|
||||||
span,
|
span,
|
||||||
@ -1593,6 +1604,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
|||||||
span,
|
span,
|
||||||
"...so that return value is valid for the call");
|
"...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) => {
|
infer::AddrOf(span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
|
@ -210,6 +210,9 @@ pub enum SubregionOrigin<'tcx> {
|
|||||||
// Region in return type of invoked fn must enclose call
|
// Region in return type of invoked fn must enclose call
|
||||||
CallReturn(Span),
|
CallReturn(Span),
|
||||||
|
|
||||||
|
// Operands must be in scope
|
||||||
|
Operand(Span),
|
||||||
|
|
||||||
// Region resulting from a `&` expr must enclose the `&` expr
|
// Region resulting from a `&` expr must enclose the `&` expr
|
||||||
AddrOf(Span),
|
AddrOf(Span),
|
||||||
|
|
||||||
@ -1195,6 +1198,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
|||||||
CallRcvr(a) => a,
|
CallRcvr(a) => a,
|
||||||
CallArg(a) => a,
|
CallArg(a) => a,
|
||||||
CallReturn(a) => a,
|
CallReturn(a) => a,
|
||||||
|
Operand(a) => a,
|
||||||
AddrOf(a) => a,
|
AddrOf(a) => a,
|
||||||
AutoBorrow(a) => a,
|
AutoBorrow(a) => a,
|
||||||
SafeDestructor(a) => a,
|
SafeDestructor(a) => a,
|
||||||
@ -1258,6 +1262,7 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
|
|||||||
CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)),
|
CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)),
|
||||||
CallArg(a) => format!("CallArg({})", a.repr(tcx)),
|
CallArg(a) => format!("CallArg({})", a.repr(tcx)),
|
||||||
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
|
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
|
||||||
|
Operand(a) => format!("Operand({})", a.repr(tcx)),
|
||||||
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
|
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
|
||||||
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
|
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
|
||||||
SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)),
|
SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)),
|
||||||
|
@ -610,6 +610,20 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
|||||||
visit::walk_expr(rcx, 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 => {
|
ast::ExprUnary(op, ref lhs) if has_method_map => {
|
||||||
let implicitly_ref_args = !ast_util::is_by_value_unop(op);
|
let implicitly_ref_args = !ast_util::is_by_value_unop(op);
|
||||||
|
|
||||||
|
25
src/test/run-pass/regions-issue-21422.rs
Normal file
25
src/test/run-pass/regions-issue-21422.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user