From 75563cd7253bb72876c5c97ff2f7813dd1485bc5 Mon Sep 17 00:00:00 2001 From: Christopher Acosta Date: Fri, 27 Jan 2023 22:23:01 +0100 Subject: [PATCH 01/11] Error code E0794 for late-bound lifetime parameter error. --- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0794.md | 64 +++++++++++++++++++ .../src/astconv/generics.rs | 2 +- .../const-arg-in-const-arg.full.stderr | 17 ++--- .../const-arg-in-const-arg.min.stderr | 18 +++--- tests/ui/late-bound-lifetimes/issue-80618.rs | 8 +++ .../late-bound-lifetimes/issue-80618.stderr | 15 +++++ .../method-call-lifetime-args-fail.stderr | 31 ++++----- .../methods/method-call-lifetime-args.stderr | 5 +- 9 files changed, 126 insertions(+), 35 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0794.md create mode 100644 tests/ui/late-bound-lifetimes/issue-80618.rs create mode 100644 tests/ui/late-bound-lifetimes/issue-80618.stderr 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`. From 82297a52753d1420dfbf71839c0274a50b025df8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Feb 2023 16:23:57 +0400 Subject: [PATCH 02/11] expand: Pass `ast::Crate` by reference to AST transforming passes Also some more attributes are passed by reference. --- .../rustc_builtin_macros/src/cmdline_attrs.rs | 4 +- .../src/proc_macro_harness.rs | 12 ++-- .../src/standard_library_imports.rs | 10 +-- .../rustc_builtin_macros/src/test_harness.rs | 2 +- compiler/rustc_expand/src/config.rs | 71 +++++++++---------- compiler/rustc_expand/src/expand.rs | 6 +- compiler/rustc_interface/src/passes.rs | 24 +++---- compiler/rustc_interface/src/queries.rs | 6 +- compiler/rustc_plugin_impl/src/load.rs | 6 +- 9 files changed, 62 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index db05c00d2118a..2b6fcc169be06 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -6,7 +6,7 @@ use rustc_ast::{self as ast, AttrItem, AttrStyle}; use rustc_session::parse::ParseSess; use rustc_span::FileName; -pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { +pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { let mut parser = rustc_parse::new_parser_from_source_str( parse_sess, @@ -36,6 +36,4 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - start_span.to(end_span), )); } - - krate } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index bc513607ddd1d..b2fcd8c5734da 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -44,14 +44,14 @@ struct CollectProcMacros<'a> { } pub fn inject( + krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand, - mut krate: ast::Crate, is_proc_macro_crate: bool, has_proc_macro_decls: bool, is_test_crate: bool, handler: &rustc_errors::Handler, -) -> ast::Crate { +) { let ecfg = ExpansionConfig::default("proc_macro".to_string()); let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); @@ -66,22 +66,20 @@ pub fn inject( }; if has_proc_macro_decls || is_proc_macro_crate { - visit::walk_crate(&mut collect, &krate); + visit::walk_crate(&mut collect, krate); } let macros = collect.macros; if !is_proc_macro_crate { - return krate; + return; } if is_test_crate { - return krate; + return; } let decls = mk_decls(&mut cx, ¯os); krate.items.push(decls); - - krate } impl<'a> CollectProcMacros<'a> { diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e67c0dba68597..d62d5b4cb1487 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -8,16 +8,12 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::DUMMY_SP; use thin_vec::thin_vec; -pub fn inject( - mut krate: ast::Crate, - resolver: &mut dyn ResolverExpand, - sess: &Session, -) -> ast::Crate { +pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: &Session) { let edition = sess.parse_sess.edition; // the first name in this list is the crate name of the crate with the prelude let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) { - return krate; + return; } else if sess.contains_name(&krate.attrs, sym::no_std) { if sess.contains_name(&krate.attrs, sym::compiler_builtins) { &[sym::core] @@ -88,6 +84,4 @@ pub fn inject( ); krate.items.insert(0, use_item); - - krate } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index d8e3db9e8ee09..82bb86892d7ef 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -37,7 +37,7 @@ struct TestCtxt<'a> { /// Traverse the crate, collecting all the test functions, eliding any /// existing main functions, and synthesizing a main test harness -pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) { +pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) { let span_diagnostic = sess.diagnostic(); let panic_strategy = sess.panic_strategy(); let platform_panic_strategy = sess.target.panic_strategy; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index d6cb173ba9ba0..9ef185e9497ce 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -192,38 +192,32 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { } /// `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features( - sess: &Session, - mut krate: ast::Crate, - lint_node_id: NodeId, -) -> (ast::Crate, Features) { +pub fn features(sess: &Session, krate: &mut ast::Crate, lint_node_id: NodeId) -> Features { let mut strip_unconfigured = StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id }; - let unconfigured_attrs = krate.attrs.clone(); + let mut unconfigured_attrs = krate.attrs.clone(); let diag = &sess.parse_sess.span_diagnostic; let err_count = diag.err_count(); - let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) { - None => { - // The entire crate is unconfigured. - krate.attrs = ast::AttrVec::new(); - krate.items = ThinVec::new(); - Features::default() - } - Some(attrs) => { - krate.attrs = attrs; - let features = get_features(sess, &krate.attrs); - if err_count == diag.err_count() { - // Avoid reconfiguring malformed `cfg_attr`s. - strip_unconfigured.features = Some(&features); - // Run configuration again, this time with features available - // so that we can perform feature-gating. - strip_unconfigured.configure_krate_attrs(unconfigured_attrs); - } - features + + krate.attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr)); + if !strip_unconfigured.in_cfg(&krate.attrs) { + // The entire crate is unconfigured. + krate.attrs = ast::AttrVec::new(); + krate.items = ThinVec::new(); + Features::default() + } else { + let features = get_features(sess, &krate.attrs); + if err_count == diag.err_count() { + // Avoid reconfiguring malformed `cfg_attr`s. + strip_unconfigured.features = Some(&features); + // Run configuration again, this time with features available + // so that we can perform feature-gating. + unconfigured_attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr)); + strip_unconfigured.in_cfg(&unconfigured_attrs); } - }; - (krate, features) + features + } } #[macro_export] @@ -254,11 +248,6 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); - self.in_cfg(&attrs).then_some(attrs) - } - /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`. /// This is only used during the invocation of `derive` proc-macros, /// which require that we cfg-expand their entire input. @@ -281,7 +270,7 @@ impl<'a> StripUnconfigured<'a> { .iter() .flat_map(|tree| match tree.clone() { AttrTokenTree::Attributes(mut data) => { - data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); if self.in_cfg(&data.attrs) { data.tokens = LazyAttrTokenStream::new( @@ -319,12 +308,16 @@ impl<'a> StripUnconfigured<'a> { /// the syntax of any `cfg_attr` is incorrect. fn process_cfg_attrs(&self, node: &mut T) { node.visit_attrs(|attrs| { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); }); } - fn process_cfg_attr(&self, attr: Attribute) -> Vec { - if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] } + fn process_cfg_attr(&self, attr: &Attribute) -> Vec { + if attr.has_name(sym::cfg_attr) { + self.expand_cfg_attr(attr, true) + } else { + vec![attr.clone()] + } } /// Parse and expand a single `cfg_attr` attribute into a list of attributes @@ -334,9 +327,9 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec { + pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec { let Some((cfg_predicate, expanded_attrs)) = - rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else { + rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else { return vec![]; }; @@ -365,10 +358,10 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs .into_iter() - .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item))) + .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item))) .collect() } else { - expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect() + expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect() } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4092a192e0c34..6408ccf7c4324 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1688,7 +1688,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { res } - fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) { + fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) { node.visit_attrs(|attrs| { // Repeated `insert` calls is inefficient, but the number of // insertions is almost always 0 or 1 in practice. @@ -1712,7 +1712,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Default::default() } sym::cfg_attr => { - self.expand_cfg_attr(&mut node, attr, pos); + self.expand_cfg_attr(&mut node, &attr, pos); continue; } _ => { @@ -1760,7 +1760,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { continue; } sym::cfg_attr => { - self.expand_cfg_attr(node, attr, pos); + self.expand_cfg_attr(node, &attr, pos); continue; } _ => visit_clobber(node, |node| { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 71bdd4df95ba3..7c1f6d8c9b872 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -76,10 +76,10 @@ pub fn register_plugins<'a>( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, register_lints: impl Fn(&Session, &mut LintStore), - mut krate: ast::Crate, + krate: &mut ast::Crate, crate_name: Symbol, -) -> Result<(ast::Crate, LintStore)> { - krate = sess.time("attributes_injection", || { +) -> Result { + sess.time("attributes_injection", || { rustc_builtin_macros::cmdline_attrs::inject( krate, &sess.parse_sess, @@ -87,7 +87,7 @@ pub fn register_plugins<'a>( ) }); - let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); + let features = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); // these need to be set "early" so that expansion sees `quote` if enabled. sess.init_features(features); @@ -117,8 +117,8 @@ pub fn register_plugins<'a>( let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); register_lints(sess, &mut lint_store); - let registrars = - sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate)); + let registrars = sess + .time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate.attrs)); sess.time("plugin_registration", || { let mut registry = plugin::Registry { lint_store: &mut lint_store }; for registrar in registrars { @@ -126,7 +126,7 @@ pub fn register_plugins<'a>( } }); - Ok((krate, lint_store)) + Ok(lint_store) } fn pre_expansion_lint<'a>( @@ -181,8 +181,8 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); - krate = sess.time("crate_injection", || { - rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess) + sess.time("crate_injection", || { + rustc_builtin_macros::standard_library_imports::inject(&mut krate, resolver, sess) }); util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); @@ -263,7 +263,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) }); sess.time("maybe_building_test_harness", || { - rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate) + rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver) }); let has_proc_macro_decls = sess.time("AST_validation", || { @@ -287,12 +287,12 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) sess.emit_warning(errors::ProcMacroCratePanicAbort); } - krate = sess.time("maybe_create_a_macro_crate", || { + sess.time("maybe_create_a_macro_crate", || { let is_test_crate = sess.opts.test; rustc_builtin_macros::proc_macro_harness::inject( + &mut krate, sess, resolver, - krate, is_proc_macro_crate, has_proc_macro_decls, is_test_crate, diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 58ad044b399b6..c618297bdc04d 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -136,14 +136,14 @@ impl<'tcx> Queries<'tcx> { pub fn register_plugins(&self) -> Result)>> { self.register_plugins.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let krate = self.parse()?.steal(); + let mut krate = self.parse()?.steal(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; - let (krate, lint_store) = passes::register_plugins( + let lint_store = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), - krate, + &mut krate, crate_name, )?; diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs index 8e75e969ae032..27e5cb9f0d014 100644 --- a/compiler/rustc_plugin_impl/src/load.rs +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -3,7 +3,7 @@ use crate::errors::{LoadPluginError, MalformedPluginAttribute}; use crate::Registry; use libloading::Library; -use rustc_ast::Crate; +use rustc_ast::Attribute; use rustc_metadata::locator; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; @@ -20,11 +20,11 @@ type PluginRegistrarFn = fn(&mut Registry<'_>); pub fn load_plugins( sess: &Session, metadata_loader: &dyn MetadataLoader, - krate: &Crate, + attrs: &[Attribute], ) -> Vec { let mut plugins = Vec::new(); - for attr in &krate.attrs { + for attr in attrs { if !attr.has_name(sym::plugin) { continue; } From 0261d25a46a33adbad617365381df1460e06d851 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 14 Mar 2023 16:09:39 +0400 Subject: [PATCH 03/11] Add some tests for the current `#![cfg(FALSE)]` crate behavior --- tests/ui/cfg/auxiliary/cfg_false_lib.rs | 6 +++++ tests/ui/cfg/cfg-false-feature.rs | 20 ++++++++++++++ tests/ui/cfg/cfg-false-feature.stderr | 35 +++++++++++++++++++++++++ tests/ui/cfg/cfg_false_no_std.rs | 11 ++++++++ 4 files changed, 72 insertions(+) create mode 100644 tests/ui/cfg/auxiliary/cfg_false_lib.rs create mode 100644 tests/ui/cfg/cfg-false-feature.rs create mode 100644 tests/ui/cfg/cfg-false-feature.stderr create mode 100644 tests/ui/cfg/cfg_false_no_std.rs diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs new file mode 100644 index 0000000000000..3c011d72b02c5 --- /dev/null +++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs @@ -0,0 +1,6 @@ +// It is unclear whether a fully unconfigured crate should link to standard library, +// or what its `no_std`/`no_core`/`compiler_builtins` status, more precisely. +// Currently the usual standard library prelude is added to such crates, +// and therefore they link to libstd. + +#![cfg(FALSE)] diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs new file mode 100644 index 0000000000000..21ea3ec79b4d6 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.rs @@ -0,0 +1,20 @@ +// It is unclear which features should be in effect in a fully unconfigured crate (issue #104633). +// Currently none on the features are in effect, so we get the feature gates reported. + +// check-pass +// compile-flags: --crate-type lib + +#![feature(decl_macro)] +#![cfg(FALSE)] +#![feature(box_syntax)] + +macro mac() {} //~ WARN `macro` is experimental + //~| WARN unstable syntax can change at any point in the future + +trait A = Clone; //~ WARN trait aliases are experimental + //~| WARN unstable syntax can change at any point in the future + +fn main() { + let box _ = Box::new(0); //~ WARN box pattern syntax is experimental + //~| WARN unstable syntax can change at any point in the future +} diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr new file mode 100644 index 0000000000000..14673fbdb1444 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.stderr @@ -0,0 +1,35 @@ +warning: trait aliases are experimental + --> $DIR/cfg-false-feature.rs:14:1 + | +LL | trait A = Clone; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: `macro` is experimental + --> $DIR/cfg-false-feature.rs:11:1 + | +LL | macro mac() {} + | ^^^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: box pattern syntax is experimental + --> $DIR/cfg-false-feature.rs:18:9 + | +LL | let box _ = Box::new(0); + | ^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 3 warnings emitted + diff --git a/tests/ui/cfg/cfg_false_no_std.rs b/tests/ui/cfg/cfg_false_no_std.rs new file mode 100644 index 0000000000000..319ea078187c2 --- /dev/null +++ b/tests/ui/cfg/cfg_false_no_std.rs @@ -0,0 +1,11 @@ +// Currently no error because the panic handler is supplied by libstd linked though the empty +// library, but the desirable behavior is unclear (see comments in cfg_false_lib.rs). + +// check-pass +// aux-build: cfg_false_lib.rs + +#![no_std] + +extern crate cfg_false_lib as _; + +fn main() {} From bf00e7da03723fdce3045da0ba6ba0e0f1b1ca3f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 14 Mar 2023 16:53:04 +0400 Subject: [PATCH 04/11] rustc_interface: Add a new query `pre_configure` It partially expands crate attributes before the main expansion pass (without modifying the crate), and the produced preliminary crate attribute list is used for querying a few attributes that are required very early. Crate-level cfg attributes are then expanded normally during the main expansion pass, like attributes on any other nodes. --- .../src/standard_library_imports.rs | 17 +++++-- compiler/rustc_driver_impl/src/lib.rs | 2 +- compiler/rustc_expand/src/base.rs | 2 + compiler/rustc_expand/src/config.rs | 40 +++++----------- compiler/rustc_expand/src/expand.rs | 10 +++- compiler/rustc_interface/src/passes.rs | 46 ++++++++++--------- compiler/rustc_interface/src/queries.rs | 41 +++++++++++++---- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 11 +++-- compiler/rustc_resolve/src/macros.rs | 4 +- tests/ui-fulldeps/lint-tool-test.rs | 1 - tests/ui-fulldeps/lint-tool-test.stderr | 32 ++++++------- 13 files changed, 113 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index d62d5b4cb1487..e977f43eb6a2b 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -8,14 +8,20 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::DUMMY_SP; use thin_vec::thin_vec; -pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: &Session) { +pub fn inject( + krate: &mut ast::Crate, + pre_configured_attrs: &[ast::Attribute], + resolver: &mut dyn ResolverExpand, + sess: &Session, +) -> usize { + let orig_num_items = krate.items.len(); let edition = sess.parse_sess.edition; // the first name in this list is the crate name of the crate with the prelude - let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) { - return; - } else if sess.contains_name(&krate.attrs, sym::no_std) { - if sess.contains_name(&krate.attrs, sym::compiler_builtins) { + let names: &[Symbol] = if sess.contains_name(pre_configured_attrs, sym::no_core) { + return 0; + } else if sess.contains_name(pre_configured_attrs, sym::no_std) { + if sess.contains_name(pre_configured_attrs, sym::compiler_builtins) { &[sym::core] } else { &[sym::core, sym::compiler_builtins] @@ -84,4 +90,5 @@ pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: & ); krate.items.insert(0, use_item); + krate.items.len() - orig_num_items } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 555917c8b5e9c..3fd18a98b12cf 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -353,7 +353,7 @@ fn run_compiler( { let plugins = queries.register_plugins()?; - let (_, lint_store) = &*plugins.borrow(); + let (.., lint_store) = &*plugins.borrow(); // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 713e4fbbdce23..53fa3f096b9dd 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1004,6 +1004,7 @@ pub struct ExpansionData { pub struct ExtCtxt<'a> { pub sess: &'a Session, pub ecfg: expand::ExpansionConfig<'a>, + pub num_standard_library_imports: usize, pub reduced_recursion_limit: Option, pub root_path: PathBuf, pub resolver: &'a mut dyn ResolverExpand, @@ -1032,6 +1033,7 @@ impl<'a> ExtCtxt<'a> { ExtCtxt { sess, ecfg, + num_standard_library_imports: 0, reduced_recursion_limit: None, resolver, lint_store, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 9ef185e9497ce..a78dc0678d5da 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -24,7 +24,6 @@ use rustc_session::Session; use rustc_span::edition::{Edition, ALL_EDITIONS}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use thin_vec::ThinVec; /// A folder that strips out items that do not belong in the current configuration. pub struct StripUnconfigured<'a> { @@ -37,7 +36,7 @@ pub struct StripUnconfigured<'a> { pub lint_node_id: NodeId, } -fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { +pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) { sess.emit_err(FeatureRemoved { span, @@ -191,33 +190,16 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { features } -/// `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features(sess: &Session, krate: &mut ast::Crate, lint_node_id: NodeId) -> Features { - let mut strip_unconfigured = - StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id }; - - let mut unconfigured_attrs = krate.attrs.clone(); - let diag = &sess.parse_sess.span_diagnostic; - let err_count = diag.err_count(); - - krate.attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr)); - if !strip_unconfigured.in_cfg(&krate.attrs) { - // The entire crate is unconfigured. - krate.attrs = ast::AttrVec::new(); - krate.items = ThinVec::new(); - Features::default() - } else { - let features = get_features(sess, &krate.attrs); - if err_count == diag.err_count() { - // Avoid reconfiguring malformed `cfg_attr`s. - strip_unconfigured.features = Some(&features); - // Run configuration again, this time with features available - // so that we can perform feature-gating. - unconfigured_attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr)); - strip_unconfigured.in_cfg(&unconfigured_attrs); - } - features - } +pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec { + let strip_unconfigured = StripUnconfigured { + sess, + features: None, + config_tokens: false, + lint_node_id: ast::CRATE_NODE_ID, + }; + let attrs: ast::AttrVec = + attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect(); + if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() } } #[macro_export] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6408ccf7c4324..ec40911545f50 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { ) -> Result { Ok(noop_flat_map(node, collector)) } + fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) { + collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() }); + } } impl InvocationCollectorNode for P { @@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate { fn noop_visit(&mut self, visitor: &mut V) { noop_visit_crate(self, visitor) } + fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) { + self.attrs.clear(); + // Standard prelude imports are left in the crate for backward compatibility. + self.items.truncate(collector.cx.num_standard_library_imports); + } } impl InvocationCollectorNode for P { @@ -1756,7 +1764,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { continue; } - self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() }); + node.expand_cfg_false(self, span); continue; } sym::cfg_attr => { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7c1f6d8c9b872..adaf33ef271e0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -3,7 +3,6 @@ use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; -use ast::CRATE_NODE_ID; use rustc_ast::{self as ast, visit}; use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; @@ -76,22 +75,14 @@ pub fn register_plugins<'a>( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, register_lints: impl Fn(&Session, &mut LintStore), - krate: &mut ast::Crate, + pre_configured_attrs: &[ast::Attribute], crate_name: Symbol, ) -> Result { - sess.time("attributes_injection", || { - rustc_builtin_macros::cmdline_attrs::inject( - krate, - &sess.parse_sess, - &sess.opts.unstable_opts.crate_attr, - ) - }); - - let features = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); // these need to be set "early" so that expansion sees `quote` if enabled. + let features = rustc_expand::config::features(sess, pre_configured_attrs); sess.init_features(features); - let crate_types = util::collect_crate_types(sess, &krate.attrs); + let crate_types = util::collect_crate_types(sess, pre_configured_attrs); sess.init_crate_types(crate_types); let stable_crate_id = StableCrateId::new( @@ -117,8 +108,9 @@ pub fn register_plugins<'a>( let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); register_lints(sess, &mut lint_store); - let registrars = sess - .time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate.attrs)); + let registrars = sess.time("plugin_loading", || { + plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs) + }); sess.time("plugin_registration", || { let mut registry = plugin::Registry { lint_store: &mut lint_store }; for registrar in registrars { @@ -173,7 +165,11 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> { /// harness if one is to be provided, injection of a dependency on the /// standard library and prelude, and name resolution. #[instrument(level = "trace", skip(krate, resolver))] -fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) -> ast::Crate { +fn configure_and_expand( + mut krate: ast::Crate, + pre_configured_attrs: &[ast::Attribute], + resolver: &mut Resolver<'_, '_>, +) -> ast::Crate { let tcx = resolver.tcx(); let sess = tcx.sess; let lint_store = unerased_lint_store(tcx); @@ -181,11 +177,16 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); - sess.time("crate_injection", || { - rustc_builtin_macros::standard_library_imports::inject(&mut krate, resolver, sess) + let num_standard_library_imports = sess.time("crate_injection", || { + rustc_builtin_macros::standard_library_imports::inject( + &mut krate, + pre_configured_attrs, + resolver, + sess, + ) }); - util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); + util::check_attr_crate_type(sess, pre_configured_attrs, &mut resolver.lint_buffer()); // Expand all macros krate = sess.time("macro_expand_crate", || { @@ -222,7 +223,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) // Create the config for macro expansion let features = sess.features_untracked(); - let recursion_limit = get_recursion_limit(&krate.attrs, sess); + let recursion_limit = get_recursion_limit(pre_configured_attrs, sess); let cfg = rustc_expand::expand::ExpansionConfig { features: Some(features), recursion_limit, @@ -235,6 +236,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) let lint_store = LintStoreExpandImpl(lint_store); let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store)); + ecx.num_standard_library_imports = num_standard_library_imports; // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); @@ -557,9 +559,9 @@ fn resolver_for_lowering<'tcx>( ) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc)> { let arenas = Resolver::arenas(); let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`. - let krate = tcx.crate_for_resolver(()).steal(); - let mut resolver = Resolver::new(tcx, &krate, &arenas); - let krate = configure_and_expand(krate, &mut resolver); + let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal(); + let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas); + let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver); // Make sure we don't mutate the cstore from here on. tcx.untracked().cstore.leak(); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index c618297bdc04d..d2293780836d5 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -88,8 +88,9 @@ pub struct Queries<'tcx> { dep_graph_future: Query>, parse: Query, + pre_configure: Query<(ast::Crate, ast::AttrVec)>, crate_name: Query, - register_plugins: Query<(ast::Crate, Lrc)>, + register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc)>, dep_graph: Query, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, @@ -106,6 +107,7 @@ impl<'tcx> Queries<'tcx> { hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), dep_graph_future: Default::default(), parse: Default::default(), + pre_configure: Default::default(), crate_name: Default::default(), register_plugins: Default::default(), dep_graph: Default::default(), @@ -133,17 +135,36 @@ impl<'tcx> Queries<'tcx> { .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) } - pub fn register_plugins(&self) -> Result)>> { + pub fn pre_configure(&self) -> Result> { + self.pre_configure.compute(|| { + let mut krate = self.parse()?.steal(); + + let sess = self.session(); + rustc_builtin_macros::cmdline_attrs::inject( + &mut krate, + &sess.parse_sess, + &sess.opts.unstable_opts.crate_attr, + ); + + let pre_configured_attrs = + rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); + Ok((krate, pre_configured_attrs)) + }) + } + + pub fn register_plugins( + &self, + ) -> Result)>> { self.register_plugins.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let mut krate = self.parse()?.steal(); + let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; let lint_store = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), - &mut krate, + &pre_configured_attrs, crate_name, )?; @@ -154,17 +175,17 @@ impl<'tcx> Queries<'tcx> { // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - Ok((krate, Lrc::new(lint_store))) + Ok((krate, pre_configured_attrs, Lrc::new(lint_store))) }) } fn crate_name(&self) -> Result> { self.crate_name.compute(|| { Ok({ - let parse_result = self.parse()?; - let krate = parse_result.borrow(); + let pre_configure_result = self.pre_configure()?; + let (_, pre_configured_attrs) = &*pre_configure_result.borrow(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - find_crate_name(self.session(), &krate.attrs) + find_crate_name(self.session(), pre_configured_attrs) }) }) } @@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> { pub fn global_ctxt(&'tcx self) -> Result>> { self.gcx.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let (krate, lint_store) = self.register_plugins()?.steal(); + let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal(); let sess = self.session(); @@ -215,7 +236,7 @@ impl<'tcx> Queries<'tcx> { feed.crate_name(crate_name); let feed = tcx.feed_unit_query(); - feed.crate_for_resolver(tcx.arena.alloc(Steal::new(krate))); + feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.metadata_loader( tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())), ); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 72907fba5e62c..9f16ecbdaa933 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -36,7 +36,7 @@ macro_rules! arena_types { )>, [] output_filenames: std::sync::Arc, [] metadata_loader: rustc_data_structures::steal::Steal>, - [] crate_for_resolver: rustc_data_structures::steal::Steal, + [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 75f05c4af23da..919fa3eceaac2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2116,7 +2116,7 @@ rustc_queries! { desc { "raw operations for metadata file access" } } - query crate_for_resolver((): ()) -> &'tcx Steal { + query crate_for_resolver((): ()) -> &'tcx Steal<(rustc_ast::Crate, rustc_ast::AttrVec)> { feedable no_hash desc { "the ast before macro expansion and name resolution" } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cd90fd3ef84d8..aba391bd38975 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1180,7 +1180,8 @@ impl<'tcx> Resolver<'_, 'tcx> { impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - krate: &Crate, + attrs: &[ast::Attribute], + crate_span: Span, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); @@ -1189,8 +1190,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None, ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), ExpnId::root(), - krate.spans.inner_span, - tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude), + crate_span, + tcx.sess.contains_name(attrs, sym::no_implicit_prelude), &mut module_map, ); let empty_module = arenas.new_module( @@ -1222,9 +1223,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .map(|(name, _)| (Ident::from_str(name), Default::default())) .collect(); - if !tcx.sess.contains_name(&krate.attrs, sym::no_core) { + if !tcx.sess.contains_name(attrs, sym::no_core) { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); - if !tcx.sess.contains_name(&krate.attrs, sym::no_std) { + if !tcx.sess.contains_name(attrs, sym::no_std) { extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 37153854f7e7f..e055ea1bb6ec9 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -112,8 +112,8 @@ fn fast_print_path(path: &ast::Path) -> Symbol { pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); - let krate = tcx.crate_for_resolver(()).borrow(); - for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) { + let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); + for attr in tcx.sess.filter_by_name(pre_configured_attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { diff --git a/tests/ui-fulldeps/lint-tool-test.rs b/tests/ui-fulldeps/lint-tool-test.rs index f92bcd213b844..9a87646e77833 100644 --- a/tests/ui-fulldeps/lint-tool-test.rs +++ b/tests/ui-fulldeps/lint-tool-test.rs @@ -9,7 +9,6 @@ #![cfg_attr(foo, warn(test_lint))] //~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future //~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future -//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future #![deny(clippy_group)] //~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future //~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future diff --git a/tests/ui-fulldeps/lint-tool-test.stderr b/tests/ui-fulldeps/lint-tool-test.stderr index 027cf8f80cff2..9dafcbc039db4 100644 --- a/tests/ui-fulldeps/lint-tool-test.stderr +++ b/tests/ui-fulldeps/lint-tool-test.stderr @@ -1,19 +1,13 @@ -warning: lint name `test_lint` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:9:23 - | -LL | #![cfg_attr(foo, warn(test_lint))] - | ^^^^^^^^^ help: change it to: `clippy::test_lint` - | - = note: `#[warn(renamed_and_removed_lints)]` on by default - warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 + --> $DIR/lint-tool-test.rs:28:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` @@ -25,26 +19,26 @@ LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` error: item is named 'lintme' - --> $DIR/lint-tool-test.rs:18:1 + --> $DIR/lint-tool-test.rs:17:1 | LL | fn lintme() { } | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ = note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]` error: item is named 'lintmetoo' - --> $DIR/lint-tool-test.rs:26:5 + --> $DIR/lint-tool-test.rs:25:5 | LL | fn lintmetoo() { } | ^^^^^^^^^^^^^^^^^^ @@ -52,13 +46,13 @@ LL | fn lintmetoo() { } = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]` warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 + --> $DIR/lint-tool-test.rs:28:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` warning: unknown lint: `this_lint_does_not_exist` - --> $DIR/lint-tool-test.rs:33:8 + --> $DIR/lint-tool-test.rs:32:8 | LL | #[deny(this_lint_does_not_exist)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,16 +74,16 @@ LL | #![cfg_attr(foo, warn(test_lint))] | ^^^^^^^^^ help: change it to: `clippy::test_lint` warning: lint name `clippy_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:13:9 + --> $DIR/lint-tool-test.rs:12:9 | LL | #![deny(clippy_group)] | ^^^^^^^^^^^^ help: change it to: `clippy::group` warning: lint name `test_group` is deprecated and may not have an effect in the future. - --> $DIR/lint-tool-test.rs:29:9 + --> $DIR/lint-tool-test.rs:28:9 | LL | #[allow(test_group)] | ^^^^^^^^^^ help: change it to: `clippy::test_group` -error: aborting due to 2 previous errors; 11 warnings emitted +error: aborting due to 2 previous errors; 10 warnings emitted From 37207536327c10186b1b348cdc57354b35bcbba6 Mon Sep 17 00:00:00 2001 From: "Partha P. Das" Date: Tue, 7 Feb 2023 21:41:28 -0500 Subject: [PATCH 05/11] Implementing " --list --format json" #107307 #49359 --- .gitignore | 1 + compiler/rustc_builtin_macros/src/test.rs | 27 ++- compiler/rustc_span/src/source_map.rs | 31 ++- library/test/src/console.rs | 83 +++++--- library/test/src/formatters/json.rs | 52 ++++- library/test/src/formatters/junit.rs | 14 +- library/test/src/formatters/mod.rs | 6 +- library/test/src/formatters/pretty.rs | 29 ++- library/test/src/formatters/terse.rs | 14 +- library/test/src/tests.rs | 200 ++++++++++++++++++ library/test/src/types.rs | 10 + src/librustdoc/doctest.rs | 10 + src/tools/compiletest/src/header.rs | 10 + tests/pretty/tests-are-sorted.pp | 22 +- tests/pretty/tests-are-sorted.rs | 3 +- .../tests-listing-format-default.rs | 18 ++ .../tests-listing-format-default.run.stdout | 5 + ...isting-format-json-without-unstableopts.rs | 18 ++ ...ormat-json-without-unstableopts.run.stderr | 1 + .../test-attrs/tests-listing-format-json.rs | 20 ++ .../tests-listing-format-json.run.stdout | 5 + .../test-attrs/tests-listing-format-terse.rs | 18 ++ .../tests-listing-format-terse.run.stdout | 3 + 23 files changed, 554 insertions(+), 46 deletions(-) create mode 100644 tests/ui/test-attrs/tests-listing-format-default.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-default.run.stdout create mode 100644 tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr create mode 100644 tests/ui/test-attrs/tests-listing-format-json.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-json.run.stdout create mode 100644 tests/ui/test-attrs/tests-listing-format-terse.rs create mode 100644 tests/ui/test-attrs/tests-listing-format-terse.run.stdout diff --git a/.gitignore b/.gitignore index ce797a7a8371d..089831b8013f7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ Session.vim .project .favorites.json .settings/ +.vs/ ## Tool .valgrindrc diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index e02c7e6c01b7e..007d14b0e748c 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_expand::base::*; use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{FileNameDisplayPreference, Span}; use std::iter; use thin_vec::{thin_vec, ThinVec}; @@ -231,6 +231,8 @@ pub fn expand_test_or_bench( &item.ident, )); + let location_info = get_location_info(cx, &item); + let mut test_const = cx.item( sp, Ident::new(item.ident.name, sp), @@ -280,6 +282,16 @@ pub fn expand_test_or_bench( cx.expr_none(sp) }, ), + // source_file: + field("source_file", cx.expr_str(sp, location_info.0)), + // start_line: start line of the test fn identifier. + field("start_line", cx.expr_usize(sp, location_info.1)), + // start_col: start column of the test fn identifier. + field("start_col", cx.expr_usize(sp, location_info.2)), + // end_line: end line of the test fn identifier. + field("end_line", cx.expr_usize(sp, location_info.3)), + // end_col: end column of the test fn identifier. + field("end_col", cx.expr_usize(sp, location_info.4)), // compile_fail: true | false field("compile_fail", cx.expr_bool(sp, false)), // no_run: true | false @@ -364,6 +376,19 @@ pub fn expand_test_or_bench( } } +fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) { + let span = item.ident.span; + let (source_file, lo_line, lo_col, hi_line, hi_col) = + cx.sess.source_map().span_to_location_info(span); + + let file_name = match source_file { + Some(sf) => sf.name.display(FileNameDisplayPreference::Remapped).to_string(), + None => "no-location".to_string(), + }; + + (Symbol::intern(&file_name), lo_line, lo_col, hi_line, hi_col) +} + fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String { mod_path .iter() diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index a1cb810a4293b..ee895f53eba9b 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -448,25 +448,36 @@ impl SourceMap { sp: Span, filename_display_pref: FileNameDisplayPreference, ) -> String { - if self.files.borrow().source_files.is_empty() || sp.is_dummy() { - return "no-location".to_string(); - } + let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp); + + let file_name = match source_file { + Some(sf) => sf.name.display(filename_display_pref).to_string(), + None => return "no-location".to_string(), + }; - let lo = self.lookup_char_pos(sp.lo()); - let hi = self.lookup_char_pos(sp.hi()); format!( - "{}:{}:{}{}", - lo.file.name.display(filename_display_pref), - lo.line, - lo.col.to_usize() + 1, + "{file_name}:{lo_line}:{lo_col}{}", if let FileNameDisplayPreference::Short = filename_display_pref { String::new() } else { - format!(": {}:{}", hi.line, hi.col.to_usize() + 1) + format!(": {hi_line}:{hi_col}") } ) } + pub fn span_to_location_info( + &self, + sp: Span, + ) -> (Option>, usize, usize, usize, usize) { + if self.files.borrow().source_files.is_empty() || sp.is_dummy() { + return (None, 0, 0, 0, 0); + } + + let lo = self.lookup_char_pos(sp.lo()); + let hi = self.lookup_char_pos(sp.hi()); + (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1) + } + /// Format the span location suitable for embedding in build artifacts pub fn span_to_embeddable_string(&self, sp: Span) -> String { self.span_to_string(sp, FileNameDisplayPreference::Remapped) diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 1ee68c8540bcc..7eee4ca236190 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -41,6 +41,46 @@ impl Write for OutputLocation { } } +pub struct ConsoleTestDiscoveryState { + pub log_out: Option, + pub tests: usize, + pub benchmarks: usize, + pub ignored: usize, + pub options: Options, +} + +impl ConsoleTestDiscoveryState { + pub fn new(opts: &TestOpts) -> io::Result { + let log_out = match opts.logfile { + Some(ref path) => Some(File::create(path)?), + None => None, + }; + + Ok(ConsoleTestDiscoveryState { + log_out, + tests: 0, + benchmarks: 0, + ignored: 0, + options: opts.options, + }) + } + + pub fn write_log(&mut self, msg: F) -> io::Result<()> + where + S: AsRef, + F: FnOnce() -> S, + { + match self.log_out { + None => Ok(()), + Some(ref mut o) => { + let msg = msg(); + let msg = msg.as_ref(); + o.write_all(msg.as_bytes()) + } + } + } +} + pub struct ConsoleTestState { pub log_out: Option, pub total: usize, @@ -138,53 +178,44 @@ impl ConsoleTestState { // List the tests to console, and optionally to logfile. Filters are honored. pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Result<()> { - let mut output = match term::stdout() { + let output = match term::stdout() { None => OutputLocation::Raw(io::stdout().lock()), Some(t) => OutputLocation::Pretty(t), }; - let quiet = opts.format == OutputFormat::Terse; - let mut st = ConsoleTestState::new(opts)?; - - let mut ntest = 0; - let mut nbench = 0; + let mut out: Box = match opts.format { + OutputFormat::Pretty | OutputFormat::Junit => { + Box::new(PrettyFormatter::new(output, false, 0, false, None)) + } + OutputFormat::Terse => Box::new(TerseFormatter::new(output, false, 0, false)), + OutputFormat::Json => Box::new(JsonFormatter::new(output)), + }; + let mut st = ConsoleTestDiscoveryState::new(opts)?; + out.write_discovery_start()?; for test in filter_tests(opts, tests).into_iter() { use crate::TestFn::*; - let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test; + let TestDescAndFn { desc, testfn } = test; let fntype = match testfn { StaticTestFn(..) | DynTestFn(..) => { - ntest += 1; + st.tests += 1; "test" } StaticBenchFn(..) | DynBenchFn(..) => { - nbench += 1; + st.benchmarks += 1; "benchmark" } }; - writeln!(output, "{name}: {fntype}")?; - st.write_log(|| format!("{fntype} {name}\n"))?; - } + st.ignored += if desc.ignore { 1 } else { 0 }; - fn plural(count: u32, s: &str) -> String { - match count { - 1 => format!("1 {s}"), - n => format!("{n} {s}s"), - } + out.write_test_discovered(&desc, fntype)?; + st.write_log(|| format!("{fntype} {}\n", desc.name))?; } - if !quiet { - if ntest != 0 || nbench != 0 { - writeln!(output)?; - } - - writeln!(output, "{}, {}", plural(ntest, "test"), plural(nbench, "benchmark"))?; - } - - Ok(()) + out.write_discovery_finish(&st) } // Updates `ConsoleTestState` depending on result of the test execution. diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 95d2faf25060f..40976ec5e1c8b 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, io, io::prelude::Write}; use super::OutputFormatter; use crate::{ - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, test_result::TestResult, time, types::TestDesc, @@ -60,6 +60,56 @@ impl JsonFormatter { } impl OutputFormatter for JsonFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + self.writeln_message(&format!(r#"{{ "type": "suite", "event": "discovery" }}"#)) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + let TestDesc { + name, + ignore, + ignore_message, + #[cfg(not(bootstrap))] + source_file, + #[cfg(not(bootstrap))] + start_line, + #[cfg(not(bootstrap))] + start_col, + #[cfg(not(bootstrap))] + end_line, + #[cfg(not(bootstrap))] + end_col, + .. + } = desc; + + #[cfg(bootstrap)] + let source_file = ""; + #[cfg(bootstrap)] + let start_line = 0; + #[cfg(bootstrap)] + let start_col = 0; + #[cfg(bootstrap)] + let end_line = 0; + #[cfg(bootstrap)] + let end_col = 0; + + self.writeln_message(&format!( + r#"{{ "type": "{test_type}", "event": "discovered", "name": "{}", "ignore": {ignore}, "ignore_message": "{}", "source_path": "{}", "start_line": {start_line}, "start_col": {start_col}, "end_line": {end_line}, "end_col": {end_col} }}"#, + EscapedString(name.as_slice()), + ignore_message.unwrap_or(""), + EscapedString(source_file), + )) + } + + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> { + let ConsoleTestDiscoveryState { tests, benchmarks, ignored, .. } = state; + + let total = tests + benchmarks; + self.writeln_message(&format!( + r#"{{ "type": "suite", "event": "completed", "tests": {tests}, "benchmarks": {benchmarks}, "total": {total}, "ignored": {ignored} }}"# + )) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { let shuffle_seed_json = if let Some(shuffle_seed) = shuffle_seed { format!(r#", "shuffle_seed": {shuffle_seed}"#) diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index 7a40ce33cb741..2e07ce3c09923 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -3,7 +3,7 @@ use std::time::Duration; use super::OutputFormatter; use crate::{ - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, test_result::TestResult, time, types::{TestDesc, TestType}, @@ -27,6 +27,18 @@ impl JunitFormatter { } impl OutputFormatter for JunitFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + + fn write_test_discovered(&mut self, _desc: &TestDesc, _test_type: &str) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + + fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) + } + fn write_run_start( &mut self, _test_count: usize, diff --git a/library/test/src/formatters/mod.rs b/library/test/src/formatters/mod.rs index cb67b6491a392..bc6ffebc1d3b2 100644 --- a/library/test/src/formatters/mod.rs +++ b/library/test/src/formatters/mod.rs @@ -1,7 +1,7 @@ use std::{io, io::prelude::Write}; use crate::{ - console::ConsoleTestState, + console::{ConsoleTestDiscoveryState, ConsoleTestState}, test_result::TestResult, time, types::{TestDesc, TestName}, @@ -18,6 +18,10 @@ pub(crate) use self::pretty::PrettyFormatter; pub(crate) use self::terse::TerseFormatter; pub(crate) trait OutputFormatter { + fn write_discovery_start(&mut self) -> io::Result<()>; + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()>; + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()>; + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()>; fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>; fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 247778e515f0d..22654a3400b44 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -3,7 +3,7 @@ use std::{io, io::prelude::Write}; use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, term, test_result::TestResult, time, @@ -181,6 +181,33 @@ impl PrettyFormatter { } impl OutputFormatter for PrettyFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + self.write_plain(format!("{}: {test_type}\n", desc.name)) + } + + fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> { + fn plural(count: usize, s: &str) -> String { + match count { + 1 => format!("1 {s}"), + n => format!("{n} {s}s"), + } + } + + if state.tests != 0 || state.benchmarks != 0 { + self.write_plain("\n")?; + } + + self.write_plain(format!( + "{}, {}\n", + plural(state.tests, "test"), + plural(state.benchmarks, "benchmark") + )) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { let noun = if test_count != 1 { "tests" } else { "test" }; let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed { diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index a431acfbc2753..2931ca6ead0ac 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -3,7 +3,7 @@ use std::{io, io::prelude::Write}; use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, - console::{ConsoleTestState, OutputLocation}, + console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation}, term, test_result::TestResult, time, @@ -167,6 +167,18 @@ impl TerseFormatter { } impl OutputFormatter for TerseFormatter { + fn write_discovery_start(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> { + self.write_plain(format!("{}: {test_type}\n", desc.name)) + } + + fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> { + Ok(()) + } + fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option) -> io::Result<()> { self.total_test_count = test_count; let noun = if test_count != 1 { "tests" } else { "test" }; diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 44776fb0a316d..5ffdbf73fbf93 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -63,6 +63,16 @@ fn one_ignored_one_unignored_test() -> Vec { name: StaticTestName("1"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -75,6 +85,16 @@ fn one_ignored_one_unignored_test() -> Vec { name: StaticTestName("2"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -95,6 +115,16 @@ pub fn do_not_run_ignored_tests() { name: StaticTestName("whatever"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -118,6 +148,16 @@ pub fn ignored_tests_result_in_ignored() { name: StaticTestName("whatever"), ignore: true, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -143,6 +183,16 @@ fn test_should_panic() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -168,6 +218,16 @@ fn test_should_panic_good_message() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage("error message"), compile_fail: false, no_run: false, @@ -198,6 +258,16 @@ fn test_should_panic_bad_message() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -232,6 +302,16 @@ fn test_should_panic_non_string_message_type() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -260,6 +340,16 @@ fn test_should_panic_but_succeeds() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic, compile_fail: false, no_run: false, @@ -288,6 +378,16 @@ fn report_time_test_template(report_time: bool) -> Option { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -325,6 +425,16 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -364,6 +474,16 @@ fn typed_test_desc(test_type: TestType) -> TestDesc { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -476,6 +596,16 @@ pub fn exclude_should_panic_option() { name: StaticTestName("3"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -500,6 +630,16 @@ pub fn exact_filter_match() { name: StaticTestName(name), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -591,6 +731,16 @@ fn sample_tests() -> Vec { name: DynTestName((*name).clone()), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -720,6 +870,16 @@ pub fn test_bench_no_iter() { name: StaticTestName("f"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -743,6 +903,16 @@ pub fn test_bench_iter() { name: StaticTestName("f"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -759,6 +929,16 @@ fn should_sort_failures_before_printing_them() { name: StaticTestName("a"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -769,6 +949,16 @@ fn should_sort_failures_before_printing_them() { name: StaticTestName("b"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -816,6 +1006,16 @@ fn test_dyn_bench_returning_err_fails_when_run_as_test() { name: StaticTestName("whatever"), ignore: false, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 6f2e033095a37..8d4e204c8ac12 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -119,6 +119,16 @@ pub struct TestDesc { pub name: TestName, pub ignore: bool, pub ignore_message: Option<&'static str>, + #[cfg(not(bootstrap))] + pub source_file: &'static str, + #[cfg(not(bootstrap))] + pub start_line: usize, + #[cfg(not(bootstrap))] + pub start_col: usize, + #[cfg(not(bootstrap))] + pub end_line: usize, + #[cfg(not(bootstrap))] + pub end_col: usize, pub should_panic: options::ShouldPanic, pub compile_fail: bool, pub no_run: bool, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 9cf84acc79f8d..aaa83ecce4817 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1057,6 +1057,16 @@ impl Tester for Collector { Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)), }, ignore_message: None, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, // compiler failures are test failures should_panic: test::ShouldPanic::No, compile_fail: config.compile_fail, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d9b39927ca4bc..22a0b1d13be16 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1047,6 +1047,16 @@ pub fn make_test_description( name, ignore, ignore_message, + #[cfg(not(bootstrap))] + source_file: "", + #[cfg(not(bootstrap))] + start_line: 0, + #[cfg(not(bootstrap))] + start_col: 0, + #[cfg(not(bootstrap))] + end_line: 0, + #[cfg(not(bootstrap))] + end_col: 0, should_panic, compile_fail: false, no_run: false, diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp index 15dcd4ed97df4..58f746f2e0ef8 100644 --- a/tests/pretty/tests-are-sorted.pp +++ b/tests/pretty/tests-are-sorted.pp @@ -4,7 +4,7 @@ use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; -// compile-flags: --crate-type=lib --test +// compile-flags: --crate-type=lib --test --remap-path-prefix={{src-base}}/=/the/src/ --remap-path-prefix={{src-base}}\=/the/src/ // pretty-compare-only // pretty-mode:expanded // pp-exact:tests-are-sorted.pp @@ -18,6 +18,11 @@ name: test::StaticTestName("m_test"), ignore: false, ignore_message: ::core::option::Option::None, + source_file: "/the/src/tests-are-sorted.rs", + start_line: 7usize, + start_col: 4usize, + end_line: 7usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, @@ -34,8 +39,13 @@ test::TestDescAndFn { desc: test::TestDesc { name: test::StaticTestName("z_test"), - ignore: false, - ignore_message: ::core::option::Option::None, + ignore: true, + ignore_message: ::core::option::Option::Some("not yet implemented"), + source_file: "/the/src/tests-are-sorted.rs", + start_line: 11usize, + start_col: 4usize, + end_line: 11usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, @@ -43,6 +53,7 @@ }, testfn: test::StaticTestFn(|| test::assert_test_result(z_test())), }; +#[ignore = "not yet implemented"] fn z_test() {} extern crate test; @@ -54,6 +65,11 @@ name: test::StaticTestName("a_test"), ignore: false, ignore_message: ::core::option::Option::None, + source_file: "/the/src/tests-are-sorted.rs", + start_line: 14usize, + start_col: 4usize, + end_line: 14usize, + end_col: 10usize, compile_fail: false, no_run: false, should_panic: test::ShouldPanic::No, diff --git a/tests/pretty/tests-are-sorted.rs b/tests/pretty/tests-are-sorted.rs index 1f737d5471930..39e0922250b8d 100644 --- a/tests/pretty/tests-are-sorted.rs +++ b/tests/pretty/tests-are-sorted.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-type=lib --test +// compile-flags: --crate-type=lib --test --remap-path-prefix={{src-base}}/=/the/src/ --remap-path-prefix={{src-base}}\=/the/src/ // pretty-compare-only // pretty-mode:expanded // pp-exact:tests-are-sorted.pp @@ -7,6 +7,7 @@ fn m_test() {} #[test] +#[ignore = "not yet implemented"] fn z_test() {} #[test] diff --git a/tests/ui/test-attrs/tests-listing-format-default.rs b/tests/ui/test-attrs/tests-listing-format-default.rs new file mode 100644 index 0000000000000..d5df4b57b0591 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-default.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list +// run-pass +// check-run-results + +// Checks the listing of tests with no --format arguments. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-default.run.stdout b/tests/ui/test-attrs/tests-listing-format-default.run.stdout new file mode 100644 index 0000000000000..72337daf02cdf --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-default.run.stdout @@ -0,0 +1,5 @@ +a_test: test +m_test: test +z_test: test + +3 tests, 0 benchmarks diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs new file mode 100644 index 0000000000000..5247f1f8f1746 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format json +// run-fail +// check-run-results + +// Checks that --format json does not work without -Zunstable-options. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr new file mode 100644 index 0000000000000..9f6276300a0bd --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json-without-unstableopts.run.stderr @@ -0,0 +1 @@ +error: The "json" format is only accepted on the nightly compiler diff --git a/tests/ui/test-attrs/tests-listing-format-json.rs b/tests/ui/test-attrs/tests-listing-format-json.rs new file mode 100644 index 0000000000000..18f1521eeeb1c --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json.rs @@ -0,0 +1,20 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format json -Zunstable-options +// run-pass +// check-run-results +// normalize-stdout-test: "fake-test-src-base/test-attrs/" -> "$$DIR/" +// normalize-stdout-test: "fake-test-src-base\\test-attrs\\" -> "$$DIR/" + +// Checks the listing of tests with --format json. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-json.run.stdout b/tests/ui/test-attrs/tests-listing-format-json.run.stdout new file mode 100644 index 0000000000000..b4131e97c34bc --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-json.run.stdout @@ -0,0 +1,5 @@ +{ "type": "suite", "event": "discovery" } +{ "type": "test", "event": "discovered", "name": "a_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 20, "start_col": 4, "end_line": 20, "end_col": 10 } +{ "type": "test", "event": "discovered", "name": "m_test", "ignore": false, "ignore_message": "", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 13, "start_col": 4, "end_line": 13, "end_col": 10 } +{ "type": "test", "event": "discovered", "name": "z_test", "ignore": true, "ignore_message": "not yet implemented", "source_path": "$DIR/tests-listing-format-json.rs", "start_line": 17, "start_col": 4, "end_line": 17, "end_col": 10 } +{ "type": "suite", "event": "completed", "tests": 3, "benchmarks": 0, "total": 3, "ignored": 1 } diff --git a/tests/ui/test-attrs/tests-listing-format-terse.rs b/tests/ui/test-attrs/tests-listing-format-terse.rs new file mode 100644 index 0000000000000..7835f71759cb4 --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-terse.rs @@ -0,0 +1,18 @@ +// no-prefer-dynamic +// compile-flags: --test +// run-flags: --list --format terse +// run-pass +// check-run-results + +// Checks the listing of tests with --format terse. + +#![cfg(test)] +#[test] +fn m_test() {} + +#[test] +#[ignore = "not yet implemented"] +fn z_test() {} + +#[test] +fn a_test() {} diff --git a/tests/ui/test-attrs/tests-listing-format-terse.run.stdout b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout new file mode 100644 index 0000000000000..22afe104bfb1d --- /dev/null +++ b/tests/ui/test-attrs/tests-listing-format-terse.run.stdout @@ -0,0 +1,3 @@ +a_test: test +m_test: test +z_test: test From 5e0fc0459e6ffd70ffbc0e540cce8623f21809a9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 17 Mar 2023 17:31:09 +0400 Subject: [PATCH 06/11] rustdoc: Correctly merge import's and its target's docs in one more case --- src/librustdoc/clean/mod.rs | 14 ++++++++------ .../rustdoc-ui/intra-doc/import-inline-merge.rs | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/import-inline-merge.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 29c3afe0d9560..bc497af9b9381 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -39,6 +39,7 @@ use std::hash::Hash; use std::mem; use thin_vec::ThinVec; +use crate::clean::inline::merge_attrs; use crate::core::{self, DocContext, ImplTraitParam}; use crate::formats::item_type::ItemType; use crate::visit_ast::Module as DocModule; @@ -2373,21 +2374,22 @@ fn clean_maybe_renamed_item<'tcx>( _ => unreachable!("not yet converted"), }; - let mut extra_attrs = Vec::new(); + let mut import_attrs = Vec::new(); + let mut target_attrs = Vec::new(); if let Some(import_id) = import_id && let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id) { let is_inline = inline::load_attrs(cx, import_id.to_def_id()).lists(sym::doc).get_word_attr(sym::inline).is_some(); // Then we get all the various imports' attributes. - get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs, is_inline); - add_without_unwanted_attributes(&mut extra_attrs, inline::load_attrs(cx, def_id), is_inline); + get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut import_attrs, is_inline); + add_without_unwanted_attributes(&mut target_attrs, inline::load_attrs(cx, def_id), is_inline); } else { // We only keep the item's attributes. - extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id)); + target_attrs.extend_from_slice(inline::load_attrs(cx, def_id)); } - let attrs = Attributes::from_ast(&extra_attrs); - let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); + let import_parent = import_id.map(|import_id| cx.tcx.local_parent(import_id).to_def_id()); + let (attrs, cfg) = merge_attrs(cx, import_parent, &target_attrs, Some(&import_attrs)); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg); diff --git a/tests/rustdoc-ui/intra-doc/import-inline-merge.rs b/tests/rustdoc-ui/intra-doc/import-inline-merge.rs new file mode 100644 index 0000000000000..31fef032b0fc9 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/import-inline-merge.rs @@ -0,0 +1,16 @@ +// Import for `A` is inlined and doc comments on the import and `A` itself are merged. +// After the merge they still have correct parent scopes to resolve both `[A]` and `[B]`. + +// check-pass + +#![allow(rustdoc::private_intra_doc_links)] + +mod m { + /// [B] + pub struct A {} + + pub struct B {} +} + +/// [A] +pub use m::A; From c7cc1c7442bc09e3c1a37f737790994c1084ad2a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 16 Mar 2023 19:35:27 -0300 Subject: [PATCH 07/11] Fix generics mismatch errors for RPITITs on -Zlower-impl-trait-in-trait-to-assoc-ty --- .../src/check/compare_impl_item.rs | 11 +++++++++++ ...match.stderr => generics-mismatch.current.stderr} | 2 +- .../in-trait/generics-mismatch.next.stderr | 12 ++++++++++++ tests/ui/impl-trait/in-trait/generics-mismatch.rs | 3 +++ 4 files changed, 27 insertions(+), 1 deletion(-) rename tests/ui/impl-trait/in-trait/{generics-mismatch.stderr => generics-mismatch.current.stderr} (90%) create mode 100644 tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6e6f8c1533bfe..32b6aeed5f8cc 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1205,6 +1205,17 @@ fn compare_number_of_generics<'tcx>( return Ok(()); } + // We never need to emit a separate error for RPITITs, since if an RPITIT + // has mismatched type or const generic arguments, then the method that it's + // inheriting the generics from will also have mismatched arguments, and + // we'll report an error for that instead. Delay a bug for safety, though. + if tcx.opt_rpitit_info(trait_.def_id).is_some() { + return Err(tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + "errors comparing numbers of generics of trait/impl functions were not emitted", + )); + } + let matchings = [ ("type", trait_own_counts.types, impl_own_counts.types), ("const", trait_own_counts.consts, impl_own_counts.consts), diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr similarity index 90% rename from tests/ui/impl-trait/in-trait/generics-mismatch.stderr rename to tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr index cd42683e0224d..310edbcb6cd1e 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.current.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/generics-mismatch.rs:11:12 + --> $DIR/generics-mismatch.rs:14:12 | LL | fn bar(&self) -> impl Sized; | - expected 0 type parameters diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr new file mode 100644 index 0000000000000..310edbcb6cd1e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.next.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/generics-mismatch.rs:14:12 + | +LL | fn bar(&self) -> impl Sized; + | - expected 0 type parameters +... +LL | fn bar(&self) {} + | ^ found 1 type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs index cc0fc720ebbfd..9259ca193d1de 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] From ae7fa1d269a3346372562570da3c51625027097b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 16 Mar 2023 20:41:24 -0300 Subject: [PATCH 08/11] Add generic parameters mismatch test for async in traits --- .../ui/async-await/in-trait/generics-mismatch.rs | 15 +++++++++++++++ .../in-trait/generics-mismatch.stderr | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/ui/async-await/in-trait/generics-mismatch.rs create mode 100644 tests/ui/async-await/in-trait/generics-mismatch.stderr diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs new file mode 100644 index 0000000000000..fc29783c0e32e --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.rs @@ -0,0 +1,15 @@ +// edition: 2021 + +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + async fn foo(); +} + +impl Foo for () { + async fn foo() {} + //~^ ERROR: method `foo` has an incompatible generic parameter for trait `Foo` [E0053] +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr new file mode 100644 index 0000000000000..3518aa05cecc2 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:11:18 + | +LL | trait Foo { + | --- +LL | async fn foo(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. From e0302bbc3bbecd172447f1105f586be3c35e043b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 16 Mar 2023 16:29:01 -0300 Subject: [PATCH 09/11] Add revisions for -Zlower-impl-trait-in-trait-to-assoc-ty fixed tests --- .../async-await/async-trait-fn.current.stderr | 42 ++++++++ .../ui/async-await/async-trait-fn.next.stderr | 42 ++++++++ tests/ui/async-await/async-trait-fn.rs | 1 + tests/ui/async-await/async-trait-fn.stderr | 6 +- ...dition-deny-async-fns-2015.current.stderr} | 20 ++-- .../edition-deny-async-fns-2015.next.stderr | 98 +++++++++++++++++++ .../edition-deny-async-fns-2015.rs | 2 + .../in-trait/generics-mismatch.current.stderr | 16 +++ .../in-trait/generics-mismatch.next.stderr | 16 +++ .../async-await/in-trait/generics-mismatch.rs | 15 +++ .../in-trait/generics-mismatch.stderr | 16 +++ ... => return-type-suggestion.current.stderr} | 4 +- .../return-type-suggestion.next.stderr | 23 +++++ .../in-trait/return-type-suggestion.rs | 2 + ... => default-body-with-rpit.current.stderr} | 6 +- .../default-body-with-rpit.next.stderr | 24 +++++ .../in-trait/default-body-with-rpit.rs | 2 + ...y.stderr => doesnt-satisfy.current.stderr} | 4 +- .../in-trait/doesnt-satisfy.next.stderr | 17 ++++ .../ui/impl-trait/in-trait/doesnt-satisfy.rs | 3 + 20 files changed, 339 insertions(+), 20 deletions(-) create mode 100644 tests/ui/async-await/async-trait-fn.current.stderr create mode 100644 tests/ui/async-await/async-trait-fn.next.stderr rename tests/ui/async-await/{edition-deny-async-fns-2015.stderr => edition-deny-async-fns-2015.current.stderr} (87%) create mode 100644 tests/ui/async-await/edition-deny-async-fns-2015.next.stderr create mode 100644 tests/ui/async-await/in-trait/generics-mismatch.current.stderr create mode 100644 tests/ui/async-await/in-trait/generics-mismatch.next.stderr create mode 100644 tests/ui/async-await/in-trait/generics-mismatch.rs create mode 100644 tests/ui/async-await/in-trait/generics-mismatch.stderr rename tests/ui/async-await/in-trait/{return-type-suggestion.stderr => return-type-suggestion.current.stderr} (89%) create mode 100644 tests/ui/async-await/in-trait/return-type-suggestion.next.stderr rename tests/ui/impl-trait/in-trait/{default-body-with-rpit.stderr => default-body-with-rpit.current.stderr} (82%) create mode 100644 tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr rename tests/ui/impl-trait/in-trait/{doesnt-satisfy.stderr => doesnt-satisfy.current.stderr} (90%) create mode 100644 tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr diff --git a/tests/ui/async-await/async-trait-fn.current.stderr b/tests/ui/async-await/async-trait-fn.current.stderr new file mode 100644 index 0000000000000..7ccf2f2301d24 --- /dev/null +++ b/tests/ui/async-await/async-trait-fn.current.stderr @@ -0,0 +1,42 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:6:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:7:5 + | +LL | async fn bar(&self) {} + | -----^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:8:5 + | +LL | async fn baz() { + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.next.stderr b/tests/ui/async-await/async-trait-fn.next.stderr new file mode 100644 index 0000000000000..7ccf2f2301d24 --- /dev/null +++ b/tests/ui/async-await/async-trait-fn.next.stderr @@ -0,0 +1,42 @@ +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:6:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:7:5 + | +LL | async fn bar(&self) {} + | -----^^^^^^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/async-trait-fn.rs:8:5 + | +LL | async fn baz() { + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.rs b/tests/ui/async-await/async-trait-fn.rs index e2062e82725c0..04123badb5383 100644 --- a/tests/ui/async-await/async-trait-fn.rs +++ b/tests/ui/async-await/async-trait-fn.rs @@ -1,4 +1,5 @@ // edition:2018 + trait T { async fn foo() {} //~ ERROR functions in traits cannot be declared `async` async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async` diff --git a/tests/ui/async-await/async-trait-fn.stderr b/tests/ui/async-await/async-trait-fn.stderr index afbe25cf7ab74..68ebe3507ac35 100644 --- a/tests/ui/async-await/async-trait-fn.stderr +++ b/tests/ui/async-await/async-trait-fn.stderr @@ -1,5 +1,5 @@ error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:3:5 + --> $DIR/async-trait-fn.rs:4:5 | LL | async fn foo() {} | -----^^^^^^^^^ @@ -12,7 +12,7 @@ LL | async fn foo() {} = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:4:5 + --> $DIR/async-trait-fn.rs:5:5 | LL | async fn bar(&self) {} | -----^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | async fn bar(&self) {} = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:5:5 + --> $DIR/async-trait-fn.rs:6:5 | LL | async fn baz() { | -----^^^^^^^^^ diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr similarity index 87% rename from tests/ui/async-await/edition-deny-async-fns-2015.stderr rename to tests/ui/async-await/edition-deny-async-fns-2015.current.stderr index ba918eb28def1..c47b99e657e14 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr @@ -1,5 +1,5 @@ error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:3:1 + --> $DIR/edition-deny-async-fns-2015.rs:5:1 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -8,7 +8,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:5:12 + --> $DIR/edition-deny-async-fns-2015.rs:7:12 | LL | fn baz() { async fn foo() {} } | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -17,7 +17,7 @@ LL | fn baz() { async fn foo() {} } = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:7:1 + --> $DIR/edition-deny-async-fns-2015.rs:9:1 | LL | async fn async_baz() { | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -26,7 +26,7 @@ LL | async fn async_baz() { = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:8:5 + --> $DIR/edition-deny-async-fns-2015.rs:10:5 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -35,7 +35,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:14:5 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -44,7 +44,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:18:5 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -53,7 +53,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:36:9 + --> $DIR/edition-deny-async-fns-2015.rs:38:9 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -62,7 +62,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:26:9 + --> $DIR/edition-deny-async-fns-2015.rs:28:9 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -71,7 +71,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:31:13 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -80,7 +80,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0706]: functions in traits cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:18:5 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 | LL | async fn foo() {} | -----^^^^^^^^^ diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr new file mode 100644 index 0000000000000..c47b99e657e14 --- /dev/null +++ b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr @@ -0,0 +1,98 @@ +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:5:1 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:7:12 + | +LL | fn baz() { async fn foo() {} } + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:9:1 + | +LL | async fn async_baz() { + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:10:5 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:16:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:38:9 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:28:9 + | +LL | async fn foo() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/edition-deny-async-fns-2015.rs:33:13 + | +LL | async fn bar() {} + | ^^^^^ to use `async fn`, switch to Rust 2018 or later + | + = help: pass `--edition 2021` to `rustc` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0706]: functions in traits cannot be declared `async` + --> $DIR/edition-deny-async-fns-2015.rs:20:5 + | +LL | async fn foo() {} + | -----^^^^^^^^^ + | | + | `async` because of this + | + = note: `async` trait functions are not currently supported + = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait + = note: see issue #91611 for more information + = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0670, E0706. +For more information about an error, try `rustc --explain E0670`. diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.rs b/tests/ui/async-await/edition-deny-async-fns-2015.rs index 6bd6d879a4ace..d4c30dc9d828d 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.rs +++ b/tests/ui/async-await/edition-deny-async-fns-2015.rs @@ -1,4 +1,6 @@ // edition:2015 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 diff --git a/tests/ui/async-await/in-trait/generics-mismatch.current.stderr b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr new file mode 100644 index 0000000000000..be23384e049da --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.current.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:13:18 + | +LL | trait Foo { + | --- +LL | async fn foo(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/generics-mismatch.next.stderr b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr new file mode 100644 index 0000000000000..be23384e049da --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.next.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:13:18 + | +LL | trait Foo { + | --- +LL | async fn foo(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs new file mode 100644 index 0000000000000..fc29783c0e32e --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.rs @@ -0,0 +1,15 @@ +// edition: 2021 + +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + async fn foo(); +} + +impl Foo for () { + async fn foo() {} + //~^ ERROR: method `foo` has an incompatible generic parameter for trait `Foo` [E0053] +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr new file mode 100644 index 0000000000000..3518aa05cecc2 --- /dev/null +++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr @@ -0,0 +1,16 @@ +error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` + --> $DIR/generics-mismatch.rs:11:18 + | +LL | trait Foo { + | --- +LL | async fn foo(); + | - expected type parameter +... +LL | impl Foo for () { + | --------------- +LL | async fn foo() {} + | ^^^^^^^^^^^^^^ found const parameter of type `usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr similarity index 89% rename from tests/ui/async-await/in-trait/return-type-suggestion.stderr rename to tests/ui/async-await/in-trait/return-type-suggestion.current.stderr index b8d83d0f28a31..a5efc75715656 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.stderr +++ b/tests/ui/async-await/in-trait/return-type-suggestion.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/return-type-suggestion.rs:3:12 + --> $DIR/return-type-suggestion.rs:5:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/return-type-suggestion.rs:8:9 + --> $DIR/return-type-suggestion.rs:10:9 | LL | Ok(()) | ^^^^^^- help: consider using a semicolon here: `;` diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr new file mode 100644 index 0000000000000..a5efc75715656 --- /dev/null +++ b/tests/ui/async-await/in-trait/return-type-suggestion.next.stderr @@ -0,0 +1,23 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/return-type-suggestion.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/return-type-suggestion.rs:10:9 + | +LL | Ok(()) + | ^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `Result<(), _>` + | + = note: expected unit type `()` + found enum `Result<(), _>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.rs b/tests/ui/async-await/in-trait/return-type-suggestion.rs index 3446761d119da..3de66306d9ab8 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.rs +++ b/tests/ui/async-await/in-trait/return-type-suggestion.rs @@ -1,4 +1,6 @@ // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr similarity index 82% rename from tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr rename to tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr index b5fc9d44d3687..3c24eff9ae301 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.current.stderr @@ -1,11 +1,11 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/default-body-with-rpit.rs:11:9 + --> $DIR/default-body-with-rpit.rs:13:9 | LL | "" | ^^ expected `impl Debug`, got `&'static str` | note: previous use here - --> $DIR/default-body-with-rpit.rs:10:39 + --> $DIR/default-body-with-rpit.rs:12:39 | LL | async fn baz(&self) -> impl Debug { | _______________________________________^ @@ -14,7 +14,7 @@ LL | | } | |_____^ error[E0720]: cannot resolve opaque type - --> $DIR/default-body-with-rpit.rs:10:28 + --> $DIR/default-body-with-rpit.rs:12:28 | LL | async fn baz(&self) -> impl Debug { | ^^^^^^^^^^ cannot resolve opaque type diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr new file mode 100644 index 0000000000000..3c24eff9ae301 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.next.stderr @@ -0,0 +1,24 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/default-body-with-rpit.rs:13:9 + | +LL | "" + | ^^ expected `impl Debug`, got `&'static str` + | +note: previous use here + --> $DIR/default-body-with-rpit.rs:12:39 + | +LL | async fn baz(&self) -> impl Debug { + | _______________________________________^ +LL | | "" +LL | | } + | |_____^ + +error[E0720]: cannot resolve opaque type + --> $DIR/default-body-with-rpit.rs:12:28 + | +LL | async fn baz(&self) -> impl Debug { + | ^^^^^^^^^^ cannot resolve opaque type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs index 0558d95128f4a..6bcc7b9ef95f0 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs @@ -1,5 +1,7 @@ // edition:2021 // known-bug: #108304 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr similarity index 90% rename from tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr rename to tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr index aa5492d285ed6..653016cf009a9 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.current.stderr @@ -1,5 +1,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` - --> $DIR/doesnt-satisfy.rs:9:17 + --> $DIR/doesnt-satisfy.rs:12:17 | LL | fn bar() -> () {} | ^^ `()` cannot be formatted with the default formatter @@ -7,7 +7,7 @@ LL | fn bar() -> () {} = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Foo::bar::{opaque#0}` - --> $DIR/doesnt-satisfy.rs:5:22 + --> $DIR/doesnt-satisfy.rs:8:22 | LL | fn bar() -> impl std::fmt::Display; | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{opaque#0}` diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr new file mode 100644 index 0000000000000..bbfa089ceef92 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.next.stderr @@ -0,0 +1,17 @@ +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/doesnt-satisfy.rs:12:17 + | +LL | fn bar() -> () {} + | ^^ `()` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `Foo::{opaque#0}` + --> $DIR/doesnt-satisfy.rs:8:22 + | +LL | fn bar() -> impl std::fmt::Display; + | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs index bb4e0d44f3eff..fcd0b51eea4fc 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] From 9139ed076d2f38a99f30b736eab968ae6d2f5e4f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 17 Mar 2023 12:37:27 -0300 Subject: [PATCH 10/11] Fix impl_trait_ty_to_ty substs --- .../rustc_hir_analysis/src/astconv/mod.rs | 8 +++++-- ...tderr => lifetime-mismatch.current.stderr} | 4 ++-- .../in-trait/lifetime-mismatch.next.stderr | 21 +++++++++++++++++++ .../async-await/in-trait/lifetime-mismatch.rs | 2 ++ ...it-more-generics-than-impl.current.stderr} | 2 +- .../trait-more-generics-than-impl.next.stderr | 12 +++++++++++ .../in-trait/trait-more-generics-than-impl.rs | 3 +++ 7 files changed, 47 insertions(+), 5 deletions(-) rename tests/ui/async-await/in-trait/{lifetime-mismatch.stderr => lifetime-mismatch.current.stderr} (91%) create mode 100644 tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr rename tests/ui/impl-trait/in-trait/{trait-more-generics-than-impl.stderr => trait-more-generics-than-impl.current.stderr} (88%) create mode 100644 tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index f830269b45dae..333e7502041e7 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -3141,8 +3141,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("impl_trait_ty_to_ty: generics={:?}", generics); let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { - if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { - // Our own parameters are the resolved lifetimes. + // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` + // since return-position impl trait in trait squashes all of the generics from its source fn + // into its own generics, so the opaque's "own" params isn't always just lifetimes. + if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len()) + { + // Resolve our own lifetime parameters. let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() }; let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() }; self.ast_region_to_region(lifetime, None).into() diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr b/tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr similarity index 91% rename from tests/ui/async-await/in-trait/lifetime-mismatch.stderr rename to tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr index d87adcc78b6c8..0e9477544a4a6 100644 --- a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.current.stderr @@ -1,5 +1,5 @@ warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/lifetime-mismatch.rs:3:12 + --> $DIR/lifetime-mismatch.rs:5:12 | LL | #![feature(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(async_fn_in_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration - --> $DIR/lifetime-mismatch.rs:12:17 + --> $DIR/lifetime-mismatch.rs:14:17 | LL | async fn foo<'a>(&self); | ---- lifetimes in impl do not match this method in trait diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr b/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr new file mode 100644 index 0000000000000..0e9477544a4a6 --- /dev/null +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.next.stderr @@ -0,0 +1,21 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/lifetime-mismatch.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/lifetime-mismatch.rs:14:17 + | +LL | async fn foo<'a>(&self); + | ---- lifetimes in impl do not match this method in trait +... +LL | async fn foo(&self) {} + | ^ lifetimes do not match method in trait + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0195`. diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.rs b/tests/ui/async-await/in-trait/lifetime-mismatch.rs index 45ede193c0fc6..5ff5a01a1ee03 100644 --- a/tests/ui/async-await/in-trait/lifetime-mismatch.rs +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.rs @@ -1,4 +1,6 @@ // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr similarity index 88% rename from tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr rename to tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr index 8ff54cad95139..64c942705cf8e 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.current.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/trait-more-generics-than-impl.rs:11:11 + --> $DIR/trait-more-generics-than-impl.rs:14:11 | LL | fn bar() -> impl Sized; | - expected 1 type parameter diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr new file mode 100644 index 0000000000000..64c942705cf8e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.next.stderr @@ -0,0 +1,12 @@ +error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/trait-more-generics-than-impl.rs:14:11 + | +LL | fn bar() -> impl Sized; + | - expected 1 type parameter +... +LL | fn bar() -> impl Sized {} + | ^ found 0 type parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs index 0bbe50ea6fd37..c2e394a1f6645 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] From 640c20272ef0d1bb8ae5425d27c5543d1bbbf1fa Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 17 Mar 2023 14:05:26 -0300 Subject: [PATCH 11/11] Fix generics_of for impl's RPITIT synthesized associated type --- compiler/rustc_ty_utils/src/assoc.rs | 10 +++------- tests/ui/async-await/in-trait/issue-102310.rs | 2 ++ tests/ui/impl-trait/in-trait/early.rs | 2 ++ tests/ui/impl-trait/in-trait/issue-102301.rs | 2 ++ tests/ui/impl-trait/in-trait/opaque-in-impl.rs | 2 ++ tests/ui/impl-trait/in-trait/where-clause.rs | 2 ++ 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 68b1086e8e3f5..49cb778118863 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -383,6 +383,8 @@ fn impl_associated_item_for_impl_trait_in_trait( impl_assoc_ty.impl_defaultness(tcx.impl_defaultness(impl_fn_def_id)); // Copy generics_of the trait's associated item but the impl as the parent. + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) resolves to the trait instead of the impl + // generics. impl_assoc_ty.generics_of({ let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id); let trait_assoc_parent_count = trait_assoc_generics.parent_count; @@ -391,16 +393,10 @@ fn impl_associated_item_for_impl_trait_in_trait( let parent_generics = tcx.generics_of(impl_def_id); let parent_count = parent_generics.parent_count + parent_generics.params.len(); - let mut impl_fn_params = tcx.generics_of(impl_fn_def_id).params.clone(); - for param in &mut params { - param.index = param.index + parent_count as u32 + impl_fn_params.len() as u32 - - trait_assoc_parent_count as u32; + param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32; } - impl_fn_params.extend(params); - params = impl_fn_params; - let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); diff --git a/tests/ui/async-await/in-trait/issue-102310.rs b/tests/ui/async-await/in-trait/issue-102310.rs index 49c3e9feeb4c4..8e5dbd08eb98b 100644 --- a/tests/ui/async-await/in-trait/issue-102310.rs +++ b/tests/ui/async-await/in-trait/issue-102310.rs @@ -1,5 +1,7 @@ // check-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/early.rs b/tests/ui/impl-trait/in-trait/early.rs index 9c1c2b5033904..831033a588061 100644 --- a/tests/ui/impl-trait/in-trait/early.rs +++ b/tests/ui/impl-trait/in-trait/early.rs @@ -1,5 +1,7 @@ // check-pass // edition:2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/issue-102301.rs b/tests/ui/impl-trait/in-trait/issue-102301.rs index a93714a658ef0..1329ca29d06aa 100644 --- a/tests/ui/impl-trait/in-trait/issue-102301.rs +++ b/tests/ui/impl-trait/in-trait/issue-102301.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs index 2e06629699aad..f48d9fa26c003 100644 --- a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs @@ -1,4 +1,6 @@ // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/impl-trait/in-trait/where-clause.rs b/tests/ui/impl-trait/in-trait/where-clause.rs index 87bac519cf304..88d86e2b54192 100644 --- a/tests/ui/impl-trait/in-trait/where-clause.rs +++ b/tests/ui/impl-trait/in-trait/where-clause.rs @@ -1,5 +1,7 @@ // check-pass // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)]