diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index df857be85adab..d104ff0891d34 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -513,6 +513,7 @@ E0790: include_str!("./error_codes/E0790.md"), E0791: include_str!("./error_codes/E0791.md"), E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), +E0794: include_str!("./error_codes/E0794.md"), } // Undocumented removed error codes. Note that many removed error codes are documented. diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md new file mode 100644 index 0000000000000..a33802885c006 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0794.md @@ -0,0 +1,64 @@ +A lifetime parameter of a function definition is called *late-bound* if it both: + +1. appears in an argument type +2. does not appear in a generic type constraint + +You cannot specify lifetime arguments for late-bound lifetime parameters. + +Erroneous code example: + +```compile_fail,E0794 +fn foo<'a>(x: &'a str) -> &'a str { x } +let _ = foo::<'static>; +``` + +The type of a concrete instance of a generic function is universally quantified +over late-bound lifetime parameters. This is because we want the function to +work for any lifetime substituted for the late-bound lifetime parameter, no +matter where the function is called. Consequently, it doesn't make sense to +specify arguments for late-bound lifetime parameters, since they are not +resolved until the function's call site(s). + +To fix the issue, remove the specified lifetime: + +``` +fn foo<'a>(x: &'a str) -> &'a str { x } +let _ = foo; +``` + +### Additional information + +Lifetime parameters that are not late-bound are called *early-bound*. +Confusion may arise from the fact that late-bound and early-bound +lifetime parameters are declared the same way in function definitions. +When referring to a function pointer type, universal quantification over +late-bound lifetime parameters can be made explicit: + +``` +trait BarTrait<'a> {} + +struct Bar<'a> { + s: &'a str +} + +impl<'a> BarTrait<'a> for Bar<'a> {} + +fn bar<'a, 'b, T>(x: &'a str, _t: T) -> &'a str +where T: BarTrait<'b> +{ + x +} + +let bar_fn: for<'a> fn(&'a str, Bar<'static>) -> &'a str = bar; // OK +let bar_fn2 = bar::<'static, Bar>; // Not allowed +let bar_fn3 = bar::; // OK +``` + +In the definition of `bar`, the lifetime parameter `'a` is late-bound, while +`'b` is early-bound. This is reflected in the type annotation for `bar_fn`, +where `'a` is universally quantified and `'b` is substituted by a specific +lifetime. It is not allowed to explicitly specify early-bound lifetime +arguments when late-bound lifetime parameters are present (as for `bar_fn2`, +see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the +types that are constrained by early-bound parameters can be specified (as for +`bar_fn3`). diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 7f6518ffd7148..11c5028744ace 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -618,7 +618,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( if position == GenericArgPosition::Value && args.num_lifetime_params() != param_counts.lifetimes { - let mut err = tcx.sess.struct_span_err(span, msg); + let mut err = struct_span_err!(tcx.sess, span, E0794, "{}", msg); err.span_note(span_late, note); err.emit(); } else { diff --git a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr index 8672e79b3e8c8..463a37d7e3d13 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.full.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.full.stderr @@ -1,4 +1,4 @@ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; @@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; @@ -22,7 +22,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:41:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; @@ -34,7 +34,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:44:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; @@ -94,7 +94,7 @@ LL | let _ = [0; bar::()]; | = help: try adding a `where` bound using this expression: `where [(); bar::()]:` -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:30:23 | LL | let _ = [0; faz::<'a>(&())]; @@ -106,7 +106,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:33:23 | LL | let _ = [0; faz::<'b>(&())]; @@ -134,7 +134,7 @@ LL | let _ = Foo::<{ bar::() }>; | = help: try adding a `where` bound using this expression: `where [(); { bar::() }]:` -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:52:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; @@ -146,7 +146,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:55:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; @@ -160,3 +160,4 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } error: aborting due to 16 previous errors +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index f1353aa99437d..a7bd9c62b0ee3 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -216,7 +216,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: [u8; bar::<{ N }>()]; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:18:23 | LL | let _: [u8; faz::<'a>(&())]; @@ -228,7 +228,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:21:23 | LL | let _: [u8; faz::<'b>(&())]; @@ -251,7 +251,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _: Foo<{ bar::<{ N }>() }>; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:41:24 | LL | let _: Foo<{ faz::<'a>(&()) }>; @@ -263,7 +263,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:44:24 | LL | let _: Foo<{ faz::<'b>(&()) }>; @@ -294,7 +294,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = [0; bar::<{ N }>()]; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:30:23 | LL | let _ = [0; faz::<'a>(&())]; @@ -306,7 +306,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:33:23 | LL | let _ = [0; faz::<'b>(&())]; @@ -329,7 +329,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | let _ = Foo::<{ bar::<{ N }>() }>; | + + -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:52:27 | LL | let _ = Foo::<{ faz::<'a>(&()) }>; @@ -341,7 +341,7 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:55:27 | LL | let _ = Foo::<{ faz::<'b>(&()) }>; @@ -355,5 +355,5 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } error: aborting due to 36 previous errors -Some errors have detailed explanations: E0658, E0747. +Some errors have detailed explanations: E0658, E0747, E0794. For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/late-bound-lifetimes/issue-80618.rs b/tests/ui/late-bound-lifetimes/issue-80618.rs new file mode 100644 index 0000000000000..6aa8ff461a9a9 --- /dev/null +++ b/tests/ui/late-bound-lifetimes/issue-80618.rs @@ -0,0 +1,8 @@ +fn foo<'a>(x: &'a str) -> &'a str { + x +} + +fn main() { + let _ = foo::<'static>; +//~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present [E0794] +} diff --git a/tests/ui/late-bound-lifetimes/issue-80618.stderr b/tests/ui/late-bound-lifetimes/issue-80618.stderr new file mode 100644 index 0000000000000..cf7423fc16feb --- /dev/null +++ b/tests/ui/late-bound-lifetimes/issue-80618.stderr @@ -0,0 +1,15 @@ +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/issue-80618.rs:6:19 + | +LL | let _ = foo::<'static>; + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/issue-80618.rs:1:8 + | +LL | fn foo<'a>(x: &'a str) -> &'a str { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0794`. diff --git a/tests/ui/methods/method-call-lifetime-args-fail.stderr b/tests/ui/methods/method-call-lifetime-args-fail.stderr index 34526256f9975..645d8b8d14ad2 100644 --- a/tests/ui/methods/method-call-lifetime-args-fail.stderr +++ b/tests/ui/methods/method-call-lifetime-args-fail.stderr @@ -30,7 +30,7 @@ note: method defined here, with 2 lifetime parameters: `'a`, `'b` LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } | ^^^^^ -- -- -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:27:15 | LL | S::late::<'static>(S, &0, &0); @@ -42,7 +42,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:29:15 | LL | S::late::<'static, 'static>(S, &0, &0); @@ -54,7 +54,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:31:15 | LL | S::late::<'static, 'static, 'static>(S, &0, &0); @@ -66,7 +66,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:34:21 | LL | S::late_early::<'static, 'static>(S, &0); @@ -78,7 +78,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:36:21 | LL | S::late_early::<'static, 'static, 'static>(S, &0); @@ -90,7 +90,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:40:24 | LL | S::late_implicit::<'static>(S, &0, &0); @@ -102,7 +102,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:42:24 | LL | S::late_implicit::<'static, 'static>(S, &0, &0); @@ -114,7 +114,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:44:24 | LL | S::late_implicit::<'static, 'static, 'static>(S, &0, &0); @@ -126,7 +126,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit(self, _: &u8, _: &u8) {} | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:47:30 | LL | S::late_implicit_early::<'static, 'static>(S, &0); @@ -138,7 +138,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:49:30 | LL | S::late_implicit_early::<'static, 'static, 'static>(S, &0); @@ -150,7 +150,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:52:35 | LL | S::late_implicit_self_early::<'static, 'static>(&S); @@ -162,7 +162,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:54:35 | LL | S::late_implicit_self_early::<'static, 'static, 'static>(&S); @@ -174,7 +174,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } | ^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:57:28 | LL | S::late_unused_early::<'static, 'static>(S); @@ -186,7 +186,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args-fail.rs:59:28 | LL | S::late_unused_early::<'static, 'static, 'static>(S); @@ -232,4 +232,5 @@ LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } error: aborting due to 18 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0794. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/methods/method-call-lifetime-args.stderr b/tests/ui/methods/method-call-lifetime-args.stderr index 64ae79e9bb2b7..b215d5832171f 100644 --- a/tests/ui/methods/method-call-lifetime-args.stderr +++ b/tests/ui/methods/method-call-lifetime-args.stderr @@ -1,4 +1,4 @@ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args.rs:9:15 | LL | S::late::<'static>(S, &0, &0); @@ -10,7 +10,7 @@ note: the late bound lifetime parameter is introduced here LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} | ^^ -error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/method-call-lifetime-args.rs:11:24 | LL | S::late_implicit::<'static>(S, &0, &0); @@ -24,3 +24,4 @@ LL | fn late_implicit(self, _: &u8, _: &u8) {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0794`.