about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-01-22 17:36:43 -0500
committerNiko Matsakis <niko@alum.mit.edu>2018-01-22 17:36:43 -0500
commit215d66b998aaa844e2d43ce7cd459c7fa69e0d9f (patch)
treec4cda5c43db3c7dc9f54f346afe3c6557bf5bd39
parentfdc18b3067b5bad257ccbe7400e3c4fb617e9e18 (diff)
downloadrust-215d66b998aaa844e2d43ce7cd459c7fa69e0d9f.tar.gz
rust-215d66b998aaa844e2d43ce7cd459c7fa69e0d9f.zip
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.
-rw-r--r--src/librustc_typeck/astconv.rs35
-rw-r--r--src/test/ui/issue-47511.rs35
-rw-r--r--src/test/ui/issue-47511.stderr16
3 files changed, 71 insertions, 15 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 4616b4cf80c..86deed86405 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 00000000000..df4ff301bc9
--- /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 <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 #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 00000000000..fabd6b6c253
--- /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
+