From 215d66b998aaa844e2d43ce7cd459c7fa69e0d9f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 22 Jan 2018 17:36:43 -0500 Subject: [PATCH] do not ICE when return type includes unconstrained anon region It turns out that this *can* happen after all, if the region is only used in projections from the input types. --- src/librustc_typeck/astconv.rs | 35 +++++++++++++++++++--------------- src/test/ui/issue-47511.rs | 35 ++++++++++++++++++++++++++++++++++ src/test/ui/issue-47511.stderr | 16 ++++++++++++++++ 3 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/issue-47511.rs create mode 100644 src/test/ui/issue-47511.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 4616b4cf80c97..86deed864057a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1206,22 +1206,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let output = bare_fn_ty.output(); let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); for br in late_bound_in_ret.difference(&late_bound_in_args) { - let br_name = match *br { - ty::BrNamed(_, name) => name, - _ => { - span_bug!( - decl.output.span(), - "anonymous bound region {:?} in return but not args", - br); - } + let lifetime_name = match *br { + ty::BrNamed(_, name) => format!("lifetime `{}`,", name), + ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => format!("an anonymous lifetime"), }; - struct_span_err!(tcx.sess, - decl.output.span(), - E0581, - "return type references lifetime `{}`, \ - which does not appear in the fn input types", - br_name) - .emit(); + let mut err = struct_span_err!(tcx.sess, + decl.output.span(), + E0581, + "return type references {} \ + which is not constrained by the fn input types", + lifetime_name); + if let ty::BrAnon(_) = *br { + // The only way for an anonymous lifetime to wind up + // in the return type but **also** be unconstrained is + // if it only appears in "associated types" in the + // input. See #47511 for an example. In this case, + // though we can easily give a hint that ought to be + // relevant. + err.note("lifetimes appearing in an associated type \ + are not considered constrained"); + } + err.emit(); } bare_fn_ty diff --git a/src/test/ui/issue-47511.rs b/src/test/ui/issue-47511.rs new file mode 100644 index 0000000000000..df4ff301bc9ce --- /dev/null +++ b/src/test/ui/issue-47511.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #47511: anonymous lifetimes can appear +// unconstrained in a return type, but only if they appear just once +// in the input, as the input to a projection. + +fn f(_: X) -> X { + //~^ ERROR return type references an anonymous lifetime + unimplemented!() +} + +fn g<'a>(_: X<'a>) -> X<'a> { + //~^ ERROR return type references lifetime `'a`, which is not constrained + unimplemented!() +} + +type X<'a> = <&'a () as Trait>::Value; + +trait Trait { + type Value; +} + +impl<'a> Trait for &'a () { + type Value = (); +} + +fn main() {} diff --git a/src/test/ui/issue-47511.stderr b/src/test/ui/issue-47511.stderr new file mode 100644 index 0000000000000..fabd6b6c25396 --- /dev/null +++ b/src/test/ui/issue-47511.stderr @@ -0,0 +1,16 @@ +error[E0581]: return type references an anonymous lifetime which is not constrained by the fn input types + --> $DIR/issue-47511.rs:15:15 + | +15 | fn f(_: X) -> X { + | ^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types + --> $DIR/issue-47511.rs:20:23 + | +20 | fn g<'a>(_: X<'a>) -> X<'a> { + | ^^^^^ + +error: aborting due to 2 previous errors +