From 6630c146f213088dff0d4ebd8dad90591544c169 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Sep 2022 17:06:28 -0700 Subject: [PATCH 01/17] Implement the `+whole-archive` modifier for `wasm-ld` This implements the `Linker::{link_whole_staticlib,link_whole_rlib}` methods for the `WasmLd` linker used on wasm targets. Previously these methods were noops since I think historically `wasm-ld` did not have support for `--whole-archive` but nowadays it does, so the flags are passed through. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e0bd7a33f7373..6e59a4f64db25 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1265,11 +1265,11 @@ impl<'a> Linker for WasmLd<'a> { } fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { - self.cmd.arg("-l").arg(lib); + self.cmd.arg("--whole-archive").arg("-l").arg(lib).arg("--no-whole-archive"); } fn link_whole_rlib(&mut self, lib: &Path) { - self.cmd.arg(lib); + self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); } fn gc_sections(&mut self, _keep_metadata: bool) { From 449a4404f5216a085cc0aa89042b39a4bdff5b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 23 Oct 2022 19:12:23 +0200 Subject: [PATCH 02/17] test attr: point at return type if Termination bound unsatisfied --- compiler/rustc_builtin_macros/src/test.rs | 18 ++++++++++++------ .../termination-trait-test-wrong-type.stderr | 12 +++++------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 705141614e252..ad4c844307106 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -103,7 +103,7 @@ pub fn expand_test_or_bench( }; // Note: non-associated fn items are already handled by `expand_test_or_bench` - if !matches!(item.kind, ast::ItemKind::Fn(_)) { + let ast::ItemKind::Fn(fn_) = &item.kind else { let diag = &cx.sess.parse_sess.span_diagnostic; let msg = "the `#[test]` attribute may only be used on a non-associated function"; let mut err = match item.kind { @@ -121,7 +121,7 @@ pub fn expand_test_or_bench( .emit(); return vec![Annotatable::Item(item)]; - } + }; // has_*_signature will report any errors in the type so compilation // will fail. We shouldn't try to expand in this case because the errors @@ -132,12 +132,14 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let (sp, attr_sp) = (cx.with_def_site_ctxt(item.span), cx.with_def_site_ctxt(attr_sp)); + let sp = cx.with_def_site_ctxt(item.span); + let ret_ty_sp = cx.with_def_site_ctxt(fn_.sig.decl.output.span()); + let attr_sp = cx.with_def_site_ctxt(attr_sp); let test_id = Ident::new(sym::test, attr_sp); // creates test::$name - let test_path = |name| cx.path(sp, vec![test_id, Ident::from_str_and_span(name, sp)]); + let test_path = |name| cx.path(ret_ty_sp, vec![test_id, Ident::from_str_and_span(name, sp)]); // creates test::ShouldPanic::$name let should_panic_path = |name| { @@ -183,7 +185,7 @@ pub fn expand_test_or_bench( vec![ // super::$test_fn(b) cx.expr_call( - sp, + ret_ty_sp, cx.expr_path(cx.path(sp, vec![item.ident])), vec![cx.expr_ident(sp, b)], ), @@ -207,7 +209,11 @@ pub fn expand_test_or_bench( cx.expr_path(test_path("assert_test_result")), vec![ // $test_fn() - cx.expr_call(sp, cx.expr_path(cx.path(sp, vec![item.ident])), vec![]), // ) + cx.expr_call( + ret_ty_sp, + cx.expr_path(cx.path(sp, vec![item.ident])), + vec![], + ), // ) ], ), // } ), // ) diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index 6ee32314607ad..9577952119adb 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -1,12 +1,10 @@ error[E0277]: the trait bound `f32: Termination` is not satisfied - --> $DIR/termination-trait-test-wrong-type.rs:6:1 + --> $DIR/termination-trait-test-wrong-type.rs:6:31 | -LL | #[test] - | ------- in this procedural macro expansion -LL | / fn can_parse_zero_as_f32() -> Result { -LL | | "0".parse() -LL | | } - | |_^ the trait `Termination` is not implemented for `f32` +LL | #[test] + | ------- in this procedural macro expansion +LL | fn can_parse_zero_as_f32() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32` | = note: required for `Result` to implement `Termination` note: required by a bound in `assert_test_result` From c0447b489ba890c740c1e5c41f3eacca148734a9 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 24 Oct 2022 16:48:28 +0800 Subject: [PATCH 03/17] fix #103435, unused lint won't produce invalid code --- compiler/rustc_lint/src/unused.rs | 44 +++++++++++++------ .../lint/issue-103435-extra-parentheses.fixed | 16 +++++++ .../ui/lint/issue-103435-extra-parentheses.rs | 16 +++++++ .../issue-103435-extra-parentheses.stderr | 43 ++++++++++++++++++ 4 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/lint/issue-103435-extra-parentheses.fixed create mode 100644 src/test/ui/lint/issue-103435-extra-parentheses.rs create mode 100644 src/test/ui/lint/issue-103435-extra-parentheses.stderr diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 46706e4984451..1299444cd7738 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -565,10 +565,26 @@ trait UnusedDelimLint { lint.set_arg("delim", Self::DELIM_STR); lint.set_arg("item", msg); if let Some((lo, hi)) = spans { - let replacement = vec![ - (lo, if keep_space.0 { " ".into() } else { "".into() }), - (hi, if keep_space.1 { " ".into() } else { "".into() }), - ]; + let sm = cx.sess().source_map(); + let lo_replace = + if keep_space.0 && + let Ok(snip) = sm.span_to_snippet(lo.with_lo(lo.lo() - BytePos(1))) && + !snip.starts_with(" ") { + " ".to_string() + } else { + "".to_string() + }; + + let hi_replace = + if keep_space.1 && + let Ok(snip) = sm.span_to_snippet(sm.next_point(hi)) && + !snip.starts_with(" ") { + " ".to_string() + } else { + "".to_string() + }; + + let replacement = vec![(lo, lo_replace), (hi, hi_replace)]; lint.multipart_suggestion( fluent::suggestion, replacement, @@ -765,6 +781,7 @@ impl UnusedParens { value: &ast::Pat, avoid_or: bool, avoid_mut: bool, + keep_space: (bool, bool), ) { use ast::{BindingAnnotation, PatKind}; @@ -789,7 +806,7 @@ impl UnusedParens { } else { None }; - self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false)); + self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space); } } } @@ -798,7 +815,7 @@ impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { match e.kind { ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => { - self.check_unused_parens_pat(cx, pat, false, false); + self.check_unused_parens_pat(cx, pat, false, false, (true, true)); } // We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already // handle a hard error for them during AST lowering in `lower_expr_mut`, but we still @@ -842,6 +859,7 @@ impl EarlyLintPass for UnusedParens { fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) { use ast::{Mutability, PatKind::*}; + let keep_space = (false, false); match &p.kind { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) @@ -849,33 +867,33 @@ impl EarlyLintPass for UnusedParens { | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, // These are list-like patterns; parens can always be removed. TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { - self.check_unused_parens_pat(cx, p, false, false); + self.check_unused_parens_pat(cx, p, false, false, keep_space); }, Struct(_, _, fps, _) => for f in fps { - self.check_unused_parens_pat(cx, &f.pat, false, false); + self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space); }, // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106. - Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false), + Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space), // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342. // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106. - Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not), + Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space), } } fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { if let StmtKind::Local(ref local) = s.kind { - self.check_unused_parens_pat(cx, &local.pat, true, false); + self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false)); } ::check_stmt(self, cx, s) } fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) { - self.check_unused_parens_pat(cx, ¶m.pat, true, false); + self.check_unused_parens_pat(cx, ¶m.pat, true, false, (false, false)); } fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { - self.check_unused_parens_pat(cx, &arm.pat, false, false); + self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false)); } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.fixed b/src/test/ui/lint/issue-103435-extra-parentheses.fixed new file mode 100644 index 0000000000000..dbbcaa441ddd6 --- /dev/null +++ b/src/test/ui/lint/issue-103435-extra-parentheses.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#![deny(unused_parens)] + +fn main() { + if let Some(_) = Some(1) {} + //~^ ERROR unnecessary parentheses around pattern + + for _x in 1..10 {} + //~^ ERROR unnecessary parentheses around pattern + + if 2 == 1 {} + //~^ ERROR unnecessary parentheses around `if` condition + + // FIXME, auto recover from this one? + // for(_x in 1..10) {} +} diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.rs b/src/test/ui/lint/issue-103435-extra-parentheses.rs new file mode 100644 index 0000000000000..f5c2a6664ede4 --- /dev/null +++ b/src/test/ui/lint/issue-103435-extra-parentheses.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![deny(unused_parens)] + +fn main() { + if let(Some(_))= Some(1) {} + //~^ ERROR unnecessary parentheses around pattern + + for(_x)in 1..10 {} + //~^ ERROR unnecessary parentheses around pattern + + if(2 == 1){} + //~^ ERROR unnecessary parentheses around `if` condition + + // FIXME, auto recover from this one? + // for(_x in 1..10) {} +} diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.stderr b/src/test/ui/lint/issue-103435-extra-parentheses.stderr new file mode 100644 index 0000000000000..a3f2fbc51ab29 --- /dev/null +++ b/src/test/ui/lint/issue-103435-extra-parentheses.stderr @@ -0,0 +1,43 @@ +error: unnecessary parentheses around pattern + --> $DIR/issue-103435-extra-parentheses.rs:5:11 + | +LL | if let(Some(_))= Some(1) {} + | ^ ^ + | +note: the lint level is defined here + --> $DIR/issue-103435-extra-parentheses.rs:2:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - if let(Some(_))= Some(1) {} +LL + if let Some(_) = Some(1) {} + | + +error: unnecessary parentheses around pattern + --> $DIR/issue-103435-extra-parentheses.rs:8:8 + | +LL | for(_x)in 1..10 {} + | ^ ^ + | +help: remove these parentheses + | +LL - for(_x)in 1..10 {} +LL + for _x in 1..10 {} + | + +error: unnecessary parentheses around `if` condition + --> $DIR/issue-103435-extra-parentheses.rs:11:7 + | +LL | if(2 == 1){} + | ^ ^ + | +help: remove these parentheses + | +LL - if(2 == 1){} +LL + if 2 == 1 {} + | + +error: aborting due to 3 previous errors + From a46af18cb1aedf7ccc5fbebd6f126c71da6cd4ee Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 24 Oct 2022 18:24:10 +0800 Subject: [PATCH 04/17] fix parentheses surrounding spacing issue in parser --- compiler/rustc_lint/src/unused.rs | 6 ++--- compiler/rustc_parse/src/errors.rs | 6 +++-- .../rustc_parse/src/parser/diagnostics.rs | 24 +++++++++++++++---- .../lint/issue-103435-extra-parentheses.fixed | 6 +++-- .../ui/lint/issue-103435-extra-parentheses.rs | 6 +++-- .../issue-103435-extra-parentheses.stderr | 20 +++++++++++++++- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1299444cd7738..d4b083de27624 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -568,8 +568,7 @@ trait UnusedDelimLint { let sm = cx.sess().source_map(); let lo_replace = if keep_space.0 && - let Ok(snip) = sm.span_to_snippet(lo.with_lo(lo.lo() - BytePos(1))) && - !snip.starts_with(" ") { + let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(" ") { " ".to_string() } else { "".to_string() @@ -577,8 +576,7 @@ trait UnusedDelimLint { let hi_replace = if keep_space.1 && - let Ok(snip) = sm.span_to_snippet(sm.next_point(hi)) && - !snip.starts_with(" ") { + let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(" ") { " ".to_string() } else { "".to_string() diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 9b177c5189bfb..a3fbc06293f70 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1122,10 +1122,12 @@ pub(crate) struct ParenthesesInForHead { #[derive(Subdiagnostic)] #[multipart_suggestion(suggestion, applicability = "machine-applicable")] pub(crate) struct ParenthesesInForHeadSugg { - #[suggestion_part(code = "")] + #[suggestion_part(code = "{left_snippet}")] pub left: Span, - #[suggestion_part(code = "")] + pub left_snippet: String, + #[suggestion_part(code = "{right_snippet}")] pub right: Span, + pub right_snippet: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 887a4a6de33b1..e9549e8999857 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1641,15 +1641,29 @@ impl<'a> Parser<'a> { (token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => { self.bump(); + let sm = self.sess.source_map(); + let left = begin_par_sp; + let right = self.prev_token.span; + let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) && + !snip.ends_with(" ") { + " ".to_string() + } else { + "".to_string() + }; + + let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) && + !snip.starts_with(" ") { + " ".to_string() + } else { + "".to_string() + }; + self.sess.emit_err(ParenthesesInForHead { - span: vec![begin_par_sp, self.prev_token.span], + span: vec![left, right], // With e.g. `for (x) in y)` this would replace `(x) in y)` // with `x) in y)` which is syntactically invalid. // However, this is prevented before we get here. - sugg: ParenthesesInForHeadSugg { - left: begin_par_sp, - right: self.prev_token.span, - }, + sugg: ParenthesesInForHeadSugg { left, right, left_snippet, right_snippet }, }); // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.fixed b/src/test/ui/lint/issue-103435-extra-parentheses.fixed index dbbcaa441ddd6..2b01b414baa6e 100644 --- a/src/test/ui/lint/issue-103435-extra-parentheses.fixed +++ b/src/test/ui/lint/issue-103435-extra-parentheses.fixed @@ -11,6 +11,8 @@ fn main() { if 2 == 1 {} //~^ ERROR unnecessary parentheses around `if` condition - // FIXME, auto recover from this one? - // for(_x in 1..10) {} + // reported by parser + for _x in 1..10 {} + //~^ ERROR expected one of + //~| ERROR unexpected parentheses surrounding } diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.rs b/src/test/ui/lint/issue-103435-extra-parentheses.rs index f5c2a6664ede4..8261610cf5646 100644 --- a/src/test/ui/lint/issue-103435-extra-parentheses.rs +++ b/src/test/ui/lint/issue-103435-extra-parentheses.rs @@ -11,6 +11,8 @@ fn main() { if(2 == 1){} //~^ ERROR unnecessary parentheses around `if` condition - // FIXME, auto recover from this one? - // for(_x in 1..10) {} + // reported by parser + for(_x in 1..10){} + //~^ ERROR expected one of + //~| ERROR unexpected parentheses surrounding } diff --git a/src/test/ui/lint/issue-103435-extra-parentheses.stderr b/src/test/ui/lint/issue-103435-extra-parentheses.stderr index a3f2fbc51ab29..29c41c91050b9 100644 --- a/src/test/ui/lint/issue-103435-extra-parentheses.stderr +++ b/src/test/ui/lint/issue-103435-extra-parentheses.stderr @@ -1,3 +1,21 @@ +error: expected one of `)`, `,`, `@`, or `|`, found keyword `in` + --> $DIR/issue-103435-extra-parentheses.rs:15:12 + | +LL | for(_x in 1..10){} + | ^^ expected one of `)`, `,`, `@`, or `|` + +error: unexpected parentheses surrounding `for` loop head + --> $DIR/issue-103435-extra-parentheses.rs:15:8 + | +LL | for(_x in 1..10){} + | ^ ^ + | +help: remove parentheses in `for` loop + | +LL - for(_x in 1..10){} +LL + for _x in 1..10 {} + | + error: unnecessary parentheses around pattern --> $DIR/issue-103435-extra-parentheses.rs:5:11 | @@ -39,5 +57,5 @@ LL - if(2 == 1){} LL + if 2 == 1 {} | -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors From 32a2f0dddb7aae3bef2939af5079eb2bcbfdf6c5 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 26 Oct 2022 00:15:47 +0800 Subject: [PATCH 05/17] suggest calling the method of the same name when method not found --- .../rustc_resolve/src/late/diagnostics.rs | 24 +++++++++---------- src/test/ui/resolve/issue-103474.rs | 16 +++++++++++++ src/test/ui/resolve/issue-103474.stderr | 20 ++++++++++++++++ src/test/ui/resolve/issue-2356.stderr | 4 ++-- src/test/ui/self/class-missing-self.stderr | 4 ++++ .../suggestions/assoc_fn_without_self.stderr | 9 +++++-- 6 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/resolve/issue-103474.rs create mode 100644 src/test/ui/resolve/issue-103474.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 23c5fac8b71c1..23b9284db335f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -213,26 +213,26 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let (mod_prefix, mod_str, suggestion) = if path.len() == 1 { debug!(?self.diagnostic_metadata.current_impl_items); debug!(?self.diagnostic_metadata.current_function); - let suggestion = if let Some(items) = self.diagnostic_metadata.current_impl_items + let suggestion = if self.current_trait_ref.is_none() && let Some((fn_kind, _)) = self.diagnostic_metadata.current_function - && self.current_trait_ref.is_none() && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt() + && let Some(items) = self.diagnostic_metadata.current_impl_items && let Some(item) = items.iter().find(|i| { - if let AssocItemKind::Fn(fn_) = &i.kind - && !fn_.sig.decl.has_self() - && i.ident.name == item_str.name + if let AssocItemKind::Fn(_) = &i.kind && i.ident.name == item_str.name { debug!(?item_str.name); - debug!(?fn_.sig.decl.inputs); return true } false }) + && let AssocItemKind::Fn(fn_) = &item.kind { + debug!(?fn_); + let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" }; Some(( - item_span, + item_span.shrink_to_lo(), "consider using the associated function", - format!("Self::{}", item.ident) + self_sugg.to_string() )) } else { None @@ -381,11 +381,13 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], span: Span) { - let is_assoc_fn = self.self_type_is_available(); + if !self.self_type_is_available() { + return; + } let Some(path_last_segment) = path.last() else { return }; let item_str = path_last_segment.ident; // Emit help message for fake-self from other languages (e.g., `this` in Javascript). - if ["this", "my"].contains(&item_str.as_str()) && is_assoc_fn { + if ["this", "my"].contains(&item_str.as_str()) { err.span_suggestion_short( span, "you might have meant to use `self` here instead", @@ -436,7 +438,6 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _)); let path_str = Segment::names_to_string(path); let ident_span = path.last().map_or(span, |ident| ident.ident.span); - let mut candidates = self .r .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected) @@ -1512,7 +1513,6 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { _ => None, } } - // Fields are generally expected in the same contexts as locals. if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) { if let Some(node_id) = diff --git a/src/test/ui/resolve/issue-103474.rs b/src/test/ui/resolve/issue-103474.rs new file mode 100644 index 0000000000000..408139ca0111e --- /dev/null +++ b/src/test/ui/resolve/issue-103474.rs @@ -0,0 +1,16 @@ +struct S {} +impl S { + fn first(&self) {} + + fn second(&self) { + first() + //~^ ERROR cannot find function `first` in this scope + } + + fn third(&self) { + no_method_err() + //~^ ERROR cannot find function `no_method_err` in this scope + } +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-103474.stderr b/src/test/ui/resolve/issue-103474.stderr new file mode 100644 index 0000000000000..78fa13fbd2e24 --- /dev/null +++ b/src/test/ui/resolve/issue-103474.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find function `first` in this scope + --> $DIR/issue-103474.rs:6:9 + | +LL | first() + | ^^^^^ not found in this scope + | +help: consider using the associated function + | +LL | self.first() + | +++++ + +error[E0425]: cannot find function `no_method_err` in this scope + --> $DIR/issue-103474.rs:11:9 + | +LL | no_method_err() + | ^^^^^^^^^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index e7c53ff44e6fe..36f3da7c95537 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -85,7 +85,7 @@ LL | static_method(); help: consider using the associated function | LL | Self::static_method(); - | ~~~~~~~~~~~~~~~~~~~ + | ++++++ error[E0425]: cannot find function `purr` in this scope --> $DIR/issue-2356.rs:54:9 @@ -114,7 +114,7 @@ LL | grow_older(); help: consider using the associated function | LL | Self::grow_older(); - | ~~~~~~~~~~~~~~~~ + | ++++++ error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:74:5 diff --git a/src/test/ui/self/class-missing-self.stderr b/src/test/ui/self/class-missing-self.stderr index d501200d73cec..063c3f013c539 100644 --- a/src/test/ui/self/class-missing-self.stderr +++ b/src/test/ui/self/class-missing-self.stderr @@ -10,6 +10,10 @@ error[E0425]: cannot find function `sleep` in this scope LL | sleep(); | ^^^^^ not found in this scope | +help: consider using the associated function + | +LL | self.sleep(); + | +++++ help: consider importing this function | LL | use std::thread::sleep; diff --git a/src/test/ui/suggestions/assoc_fn_without_self.stderr b/src/test/ui/suggestions/assoc_fn_without_self.stderr index 88920b852905b..febdd67338c99 100644 --- a/src/test/ui/suggestions/assoc_fn_without_self.stderr +++ b/src/test/ui/suggestions/assoc_fn_without_self.stderr @@ -7,13 +7,18 @@ LL | foo(); help: consider using the associated function | LL | Self::foo(); - | ~~~~~~~~~ + | ++++++ error[E0425]: cannot find function `bar` in this scope --> $DIR/assoc_fn_without_self.rs:17:9 | LL | bar(); | ^^^ not found in this scope + | +help: consider using the associated function + | +LL | self.bar(); + | +++++ error[E0425]: cannot find function `baz` in this scope --> $DIR/assoc_fn_without_self.rs:18:9 @@ -24,7 +29,7 @@ LL | baz(2, 3); help: consider using the associated function | LL | Self::baz(2, 3); - | ~~~~~~~~~ + | ++++++ error[E0425]: cannot find function `foo` in this scope --> $DIR/assoc_fn_without_self.rs:14:13 From 27164495881d2d3d1bb1ef79850b00f1e9989ba7 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 26 Oct 2022 05:32:19 +0800 Subject: [PATCH 06/17] add testcase for suggest self --- src/test/ui/resolve/issue-103474.rs | 12 ++++++++++++ src/test/ui/resolve/issue-103474.stderr | 17 ++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/test/ui/resolve/issue-103474.rs b/src/test/ui/resolve/issue-103474.rs index 408139ca0111e..14f2259e1d4e8 100644 --- a/src/test/ui/resolve/issue-103474.rs +++ b/src/test/ui/resolve/issue-103474.rs @@ -13,4 +13,16 @@ impl S { } } +// https://github.com/rust-lang/rust/pull/103531#discussion_r1004728080 +struct Foo { + i: i32, +} + +impl Foo { + fn needs_self() { + this.i + //~^ ERROR cannot find value `this` in this scope + } +} + fn main() {} diff --git a/src/test/ui/resolve/issue-103474.stderr b/src/test/ui/resolve/issue-103474.stderr index 78fa13fbd2e24..415d231552a03 100644 --- a/src/test/ui/resolve/issue-103474.stderr +++ b/src/test/ui/resolve/issue-103474.stderr @@ -1,3 +1,18 @@ +error[E0425]: cannot find value `this` in this scope + --> $DIR/issue-103474.rs:23:9 + | +LL | this.i + | ^^^^ not found in this scope + | +help: you might have meant to use `self` here instead + | +LL | self.i + | ~~~~ +help: if you meant to use `self`, you are also missing a `self` receiver argument + | +LL | fn needs_self(&self) { + | +++++ + error[E0425]: cannot find function `first` in this scope --> $DIR/issue-103474.rs:6:9 | @@ -15,6 +30,6 @@ error[E0425]: cannot find function `no_method_err` in this scope LL | no_method_err() | ^^^^^^^^^^^^^ not found in this scope -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. From 4b5cff5b553edee6e3965c6fa7b50f698d653ac6 Mon Sep 17 00:00:00 2001 From: Pete Date: Thu, 3 Nov 2022 14:15:32 +0100 Subject: [PATCH 07/17] Fix broken link in error code E0706 docs Corresponding subsection in async book is not `07.05` not `07.06`. The information on the linked page is the same so it may be reasonable to remove the whole sentence. --- compiler/rustc_error_codes/src/error_codes/E0706.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0706.md b/compiler/rustc_error_codes/src/error_codes/E0706.md index d379b8a2384c6..fabd855a222f0 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0706.md +++ b/compiler/rustc_error_codes/src/error_codes/E0706.md @@ -56,4 +56,4 @@ You might be interested in visiting the [async book] for further information. [`async-trait` crate]: https://crates.io/crates/async-trait [async-is-hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/ [Generic Associated Types]: https://github.com/rust-lang/rust/issues/44265 -[async book]: https://rust-lang.github.io/async-book/07_workarounds/06_async_in_traits.html +[async book]: https://rust-lang.github.io/async-book/07_workarounds/05_async_in_traits.html From 8e0cac18cd2951e2679ea55e15242d04e2d410c9 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 7 Nov 2022 11:13:01 -0700 Subject: [PATCH 08/17] rustdoc: refactor `notable_traits_decl` to just act on the type directly --- src/librustdoc/html/render/mod.rs | 133 +++++++++++------------ src/librustdoc/html/render/print_item.rs | 7 +- 2 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 3a041ae15d618..881f107925315 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -861,7 +861,11 @@ fn assoc_method( name = name, generics = g.print(cx), decl = d.full_print(header_len, indent, cx), - notable_traits = notable_traits_decl(d, cx), + notable_traits = d + .output + .as_return() + .and_then(|output| notable_traits_decl(output, cx)) + .unwrap_or_default(), where_clause = print_where_clause(g, cx, indent, end_newline), ) } @@ -1273,71 +1277,64 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { +fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> Option { let mut out = Buffer::html(); - if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t))) + let did = ty.def_id(cx.cache())?; + + // Box has pass-through impls for Read, Write, Iterator, and Future when the + // boxed type implements one of those. We don't want to treat every Box return + // as being notably an Iterator (etc), though, so we exempt it. Pin has the same + // issue, with a pass-through impl for Future. + if Some(did) == cx.tcx().lang_items().owned_box() + || Some(did) == cx.tcx().lang_items().pin_type() { - // Box has pass-through impls for Read, Write, Iterator, and Future when the - // boxed type implements one of those. We don't want to treat every Box return - // as being notably an Iterator (etc), though, so we exempt it. Pin has the same - // issue, with a pass-through impl for Future. - if Some(did) == cx.tcx().lang_items().owned_box() - || Some(did) == cx.tcx().lang_items().pin_type() - { - return "".to_string(); - } - if let Some(impls) = cx.cache().impls.get(&did) { - for i in impls { - let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) - { - // Two different types might have the same did, - // without actually being the same. - continue; - } - if let Some(trait_) = &impl_.trait_ { - let trait_did = trait_.def_id(); - - if cx - .cache() - .traits - .get(&trait_did) - .map_or(false, |t| t.is_notable_trait(cx.tcx())) - { - if out.is_empty() { - write!( - &mut out, - "Notable traits for {}\ - ", - impl_.for_.print(cx) - ); - } + return None; + } + if let Some(impls) = cx.cache().impls.get(&did) { + for i in impls { + let impl_ = i.inner_impl(); + if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + // Two different types might have the same did, + // without actually being the same. + continue; + } + if let Some(trait_) = &impl_.trait_ { + let trait_did = trait_.def_id(); - //use the "where" class here to make it small + if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) + { + if out.is_empty() { write!( &mut out, - "{}", - impl_.print(false, cx) + "Notable traits for {}\ + ", + impl_.for_.print(cx) ); - for it in &impl_.items { - if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { - out.push_str(" "); - let empty_set = FxHashSet::default(); - let src_link = - AssocItemLink::GotoSource(trait_did.into(), &empty_set); - assoc_type( - &mut out, - it, - &tydef.generics, - &[], // intentionally leaving out bounds - Some(&tydef.type_), - src_link, - 0, - cx, - ); - out.push_str(";"); - } + } + + //use the "where" class here to make it small + write!( + &mut out, + "{}", + impl_.print(false, cx) + ); + for it in &impl_.items { + if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { + out.push_str(" "); + let empty_set = FxHashSet::default(); + let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set); + assoc_type( + &mut out, + it, + &tydef.generics, + &[], // intentionally leaving out bounds + Some(&tydef.type_), + src_link, + 0, + cx, + ); + out.push_str(";"); } } } @@ -1345,16 +1342,18 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { } } - if !out.is_empty() { - out.insert_str( - 0, - "ⓘ\ - ", - ); - out.push_str(""); + if out.is_empty() { + return None; } - out.into_inner() + out.insert_str( + 0, + "ⓘ\ + ", + ); + out.push_str(""); + + Some(out.into_inner()) } #[derive(Clone, Copy, Debug)] diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index ce4fc4d68fac2..e6abd23eb951b 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -533,7 +533,12 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle generics = f.generics.print(cx), where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline), decl = f.decl.full_print(header_len, 0, cx), - notable_traits = notable_traits_decl(&f.decl, cx), + notable_traits = f + .decl + .output + .as_return() + .and_then(|output| notable_traits_decl(output, cx)) + .unwrap_or_default(), ); }); }); From 303653ef65a337b21226a52546615936225fb5af Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 7 Nov 2022 15:53:30 -0700 Subject: [PATCH 09/17] rustdoc: use javascript to layout notable traits popups Fixes #102576 --- src/librustdoc/html/format.rs | 4 - src/librustdoc/html/render/context.rs | 7 +- src/librustdoc/html/render/mod.rs | 145 ++++++++++++------ src/librustdoc/html/render/print_item.rs | 29 ++-- src/librustdoc/html/static/css/noscript.css | 6 + src/librustdoc/html/static/css/rustdoc.css | 23 +-- src/librustdoc/html/static/js/main.js | 85 +++++++++- src/test/rustdoc-gui/notable-trait.goml | 29 ++-- ...c-notable_trait-slice.bare_fn_matches.html | 1 + src/test/rustdoc/doc-notable_trait-slice.rs | 4 +- .../rustdoc/doc-notable_trait.bare-fn.html | 1 + src/test/rustdoc/doc-notable_trait.rs | 10 +- .../doc-notable_trait.some-struct-new.html | 1 + .../rustdoc/doc-notable_trait.wrap-me.html | 1 + .../spotlight-from-dependency.odd.html | 1 + src/test/rustdoc/spotlight-from-dependency.rs | 3 +- 16 files changed, 260 insertions(+), 90 deletions(-) create mode 100644 src/test/rustdoc/doc-notable_trait-slice.bare_fn_matches.html create mode 100644 src/test/rustdoc/doc-notable_trait.bare-fn.html create mode 100644 src/test/rustdoc/doc-notable_trait.some-struct-new.html create mode 100644 src/test/rustdoc/doc-notable_trait.wrap-me.html create mode 100644 src/test/rustdoc/spotlight-from-dependency.odd.html diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a5c3d35b1b594..39e2a90222670 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -107,10 +107,6 @@ impl Buffer { self.buffer } - pub(crate) fn insert_str(&mut self, idx: usize, s: &str) { - self.buffer.insert_str(idx, s); - } - pub(crate) fn push_str(&mut self, s: &str) { self.buffer.push_str(s); } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 51843a505f709..73690c86f4f72 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -69,11 +69,13 @@ pub(crate) struct Context<'tcx> { /// the source files are present in the html rendering, then this will be /// `true`. pub(crate) include_sources: bool, + /// Collection of all types with notable traits referenced in the current module. + pub(crate) types_with_notable_traits: FxHashSet, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. #[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 128); +rustc_data_structures::static_assert_size!(Context<'_>, 160); /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { @@ -532,6 +534,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { deref_id_map: FxHashMap::default(), shared: Rc::new(scx), include_sources, + types_with_notable_traits: FxHashSet::default(), }; if emit_crate { @@ -560,6 +563,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { id_map: IdMap::new(), shared: Rc::clone(&self.shared), include_sources: self.include_sources, + types_with_notable_traits: FxHashSet::default(), } } @@ -803,6 +807,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } } } + Ok(()) } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 881f107925315..1c13e2bf67781 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -59,7 +59,7 @@ use rustc_span::{ symbol::{sym, Symbol}, BytePos, FileName, RealFileName, }; -use serde::ser::SerializeSeq; +use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Serialize, Serializer}; use crate::clean::{self, ItemId, RenderedLink, SelfTy}; @@ -803,7 +803,7 @@ fn assoc_method( d: &clean::FnDecl, link: AssocItemLink<'_>, parent: ItemType, - cx: &Context<'_>, + cx: &mut Context<'_>, render_mode: RenderMode, ) { let tcx = cx.tcx(); @@ -836,6 +836,8 @@ fn assoc_method( + name.as_str().len() + generics_len; + let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx)); + let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; let indent_str = " "; @@ -861,13 +863,9 @@ fn assoc_method( name = name, generics = g.print(cx), decl = d.full_print(header_len, indent, cx), - notable_traits = d - .output - .as_return() - .and_then(|output| notable_traits_decl(output, cx)) - .unwrap_or_default(), + notable_traits = notable_traits.unwrap_or_default(), where_clause = print_where_clause(g, cx, indent, end_newline), - ) + ); } /// Writes a span containing the versions at which an item became stable and/or const-stable. For @@ -967,7 +965,7 @@ fn render_assoc_item( item: &clean::Item, link: AssocItemLink<'_>, parent: ItemType, - cx: &Context<'_>, + cx: &mut Context<'_>, render_mode: RenderMode, ) { match &*item.kind { @@ -1277,8 +1275,8 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> Option { - let mut out = Buffer::html(); +pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option { + let mut has_notable_trait = false; let did = ty.def_id(cx.cache())?; @@ -1291,6 +1289,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> Option { { return None; } + if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); @@ -1304,56 +1303,106 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> Option { if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) { - if out.is_empty() { - write!( - &mut out, - "Notable traits for {}\ - ", - impl_.for_.print(cx) - ); - } + has_notable_trait = true; + } + } + } + } + + if has_notable_trait { + cx.types_with_notable_traits.insert(ty.clone()); + Some(format!( + "\ + \ + ", + ty = ty.print(cx), + )) + } else { + None + } +} + +fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { + let mut out = Buffer::html(); + + let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this"); - //use the "where" class here to make it small + let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this"); + + for i in impls { + let impl_ = i.inner_impl(); + if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + // Two different types might have the same did, + // without actually being the same. + continue; + } + if let Some(trait_) = &impl_.trait_ { + let trait_did = trait_.def_id(); + + if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) { + if out.is_empty() { write!( &mut out, - "{}", - impl_.print(false, cx) + "

Notable traits for {}

\ +
",
+                        impl_.for_.print(cx)
                     );
-                    for it in &impl_.items {
-                        if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
-                            out.push_str("    ");
-                            let empty_set = FxHashSet::default();
-                            let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
-                            assoc_type(
-                                &mut out,
-                                it,
-                                &tydef.generics,
-                                &[], // intentionally leaving out bounds
-                                Some(&tydef.type_),
-                                src_link,
-                                0,
-                                cx,
-                            );
-                            out.push_str(";");
-                        }
+                }
+
+                //use the "where" class here to make it small
+                write!(
+                    &mut out,
+                    "{}",
+                    impl_.print(false, cx)
+                );
+                for it in &impl_.items {
+                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
+                        out.push_str("    ");
+                        let empty_set = FxHashSet::default();
+                        let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
+                        assoc_type(
+                            &mut out,
+                            it,
+                            &tydef.generics,
+                            &[], // intentionally leaving out bounds
+                            Some(&tydef.type_),
+                            src_link,
+                            0,
+                            cx,
+                        );
+                        out.push_str(";");
                     }
                 }
             }
         }
     }
-
     if out.is_empty() {
-        return None;
+        write!(&mut out, "
",); } - out.insert_str( - 0, - "ⓘ\ - ", - ); - out.push_str("
"); + (format!("{:#}", ty.print(cx)), out.into_inner()) +} - Some(out.into_inner()) +pub(crate) fn notable_traits_json<'a>( + tys: impl Iterator, + cx: &Context<'_>, +) -> String { + let mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect(); + struct NotableTraitsMap(Vec<(String, String)>); + impl Serialize for NotableTraitsMap { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(self.0.len()))?; + for item in &self.0 { + map.serialize_entry(&item.0, &item.1)?; + } + map.end() + } + } + serde_json::to_string(&NotableTraitsMap(mp)) + .expect("serialize (string, string) -> json object cannot fail") } #[derive(Clone, Copy, Debug)] diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e6abd23eb951b..ac11a860a4f0b 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -17,9 +17,10 @@ use std::rc::Rc; use super::{ collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference, - item_ty_to_section, notable_traits_decl, render_all_impls, render_assoc_item, - render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl, - render_rightside, render_stability_since_raw, AssocItemLink, Context, ImplRenderingParameters, + item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, + render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre, + render_impl, render_rightside, render_stability_since_raw, AssocItemLink, Context, + ImplRenderingParameters, }; use crate::clean; use crate::config::ModuleSorting; @@ -183,6 +184,16 @@ pub(super) fn print_item( unreachable!(); } } + + // Render notable-traits.js used for all methods in this module. + if !cx.types_with_notable_traits.is_empty() { + write!( + buf, + r#""#, + notable_traits_json(cx.types_with_notable_traits.iter(), cx) + ); + cx.types_with_notable_traits.clear(); + } } /// For large structs, enums, unions, etc, determine whether to hide their fields @@ -516,6 +527,9 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle + name.as_str().len() + generics_len; + let notable_traits = + f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx)); + wrap_into_item_decl(w, |w| { wrap_item(w, "fn", |w| { render_attributes_in_pre(w, it, ""); @@ -533,16 +547,11 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle generics = f.generics.print(cx), where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline), decl = f.decl.full_print(header_len, 0, cx), - notable_traits = f - .decl - .output - .as_return() - .and_then(|output| notable_traits_decl(output, cx)) - .unwrap_or_default(), + notable_traits = notable_traits.unwrap_or_default(), ); }); }); - document(w, cx, it, None, HeadingOffset::H2) + document(w, cx, it, None, HeadingOffset::H2); } fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) { diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 301f03a16427a..54e8b6561f34f 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -22,3 +22,9 @@ nav.sub { .source .sidebar { display: none; } + +.notable-traits { + /* layout requires javascript + https://github.com/rust-lang/rust/issues/102576 */ + display: none; +} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a38c0e42ab455..44e4cc0c7acd5 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -183,6 +183,8 @@ h4.code-header { font-weight: 600; margin: 0; padding: 0; + /* position notable traits in mobile mode within the header */ + position: relative; } #crate-search, @@ -1268,13 +1270,12 @@ h3.variant { cursor: pointer; } -.notable-traits:hover .notable-traits-tooltiptext, -.notable-traits .notable-traits-tooltiptext.force-tooltip { +.notable-traits .notable-traits-tooltiptext { display: inline-block; + visibility: hidden; } -.notable-traits .notable-traits-tooltiptext { - display: none; +.notable-traits-tooltiptext { padding: 5px 3px 3px 3px; border-radius: 6px; margin-left: 5px; @@ -1292,22 +1293,26 @@ h3.variant { content: "\00a0\00a0\00a0"; } -.notable-traits .docblock { +.notable-traits-tooltiptext .docblock { margin: 0; } -.notable-traits .notable { - margin: 0; - margin-bottom: 13px; +.notable-traits-tooltiptext .notable { font-size: 1.1875rem; font-weight: 600; display: block; } -.notable-traits .docblock code.content { +.notable-traits-tooltiptext pre, .notable-traits-tooltiptext code { + background: transparent; +} + +.notable-traits-tooltiptext .docblock pre.content { margin: 0; padding: 0; font-size: 1.25rem; + white-space: pre-wrap; + overflow: hidden; } .search-failed { diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 1c84393cb4e6f..8c9d8bc34631a 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -790,6 +790,19 @@ function loadCss(cssUrl) { // we need to switch away from mobile mode and make the main content area scrollable. hideSidebar(); } + if (window.CURRENT_NOTABLE_ELEMENT) { + // As a workaround to the behavior of `contains: layout` used in doc togglers, the + // notable traits popup is positioned using javascript. + // + // This means when the window is resized, we need to redo the layout. + const base = window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE; + const force_visible = base.NOTABLE_FORCE_VISIBLE; + hideNotable(); + if (force_visible) { + showNotable(base); + base.NOTABLE_FORCE_VISIBLE = true; + } + } }); function handleClick(id, f) { @@ -822,10 +835,78 @@ function loadCss(cssUrl) { }); }); + function showNotable(e) { + if (!window.NOTABLE_TRAITS) { + const data = document.getElementById("notable-traits-data"); + if (data) { + window.NOTABLE_TRAITS = JSON.parse(data.innerText); + } else { + throw new Error("showNotable() called on page without any notable traits!"); + } + } + if (window.CURRENT_NOTABLE_ELEMENT && window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE === e) { + // Make this function idempotent. + return; + } + hideNotable(); + const ty = e.getAttribute("data-ty"); + const tooltip = e.getElementsByClassName("notable-traits-tooltip")[0]; + const wrapper = document.createElement("div"); + wrapper.innerHTML = "
" + window.NOTABLE_TRAITS[ty] + "
"; + wrapper.className = "notable-traits-tooltiptext"; + tooltip.appendChild(wrapper); + const pos = wrapper.getBoundingClientRect(); + tooltip.removeChild(wrapper); + wrapper.style.top = (pos.top + window.scrollY) + "px"; + wrapper.style.left = (pos.left + window.scrollX) + "px"; + wrapper.style.width = pos.width + "px"; + document.documentElement.appendChild(wrapper); + window.CURRENT_NOTABLE_ELEMENT = wrapper; + window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE = e; + wrapper.onpointerleave = function(ev) { + // If this is a synthetic touch event, ignore it. A click event will be along shortly. + if (ev.pointerType !== "mouse") { + return; + } + if (!e.NOTABLE_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) { + hideNotable(); + } + }; + } + + function hideNotable() { + if (window.CURRENT_NOTABLE_ELEMENT) { + window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE = false; + document.documentElement.removeChild(window.CURRENT_NOTABLE_ELEMENT); + window.CURRENT_NOTABLE_ELEMENT = null; + } + } + onEachLazy(document.getElementsByClassName("notable-traits"), e => { e.onclick = function() { - this.getElementsByClassName("notable-traits-tooltiptext")[0] - .classList.toggle("force-tooltip"); + this.NOTABLE_FORCE_VISIBLE = this.NOTABLE_FORCE_VISIBLE ? false : true; + if (window.CURRENT_NOTABLE_ELEMENT && !this.NOTABLE_FORCE_VISIBLE) { + hideNotable(); + } else { + showNotable(this); + } + }; + e.onpointerenter = function(ev) { + // If this is a synthetic touch event, ignore it. A click event will be along shortly. + if (ev.pointerType !== "mouse") { + return; + } + showNotable(this); + }; + e.onpointerleave = function(ev) { + // If this is a synthetic touch event, ignore it. A click event will be along shortly. + if (ev.pointerType !== "mouse") { + return; + } + if (!this.NOTABLE_FORCE_VISIBLE && + !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) { + hideNotable(); + } }; }); diff --git a/src/test/rustdoc-gui/notable-trait.goml b/src/test/rustdoc-gui/notable-trait.goml index efe0cb15f08a0..81d381ed1262d 100644 --- a/src/test/rustdoc-gui/notable-trait.goml +++ b/src/test/rustdoc-gui/notable-trait.goml @@ -25,22 +25,28 @@ assert-position: ( {"x": 951}, ) // The tooltip should be beside the `i` +// Also, clicking the tooltip should bring its text into the DOM +assert-count: ("//*[@class='notable-traits-tooltiptext']", 0) click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']" +assert-count: ("//*[@class='notable-traits-tooltiptext']", 1) compare-elements-position-near: ( "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']", + "//*[@class='notable-traits-tooltiptext']", {"y": 2} ) compare-elements-position-false: ( "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']", + "//*[@class='notable-traits-tooltiptext']", ("x") ) // The docblock should be flush with the border. assert-css: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']", + "//*[@class='notable-traits-tooltiptext']/*[@class='docblock']", {"margin-left": "0px"} ) +click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']" +move-cursor-to: "//h1" +assert-count: ("//*[@class='notable-traits-tooltiptext']", 0) // Now only the `i` should be on the next line. size: (1055, 600) @@ -98,26 +104,31 @@ assert-position: ( {"x": 289}, ) // The tooltip should be below `i` +click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']" +assert-count: ("//*[@class='notable-traits-tooltiptext']", 1) compare-elements-position-near-false: ( "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']", + "//*[@class='notable-traits-tooltiptext']", {"y": 2} ) compare-elements-position-false: ( "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']", - "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']", + "//*[@class='notable-traits-tooltiptext']", ("x") ) compare-elements-position-near: ( - "//*[@id='method.create_an_iterator_from_read']/parent::*", - "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']", - {"x": 5} + "//*[@id='method.create_an_iterator_from_read']", + "//*[@class='notable-traits-tooltiptext']", + {"x": 10} ) // The docblock should be flush with the border. assert-css: ( - "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']", + "//*[@class='notable-traits-tooltiptext']/*[@class='docblock']", {"margin-left": "0px"} ) +click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']" +move-cursor-to: "//h1" +assert-count: ("//*[@class='notable-traits-tooltiptext']", 0) // Checking on very small mobile. The `i` should be on its own line. size: (365, 600) diff --git a/src/test/rustdoc/doc-notable_trait-slice.bare_fn_matches.html b/src/test/rustdoc/doc-notable_trait-slice.bare_fn_matches.html new file mode 100644 index 0000000000000..6b58be7e6853e --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait-slice.bare_fn_matches.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/doc-notable_trait-slice.rs b/src/test/rustdoc/doc-notable_trait-slice.rs index b0d414027216a..2411da8cd4549 100644 --- a/src/test/rustdoc/doc-notable_trait-slice.rs +++ b/src/test/rustdoc/doc-notable_trait-slice.rs @@ -8,13 +8,13 @@ pub struct OtherStruct; impl SomeTrait for &[SomeStruct] {} // @has doc_notable_trait_slice/fn.bare_fn_matches.html -// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]' +// @snapshot bare_fn_matches - '//script[@id="notable-traits-data"]' pub fn bare_fn_matches() -> &'static [SomeStruct] { &[] } // @has doc_notable_trait_slice/fn.bare_fn_no_matches.html -// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]' +// @count - '//script[@id="notable-traits-data"]' 0 pub fn bare_fn_no_matches() -> &'static [OtherStruct] { &[] } diff --git a/src/test/rustdoc/doc-notable_trait.bare-fn.html b/src/test/rustdoc/doc-notable_trait.bare-fn.html new file mode 100644 index 0000000000000..4e4a3f18f2498 --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait.bare-fn.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/doc-notable_trait.rs b/src/test/rustdoc/doc-notable_trait.rs index 58a24b855d6e2..1f2cd7181c3d4 100644 --- a/src/test/rustdoc/doc-notable_trait.rs +++ b/src/test/rustdoc/doc-notable_trait.rs @@ -9,7 +9,8 @@ impl SomeTrait for Wrapper {} #[doc(notable_trait)] pub trait SomeTrait { // @has doc_notable_trait/trait.SomeTrait.html - // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' + // @has - '//span[@class="notable-traits"]/@data-ty' 'Wrapper' + // @snapshot wrap-me - '//script[@id="notable-traits-data"]' fn wrap_me(self) -> Wrapper where Self: Sized { Wrapper { inner: self, @@ -22,15 +23,16 @@ impl SomeTrait for SomeStruct {} impl SomeStruct { // @has doc_notable_trait/struct.SomeStruct.html - // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' - // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' + // @has - '//span[@class="notable-traits"]/@data-ty' 'SomeStruct' + // @snapshot some-struct-new - '//script[@id="notable-traits-data"]' pub fn new() -> SomeStruct { SomeStruct } } // @has doc_notable_trait/fn.bare_fn.html -// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' +// @has - '//span[@class="notable-traits"]/@data-ty' 'SomeStruct' +// @snapshot bare-fn - '//script[@id="notable-traits-data"]' pub fn bare_fn() -> SomeStruct { SomeStruct } diff --git a/src/test/rustdoc/doc-notable_trait.some-struct-new.html b/src/test/rustdoc/doc-notable_trait.some-struct-new.html new file mode 100644 index 0000000000000..a61e7c752e66d --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait.some-struct-new.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/doc-notable_trait.wrap-me.html b/src/test/rustdoc/doc-notable_trait.wrap-me.html new file mode 100644 index 0000000000000..9a59d5edd12a8 --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait.wrap-me.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/spotlight-from-dependency.odd.html b/src/test/rustdoc/spotlight-from-dependency.odd.html new file mode 100644 index 0000000000000..987a949af44b1 --- /dev/null +++ b/src/test/rustdoc/spotlight-from-dependency.odd.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/rustdoc/spotlight-from-dependency.rs b/src/test/rustdoc/spotlight-from-dependency.rs index 5245789212d8c..156aedca62b4e 100644 --- a/src/test/rustdoc/spotlight-from-dependency.rs +++ b/src/test/rustdoc/spotlight-from-dependency.rs @@ -3,7 +3,8 @@ use std::iter::Iterator; // @has foo/struct.Odd.html -// @has - '//*[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd' +// @has - '//*[@id="method.new"]//span[@class="notable-traits"]/@data-ty' 'Odd' +// @snapshot odd - '//script[@id="notable-traits-data"]' pub struct Odd { current: usize, } From a45151e2cbe74de63f50656b24257663d145c52a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 7 Nov 2022 21:18:01 -0700 Subject: [PATCH 10/17] rustdoc: fix font color inheritance from body, and test --- src/librustdoc/html/static/js/main.js | 6 +- src/test/rustdoc-gui/notable-trait.goml | 73 +++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 8c9d8bc34631a..0426774e80d46 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -860,7 +860,8 @@ function loadCss(cssUrl) { wrapper.style.top = (pos.top + window.scrollY) + "px"; wrapper.style.left = (pos.left + window.scrollX) + "px"; wrapper.style.width = pos.width + "px"; - document.documentElement.appendChild(wrapper); + const body = document.getElementsByTagName("body")[0]; + body.appendChild(wrapper); window.CURRENT_NOTABLE_ELEMENT = wrapper; window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE = e; wrapper.onpointerleave = function(ev) { @@ -877,7 +878,8 @@ function loadCss(cssUrl) { function hideNotable() { if (window.CURRENT_NOTABLE_ELEMENT) { window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE = false; - document.documentElement.removeChild(window.CURRENT_NOTABLE_ELEMENT); + const body = document.getElementsByTagName("body")[0]; + body.removeChild(window.CURRENT_NOTABLE_ELEMENT); window.CURRENT_NOTABLE_ELEMENT = null; } } diff --git a/src/test/rustdoc-gui/notable-trait.goml b/src/test/rustdoc-gui/notable-trait.goml index 81d381ed1262d..d8261d8dc902c 100644 --- a/src/test/rustdoc-gui/notable-trait.goml +++ b/src/test/rustdoc-gui/notable-trait.goml @@ -137,3 +137,76 @@ compare-elements-position-false: ( "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']", ("y", "x"), ) + +// Now check the colors. +define-function: ( + "check-colors", + (theme, header_color, content_color, type_color, trait_color), + [ + ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"), + // This is needed to ensure that the text color is computed. + ("show-text", true), + + // Setting the theme. + ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}), + // We reload the page so the local storage settings are being used. + ("reload"), + + ("move-cursor-to", "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"), + ("assert-count", (".notable-traits-tooltiptext", 1)), + + ("assert-css", ( + ".notable-traits-tooltiptext h3.notable", + {"color": |header_color|}, + ALL, + )), + ("assert-css", ( + ".notable-traits-tooltiptext pre.content", + {"color": |content_color|}, + ALL, + )), + ("assert-css", ( + ".notable-traits-tooltiptext pre.content a.struct", + {"color": |type_color|}, + ALL, + )), + ("assert-css", ( + ".notable-traits-tooltiptext pre.content a.trait", + {"color": |trait_color|}, + ALL, + )), + ] +) + +call-function: ( + "check-colors", + { + "theme": "ayu", + "content_color": "rgb(230, 225, 207)", + "header_color": "rgb(255, 255, 255)", + "type_color": "rgb(255, 160, 165)", + "trait_color": "rgb(57, 175, 215)", + }, +) + +call-function: ( + "check-colors", + { + "theme": "dark", + "content_color": "rgb(221, 221, 221)", + "header_color": "rgb(221, 221, 221)", + "type_color": "rgb(45, 191, 184)", + "trait_color": "rgb(183, 140, 242)", + }, +) + +call-function: ( + "check-colors", + { + "theme": "light", + "content_color": "rgb(0, 0, 0)", + "header_color": "rgb(0, 0, 0)", + "type_color": "rgb(173, 55, 138)", + "trait_color": "rgb(110, 79, 201)", + }, +) From 0e0bcd95cda4293915ecd68921320a0928cdd0bb Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Fri, 4 Nov 2022 16:27:28 +0000 Subject: [PATCH 11/17] prevent uninitialized access in black_box for zero-sized-types --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 15 +++++++-- src/test/ui/sanitize/memory-passing.rs | 32 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/sanitize/memory-passing.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 825011941a241..cf590a43826e5 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -340,17 +340,26 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::black_box => { args[0].val.store(self, result); - + let result_val_span = [result.llval]; // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do // this. LLVM's interpretation of inline assembly is that it's, well, a black // box. This isn't the greatest implementation since it probably deoptimizes // more than we want, but it's so far good enough. + // + // For zero-sized types, the location pointed to by the result may be + // uninitialized. Do not "use" the result in this case; instead just clobber + // the memory. + let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() { + ("~{memory}", &[]) + } else { + ("r,~{memory}", &result_val_span) + }; crate::asm::inline_asm_call( self, "", - "r,~{memory}", - &[result.llval], + constraint, + inputs, self.type_void(), true, false, diff --git a/src/test/ui/sanitize/memory-passing.rs b/src/test/ui/sanitize/memory-passing.rs new file mode 100644 index 0000000000000..6d9b70ad6b1c2 --- /dev/null +++ b/src/test/ui/sanitize/memory-passing.rs @@ -0,0 +1,32 @@ +// needs-sanitizer-support +// needs-sanitizer-memory +// +// revisions: unoptimized optimized +// +// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O +// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins +// +// run-pass +// +// This test case intentionally limits the usage of the std, +// since it will be linked with an uninstrumented version of it. + +#![feature(core_intrinsics)] +#![feature(start)] +#![allow(invalid_value)] + +use std::hint::black_box; + +fn calling_black_box_on_zst_ok() { + // It's OK to call black_box on a value of a zero-sized type, even if its + // underlying the memory location is uninitialized. For non-zero-sized types, + // this would be an MSAN error. + let zst = (); + black_box(zst); +} + +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + calling_black_box_on_zst_ok(); + 0 +} From 06a77af35dea5dcdabe1676b795d375e119a0407 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 8 Nov 2022 17:22:44 +0530 Subject: [PATCH 12/17] Add retry flag to remote-test-server This allows retrying binding TCP Socket multiple times. This is useful when using emulators as network might not be available in the beginning. This was orignally implemented in https://github.com/rust-lang/rust/pull/100316 Signed-off-by: Ayush Singh --- src/tools/remote-test-server/src/main.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index ec992da681219..8e7c39e72b68b 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -39,6 +39,8 @@ macro_rules! t { } static TEST: AtomicUsize = AtomicUsize::new(0); +const RETRY_INTERVAL: u64 = 1; +const NUMBER_OF_RETRIES: usize = 5; #[derive(Copy, Clone)] struct Config { @@ -115,7 +117,7 @@ fn main() { let config = Config::parse_args(); println!("starting test server"); - let listener = t!(TcpListener::bind(config.bind)); + let listener = bind_socket(config.bind); let (work, tmp): (PathBuf, PathBuf) = if cfg!(target_os = "android") { ("/data/local/tmp/work".into(), "/data/local/tmp/work/tmp".into()) } else { @@ -159,6 +161,16 @@ fn main() { } } +fn bind_socket(addr: SocketAddr) -> TcpListener { + for _ in 0..(NUMBER_OF_RETRIES - 1) { + if let Ok(x) = TcpListener::bind(addr) { + return x; + } + std::thread::sleep(std::time::Duration::from_secs(RETRY_INTERVAL)); + } + TcpListener::bind(addr).unwrap() +} + fn handle_push(socket: TcpStream, work: &Path, config: Config) { let mut reader = BufReader::new(socket); let dst = recv(&work, &mut reader); From 53e8b490d82a1abe0c617404fe1b352579cfbbc0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 9 Nov 2022 13:55:52 -0700 Subject: [PATCH 13/17] rustdoc: sort output to make it deterministic --- src/librustdoc/html/render/mod.rs | 3 ++- src/test/rustdoc/doc-notable_trait.some-struct-new.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1c13e2bf67781..fffd90c51fad1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1387,7 +1387,8 @@ pub(crate) fn notable_traits_json<'a>( tys: impl Iterator, cx: &Context<'_>, ) -> String { - let mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect(); + let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect(); + mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2)); struct NotableTraitsMap(Vec<(String, String)>); impl Serialize for NotableTraitsMap { fn serialize(&self, serializer: S) -> Result diff --git a/src/test/rustdoc/doc-notable_trait.some-struct-new.html b/src/test/rustdoc/doc-notable_trait.some-struct-new.html index a61e7c752e66d..c0fd9748fd371 100644 --- a/src/test/rustdoc/doc-notable_trait.some-struct-new.html +++ b/src/test/rustdoc/doc-notable_trait.some-struct-new.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 50bb7a40e11918a93e19ca44ca8893e3b56a8ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 16 Aug 2022 07:46:33 -0700 Subject: [PATCH 14/17] Tweak span for `#[must_use]` Do not point at whole statement, only at the expression (skip pointing at `;`) --- compiler/rustc_lint/src/unused.rs | 9 +++------ .../2229_closure_analysis/match/issue-87097.stderr | 4 ++-- .../cfg-attr-multi-true.stderr | 2 +- src/test/ui/generator/issue-52398.stderr | 4 ++-- src/test/ui/generator/issue-57084.stderr | 2 +- src/test/ui/generator/match-bindings.stderr | 2 +- src/test/ui/generator/reborrow-mut-upvar.stderr | 2 +- .../too-live-local-in-immovable-gen.stderr | 2 +- src/test/ui/generator/yield-in-args-rev.stderr | 2 +- src/test/ui/generator/yield-in-box.stderr | 2 +- src/test/ui/generator/yield-in-initializer.stderr | 2 +- src/test/ui/generator/yield-subtype.stderr | 2 +- src/test/ui/issues/issue-1460.stderr | 2 +- src/test/ui/issues/issue-16256.stderr | 2 +- src/test/ui/lint/fn_must_use.stderr | 12 ++++++------ .../ui/lint/unused/must-use-box-from-raw.stderr | 2 +- src/test/ui/lint/unused/must_use-array.stderr | 8 ++++---- .../lint/unused/must_use-in-stdlib-traits.stderr | 10 +++++----- src/test/ui/lint/unused/must_use-trait.stderr | 6 +++--- src/test/ui/lint/unused/must_use-unit.stderr | 4 ++-- src/test/ui/lint/unused/unused-closure.stderr | 14 +++++++------- src/test/ui/lint/unused/unused-result.stderr | 8 ++++---- .../lint/unused/unused_attributes-must_use.stderr | 14 +++++++------- src/test/ui/nll/issue-48623-generator.stderr | 2 +- 24 files changed, 58 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 46706e4984451..3e8bd7a374dea 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -87,17 +87,14 @@ declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]); impl<'tcx> LateLintPass<'tcx> for UnusedResults { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { - let expr = match s.kind { - hir::StmtKind::Semi(ref expr) => &**expr, - _ => return, - }; + let hir::StmtKind::Semi(expr) = s.kind else { return; }; if let hir::ExprKind::Ret(..) = expr.kind { return; } let ty = cx.typeck_results().expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1); + let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, expr.span, "", "", 1); let mut fn_warned = false; let mut op_warned = false; @@ -119,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { _ => None, }; if let Some(def_id) = maybe_def_id { - fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", ""); + fn_warned = check_must_use_def(cx, def_id, expr.span, "return value of ", ""); } else if type_permits_lack_of_use { // We don't warn about unused unit or uninhabited types. // (See https://github.com/rust-lang/rust/issues/43806 for details.) diff --git a/src/test/ui/closures/2229_closure_analysis/match/issue-87097.stderr b/src/test/ui/closures/2229_closure_analysis/match/issue-87097.stderr index 3840108597131..39ec71ba22a18 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/issue-87097.stderr +++ b/src/test/ui/closures/2229_closure_analysis/match/issue-87097.stderr @@ -16,7 +16,7 @@ LL | / || match out_ref { LL | | Variant::A => (), LL | | Variant::B => (), LL | | }; - | |______^ + | |_____^ | = note: closures are lazy and do nothing unless called = note: `#[warn(unused_must_use)]` on by default @@ -28,7 +28,7 @@ LL | / || match here.field { LL | | Variant::A => (), LL | | Variant::B => (), LL | | }; - | |______^ + | |_____^ | = note: closures are lazy and do nothing unless called diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr index 5f278f94b93bd..fbfcd45652f19 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr @@ -28,7 +28,7 @@ warning: unused `MustUseDeprecated` that must be used --> $DIR/cfg-attr-multi-true.rs:19:5 | LL | MustUseDeprecated::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/cfg-attr-multi-true.rs:7:9 diff --git a/src/test/ui/generator/issue-52398.stderr b/src/test/ui/generator/issue-52398.stderr index 30a6732f75956..539343275df60 100644 --- a/src/test/ui/generator/issue-52398.stderr +++ b/src/test/ui/generator/issue-52398.stderr @@ -4,7 +4,7 @@ warning: unused generator that must be used LL | / move || { LL | | A.test(yield); LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default @@ -16,7 +16,7 @@ LL | / static move || { LL | | yield *y.borrow(); LL | | return "Done"; LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed diff --git a/src/test/ui/generator/issue-57084.stderr b/src/test/ui/generator/issue-57084.stderr index 29aca94408a82..8f1fc5e803194 100644 --- a/src/test/ui/generator/issue-57084.stderr +++ b/src/test/ui/generator/issue-57084.stderr @@ -7,7 +7,7 @@ LL | | loop { LL | | yield LL | | } LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/generator/match-bindings.stderr b/src/test/ui/generator/match-bindings.stderr index b911b6661909a..3dd2d595445aa 100644 --- a/src/test/ui/generator/match-bindings.stderr +++ b/src/test/ui/generator/match-bindings.stderr @@ -8,7 +8,7 @@ LL | | match Enum::A(String::new()) { ... | LL | | } LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/generator/reborrow-mut-upvar.stderr b/src/test/ui/generator/reborrow-mut-upvar.stderr index e83dbf833bfa7..2e1fec35eaf52 100644 --- a/src/test/ui/generator/reborrow-mut-upvar.stderr +++ b/src/test/ui/generator/reborrow-mut-upvar.stderr @@ -8,7 +8,7 @@ LL | | yield; ... | LL | | *bar = 2; LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/generator/too-live-local-in-immovable-gen.stderr b/src/test/ui/generator/too-live-local-in-immovable-gen.stderr index 5cb43067fee6b..e262f213f63d2 100644 --- a/src/test/ui/generator/too-live-local-in-immovable-gen.stderr +++ b/src/test/ui/generator/too-live-local-in-immovable-gen.stderr @@ -8,7 +8,7 @@ LL | | // and it should also find out that `a` is not live. ... | LL | | let _ = &a; LL | | }; - | |__________^ + | |_________^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/generator/yield-in-args-rev.stderr b/src/test/ui/generator/yield-in-args-rev.stderr index c9e1ab722d47f..a87248f662100 100644 --- a/src/test/ui/generator/yield-in-args-rev.stderr +++ b/src/test/ui/generator/yield-in-args-rev.stderr @@ -5,7 +5,7 @@ LL | / || { LL | | let b = true; LL | | foo(yield, &b); LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/generator/yield-in-box.stderr b/src/test/ui/generator/yield-in-box.stderr index 8587e1dc663bc..9d03ee00800c8 100644 --- a/src/test/ui/generator/yield-in-box.stderr +++ b/src/test/ui/generator/yield-in-box.stderr @@ -8,7 +8,7 @@ LL | | let _t = box (&x, yield 0, &y); ... | LL | | } LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/generator/yield-in-initializer.stderr b/src/test/ui/generator/yield-in-initializer.stderr index 07de24662cf2e..ed14a2e3273af 100644 --- a/src/test/ui/generator/yield-in-initializer.stderr +++ b/src/test/ui/generator/yield-in-initializer.stderr @@ -8,7 +8,7 @@ LL | | // See https://github.com/rust-lang/rust/issues/52792 ... | LL | | } LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/generator/yield-subtype.stderr b/src/test/ui/generator/yield-subtype.stderr index fe10477bf7380..97862e91cd4a0 100644 --- a/src/test/ui/generator/yield-subtype.stderr +++ b/src/test/ui/generator/yield-subtype.stderr @@ -5,7 +5,7 @@ LL | / || { LL | | yield a; LL | | yield b; LL | | }; - | |______^ + | |_____^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/issues/issue-1460.stderr b/src/test/ui/issues/issue-1460.stderr index f0ff2cafd4466..eb7661fad56db 100644 --- a/src/test/ui/issues/issue-1460.stderr +++ b/src/test/ui/issues/issue-1460.stderr @@ -2,7 +2,7 @@ warning: unused closure that must be used --> $DIR/issue-1460.rs:6:5 | LL | {|i: u32| if 1 == i { }}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/issues/issue-16256.stderr b/src/test/ui/issues/issue-16256.stderr index ca8e9a1bed337..d920530b57c69 100644 --- a/src/test/ui/issues/issue-16256.stderr +++ b/src/test/ui/issues/issue-16256.stderr @@ -2,7 +2,7 @@ warning: unused closure that must be used --> $DIR/issue-16256.rs:6:5 | LL | |c: u8| buf.push(c); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called = note: `#[warn(unused_must_use)]` on by default diff --git a/src/test/ui/lint/fn_must_use.stderr b/src/test/ui/lint/fn_must_use.stderr index 2805720f035b8..657f23c60856f 100644 --- a/src/test/ui/lint/fn_must_use.stderr +++ b/src/test/ui/lint/fn_must_use.stderr @@ -2,7 +2,7 @@ warning: unused return value of `need_to_use_this_value` that must be used --> $DIR/fn_must_use.rs:55:5 | LL | need_to_use_this_value(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: it's important note: the lint level is defined here @@ -15,13 +15,13 @@ warning: unused return value of `MyStruct::need_to_use_this_method_value` that m --> $DIR/fn_must_use.rs:60:5 | LL | m.need_to_use_this_method_value(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused return value of `EvenNature::is_even` that must be used --> $DIR/fn_must_use.rs:61:5 | LL | m.is_even(); // trait method! - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: no side effects @@ -29,19 +29,19 @@ warning: unused return value of `MyStruct::need_to_use_this_associated_function_ --> $DIR/fn_must_use.rs:64:5 | LL | MyStruct::need_to_use_this_associated_function_value(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:70:5 | LL | 2.eq(&3); - | ^^^^^^^^^ + | ^^^^^^^^ warning: unused return value of `std::cmp::PartialEq::eq` that must be used --> $DIR/fn_must_use.rs:71:5 | LL | m.eq(&n); - | ^^^^^^^^^ + | ^^^^^^^^ warning: unused comparison that must be used --> $DIR/fn_must_use.rs:74:5 diff --git a/src/test/ui/lint/unused/must-use-box-from-raw.stderr b/src/test/ui/lint/unused/must-use-box-from-raw.stderr index 011acc3bf5d6e..72118275774d1 100644 --- a/src/test/ui/lint/unused/must-use-box-from-raw.stderr +++ b/src/test/ui/lint/unused/must-use-box-from-raw.stderr @@ -2,7 +2,7 @@ warning: unused return value of `Box::::from_raw` that must be used --> $DIR/must-use-box-from-raw.rs:8:5 | LL | Box::from_raw(ptr); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: call `drop(from_raw(ptr))` if you intend to drop the `Box` note: the lint level is defined here diff --git a/src/test/ui/lint/unused/must_use-array.stderr b/src/test/ui/lint/unused/must_use-array.stderr index 45a5317fccc6e..bba2b1ba078c6 100644 --- a/src/test/ui/lint/unused/must_use-array.stderr +++ b/src/test/ui/lint/unused/must_use-array.stderr @@ -2,7 +2,7 @@ error: unused array of `S` that must be used --> $DIR/must_use-array.rs:39:5 | LL | singleton(); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/must_use-array.rs:1:9 @@ -14,7 +14,7 @@ error: unused array of `S` that must be used --> $DIR/must_use-array.rs:40:5 | LL | many(); - | ^^^^^^^ + | ^^^^^^ error: unused array of `S` in tuple element 0 that must be used --> $DIR/must_use-array.rs:41:6 @@ -26,7 +26,7 @@ error: unused array of implementers of `T` that must be used --> $DIR/must_use-array.rs:42:5 | LL | array_of_impl_trait(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: unused array of boxed `T` trait objects in tuple element 1 that must be used --> $DIR/must_use-array.rs:43:5 @@ -38,7 +38,7 @@ error: unused array of arrays of arrays of `S` that must be used --> $DIR/must_use-array.rs:45:5 | LL | array_of_arrays_of_arrays(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/lint/unused/must_use-in-stdlib-traits.stderr b/src/test/ui/lint/unused/must_use-in-stdlib-traits.stderr index f5199f43c74bd..ef738708d5f4e 100644 --- a/src/test/ui/lint/unused/must_use-in-stdlib-traits.stderr +++ b/src/test/ui/lint/unused/must_use-in-stdlib-traits.stderr @@ -2,7 +2,7 @@ error: unused implementer of `Iterator` that must be used --> $DIR/must_use-in-stdlib-traits.rs:42:4 | LL | iterator(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: iterators are lazy and do nothing unless consumed note: the lint level is defined here @@ -15,7 +15,7 @@ error: unused implementer of `Future` that must be used --> $DIR/must_use-in-stdlib-traits.rs:43:4 | LL | future(); - | ^^^^^^^^^ + | ^^^^^^^^ | = note: futures do nothing unless you `.await` or poll them @@ -23,7 +23,7 @@ error: unused implementer of `FnOnce` that must be used --> $DIR/must_use-in-stdlib-traits.rs:44:4 | LL | square_fn_once(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called @@ -31,7 +31,7 @@ error: unused implementer of `FnMut` that must be used --> $DIR/must_use-in-stdlib-traits.rs:45:4 | LL | square_fn_mut(); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called @@ -39,7 +39,7 @@ error: unused implementer of `Fn` that must be used --> $DIR/must_use-in-stdlib-traits.rs:46:4 | LL | square_fn(); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called diff --git a/src/test/ui/lint/unused/must_use-trait.stderr b/src/test/ui/lint/unused/must_use-trait.stderr index a42eb8841789d..2f54964848359 100644 --- a/src/test/ui/lint/unused/must_use-trait.stderr +++ b/src/test/ui/lint/unused/must_use-trait.stderr @@ -2,7 +2,7 @@ error: unused implementer of `Critical` that must be used --> $DIR/must_use-trait.rs:33:5 | LL | get_critical(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/must_use-trait.rs:1:9 @@ -14,13 +14,13 @@ error: unused boxed `Critical` trait object that must be used --> $DIR/must_use-trait.rs:34:5 | LL | get_boxed_critical(); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: unused boxed boxed `Critical` trait object that must be used --> $DIR/must_use-trait.rs:35:5 | LL | get_nested_boxed_critical(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unused boxed `Critical` trait object in tuple element 1 that must be used --> $DIR/must_use-trait.rs:37:5 diff --git a/src/test/ui/lint/unused/must_use-unit.stderr b/src/test/ui/lint/unused/must_use-unit.stderr index 7f25a19350862..9fcbc5074ea80 100644 --- a/src/test/ui/lint/unused/must_use-unit.stderr +++ b/src/test/ui/lint/unused/must_use-unit.stderr @@ -2,7 +2,7 @@ error: unused return value of `foo` that must be used --> $DIR/must_use-unit.rs:13:5 | LL | foo(); - | ^^^^^^ + | ^^^^^ | note: the lint level is defined here --> $DIR/must_use-unit.rs:2:9 @@ -14,7 +14,7 @@ error: unused return value of `bar` that must be used --> $DIR/must_use-unit.rs:15:5 | LL | bar(); - | ^^^^^^ + | ^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/unused/unused-closure.stderr b/src/test/ui/lint/unused/unused-closure.stderr index 4362abd2037ff..c3a82402e0a2e 100644 --- a/src/test/ui/lint/unused/unused-closure.stderr +++ b/src/test/ui/lint/unused/unused-closure.stderr @@ -4,7 +4,7 @@ error: unused closure that must be used LL | / || { LL | | println!("Hello!"); LL | | }; - | |______^ + | |_____^ | = note: closures are lazy and do nothing unless called note: the lint level is defined here @@ -17,7 +17,7 @@ error: unused implementer of `Future` that must be used --> $DIR/unused-closure.rs:13:5 | LL | async {}; - | ^^^^^^^^^ + | ^^^^^^^^ | = note: futures do nothing unless you `.await` or poll them @@ -25,7 +25,7 @@ error: unused closure that must be used --> $DIR/unused-closure.rs:14:5 | LL | || async {}; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called @@ -33,7 +33,7 @@ error: unused closure that must be used --> $DIR/unused-closure.rs:15:5 | LL | async || {}; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called @@ -41,7 +41,7 @@ error: unused array of boxed arrays of closures that must be used --> $DIR/unused-closure.rs:18:5 | LL | [Box::new([|| {}; 10]); 1]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called @@ -49,7 +49,7 @@ error: unused closure that must be used --> $DIR/unused-closure.rs:20:5 | LL | vec![|| "a"].pop().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called @@ -57,7 +57,7 @@ error: unused closure that must be used --> $DIR/unused-closure.rs:23:9 | LL | || true; - | ^^^^^^^^ + | ^^^^^^^ | = note: closures are lazy and do nothing unless called diff --git a/src/test/ui/lint/unused/unused-result.stderr b/src/test/ui/lint/unused/unused-result.stderr index 087e06341cdde..4e1ba1fd9595f 100644 --- a/src/test/ui/lint/unused/unused-result.stderr +++ b/src/test/ui/lint/unused/unused-result.stderr @@ -2,7 +2,7 @@ error: unused `MustUse` that must be used --> $DIR/unused-result.rs:21:5 | LL | foo::(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/unused-result.rs:2:25 @@ -14,7 +14,7 @@ error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:22:5 | LL | foo::(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = note: some message @@ -34,13 +34,13 @@ error: unused `MustUse` that must be used --> $DIR/unused-result.rs:35:5 | LL | foo::(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: unused `MustUseMsg` that must be used --> $DIR/unused-result.rs:36:5 | LL | foo::(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = note: some message diff --git a/src/test/ui/lint/unused/unused_attributes-must_use.stderr b/src/test/ui/lint/unused/unused_attributes-must_use.stderr index ce959ddbc4697..0f699429e0243 100644 --- a/src/test/ui/lint/unused/unused_attributes-must_use.stderr +++ b/src/test/ui/lint/unused/unused_attributes-must_use.stderr @@ -139,7 +139,7 @@ error: unused `X` that must be used --> $DIR/unused_attributes-must_use.rs:103:5 | LL | X; - | ^^ + | ^ | note: the lint level is defined here --> $DIR/unused_attributes-must_use.rs:2:28 @@ -151,37 +151,37 @@ error: unused `Y` that must be used --> $DIR/unused_attributes-must_use.rs:104:5 | LL | Y::Z; - | ^^^^^ + | ^^^^ error: unused `U` that must be used --> $DIR/unused_attributes-must_use.rs:105:5 | LL | U { unit: () }; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: unused return value of `U::method` that must be used --> $DIR/unused_attributes-must_use.rs:106:5 | LL | U::method(); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: unused return value of `foo` that must be used --> $DIR/unused_attributes-must_use.rs:107:5 | LL | foo(); - | ^^^^^^ + | ^^^^^ error: unused return value of `foreign_foo` that must be used --> $DIR/unused_attributes-must_use.rs:110:9 | LL | foreign_foo(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: unused return value of `Use::get_four` that must be used --> $DIR/unused_attributes-must_use.rs:118:5 | LL | ().get_four(); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: aborting due to 28 previous errors diff --git a/src/test/ui/nll/issue-48623-generator.stderr b/src/test/ui/nll/issue-48623-generator.stderr index 1b35165db45dc..bfdfca2100406 100644 --- a/src/test/ui/nll/issue-48623-generator.stderr +++ b/src/test/ui/nll/issue-48623-generator.stderr @@ -2,7 +2,7 @@ warning: unused generator that must be used --> $DIR/issue-48623-generator.rs:15:5 | LL | move || { d; yield; &mut *r }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: generators are lazy and do nothing unless resumed = note: `#[warn(unused_must_use)]` on by default From 243496e1299bc6dddb3824a91f026da34f732199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 16 Aug 2022 07:56:42 -0700 Subject: [PATCH 15/17] Consider `#[must_use]` annotation on `async fn` as also affecting the `Future::Output` No longer lint against `#[must_use] async fn foo()`. When encountering a statement that awaits on a `Future`, check if the `Future`'s parent item is annotated with `#[must_use]` and emit a lint if so. This effectively makes `must_use` an annotation on the `Future::Output` instead of only the `Future` itself. Fix #78149. --- compiler/rustc_lint/src/unused.rs | 14 +++- compiler/rustc_passes/src/check_attr.rs | 14 +--- src/test/ui/lint/unused/unused-async.rs | 29 ++++++-- src/test/ui/lint/unused/unused-async.stderr | 79 ++++++++++++++------- 4 files changed, 93 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 3e8bd7a374dea..1a5515530ae9f 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_infer::traits::util::elaborate_predicates_with_span; use rustc_middle::ty::adjustment; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, DefIdTree, Ty}; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; @@ -93,6 +93,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { return; } + if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind + && let ty = cx.typeck_results().expr_ty(&await_expr) + && let ty::Opaque(def_id, _) = ty.kind() + && cx.tcx.ty_is_opaque_future(ty) + && let parent = cx.tcx.parent(*def_id) + && check_must_use_def(cx, parent, expr.span, "awaited future returned by ", "") + { + // We have a bare `foo().await;` on an opaque type from an async function that was + // annotated with `#[must_use]`. + return; + } + let ty = cx.typeck_results().expr_ty(&expr); let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, expr.span, "", "", 1); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 27a57adf964a3..e0da0096c4e1e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -139,7 +139,7 @@ impl CheckAttrVisitor<'_> { sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target), sym::const_trait => self.check_const_trait(attr, span, target), sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), - sym::must_use => self.check_must_use(hir_id, &attr, span, target), + sym::must_use => self.check_must_use(hir_id, &attr, target), sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target), sym::rustc_allow_incoherent_impl => { self.check_allow_incoherent_impl(&attr, span, target) @@ -1163,17 +1163,7 @@ impl CheckAttrVisitor<'_> { } /// Warns against some misuses of `#[must_use]` - fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { - let node = self.tcx.hir().get(hir_id); - if let Some(kind) = node.fn_kind() && let rustc_hir::IsAsync::Async = kind.asyncness() { - self.tcx.emit_spanned_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span, - errors::MustUseAsync { span } - ); - } - + fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool { if !matches!( target, Target::Fn diff --git a/src/test/ui/lint/unused/unused-async.rs b/src/test/ui/lint/unused/unused-async.rs index 7d17af1157379..eda28dab27fac 100644 --- a/src/test/ui/lint/unused/unused-async.rs +++ b/src/test/ui/lint/unused/unused-async.rs @@ -1,24 +1,43 @@ // edition:2018 -// run-pass -#![allow(dead_code)] +#![deny(unused_must_use)] + #[must_use] -//~^ WARNING `must_use` -async fn test() -> i32 { +async fn foo() -> i32 { 1 } +#[must_use] +fn bar() -> impl std::future::Future { + async { + 42 + } +} + +async fn baz() -> i32 { + 0 +} struct Wowee {} impl Wowee { #[must_use] - //~^ WARNING `must_use` async fn test_method() -> i32 { 1 } } +async fn test() { + foo(); //~ ERROR unused return value of `foo` that must be used + //~^ ERROR unused implementer of `Future` that must be used + foo().await; //~ ERROR unused awaited future returned by `foo` that must be used + bar(); //~ ERROR unused return value of `bar` that must be used + //~^ ERROR unused implementer of `Future` that must be used + bar().await; //~ ERROR unused awaited future returned by `bar` that must be used + baz(); //~ ERROR unused implementer of `Future` that must be used + baz().await; // ok +} + /* FIXME(guswynn) update this test when async-fn-in-traits works trait Doer { #[must_use] diff --git a/src/test/ui/lint/unused/unused-async.stderr b/src/test/ui/lint/unused/unused-async.stderr index 6bbc9e2bf0088..ae284681720af 100644 --- a/src/test/ui/lint/unused/unused-async.stderr +++ b/src/test/ui/lint/unused/unused-async.stderr @@ -1,26 +1,55 @@ -warning: `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within - --> $DIR/unused-async.rs:5:1 - | -LL | #[must_use] - | ^^^^^^^^^^^ -LL | -LL | / async fn test() -> i32 { -LL | | 1 -LL | | } - | |_- this attribute does nothing, the `Future`s returned by async functions are already `must_use` - | - = note: `#[warn(unused_attributes)]` on by default - -warning: `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within - --> $DIR/unused-async.rs:15:5 - | -LL | #[must_use] - | ^^^^^^^^^^^ -LL | -LL | / async fn test_method() -> i32 { -LL | | 1 -LL | | } - | |_____- this attribute does nothing, the `Future`s returned by async functions are already `must_use` - -warning: 2 warnings emitted +error: unused implementer of `Future` that must be used + --> $DIR/unused-async.rs:31:5 + | +LL | foo(); + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-async.rs:2:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + = note: futures do nothing unless you `.await` or poll them + +error: unused return value of `foo` that must be used + --> $DIR/unused-async.rs:31:5 + | +LL | foo(); + | ^^^^^ + +error: unused awaited future returned by `foo` that must be used + --> $DIR/unused-async.rs:33:5 + | +LL | foo().await; + | ^^^^^^^^^^^ + +error: unused implementer of `Future` that must be used + --> $DIR/unused-async.rs:34:5 + | +LL | bar(); + | ^^^^^ + | + = note: futures do nothing unless you `.await` or poll them + +error: unused return value of `bar` that must be used + --> $DIR/unused-async.rs:34:5 + | +LL | bar(); + | ^^^^^ + +error: unused awaited future returned by `bar` that must be used + --> $DIR/unused-async.rs:36:5 + | +LL | bar().await; + | ^^^^^^^^^^^ + +error: unused implementer of `Future` that must be used + --> $DIR/unused-async.rs:37:5 + | +LL | baz(); + | ^^^^^ + | + = note: futures do nothing unless you `.await` or poll them + +error: aborting due to 7 previous errors From 8bd8484972ccfb4134c39b93c6ec68406bd1e63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 17 Aug 2022 08:21:43 -0700 Subject: [PATCH 16/17] review comments --- compiler/rustc_lint/src/unused.rs | 13 ++++++++++--- src/test/ui/lint/unused/unused-async.rs | 4 ++-- src/test/ui/lint/unused/unused-async.stderr | 4 ++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1a5515530ae9f..045d76cac62b8 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -95,10 +95,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind && let ty = cx.typeck_results().expr_ty(&await_expr) - && let ty::Opaque(def_id, _) = ty.kind() + && let ty::Opaque(future_def_id, _) = ty.kind() && cx.tcx.ty_is_opaque_future(ty) - && let parent = cx.tcx.parent(*def_id) - && check_must_use_def(cx, parent, expr.span, "awaited future returned by ", "") + // FIXME: This also includes non-async fns that return `impl Future`. + && let async_fn_def_id = cx.tcx.parent(*future_def_id) + && check_must_use_def( + cx, + async_fn_def_id, + expr.span, + "output of future returned by ", + "", + ) { // We have a bare `foo().await;` on an opaque type from an async function that was // annotated with `#[must_use]`. diff --git a/src/test/ui/lint/unused/unused-async.rs b/src/test/ui/lint/unused/unused-async.rs index eda28dab27fac..4be93aa155ad9 100644 --- a/src/test/ui/lint/unused/unused-async.rs +++ b/src/test/ui/lint/unused/unused-async.rs @@ -30,10 +30,10 @@ impl Wowee { async fn test() { foo(); //~ ERROR unused return value of `foo` that must be used //~^ ERROR unused implementer of `Future` that must be used - foo().await; //~ ERROR unused awaited future returned by `foo` that must be used + foo().await; //~ ERROR unused output of future returned by `foo` that must be used bar(); //~ ERROR unused return value of `bar` that must be used //~^ ERROR unused implementer of `Future` that must be used - bar().await; //~ ERROR unused awaited future returned by `bar` that must be used + bar().await; //~ ERROR unused output of future returned by `bar` that must be used baz(); //~ ERROR unused implementer of `Future` that must be used baz().await; // ok } diff --git a/src/test/ui/lint/unused/unused-async.stderr b/src/test/ui/lint/unused/unused-async.stderr index ae284681720af..abc49599309ca 100644 --- a/src/test/ui/lint/unused/unused-async.stderr +++ b/src/test/ui/lint/unused/unused-async.stderr @@ -17,7 +17,7 @@ error: unused return value of `foo` that must be used LL | foo(); | ^^^^^ -error: unused awaited future returned by `foo` that must be used +error: unused output of future returned by `foo` that must be used --> $DIR/unused-async.rs:33:5 | LL | foo().await; @@ -37,7 +37,7 @@ error: unused return value of `bar` that must be used LL | bar(); | ^^^^^ -error: unused awaited future returned by `bar` that must be used +error: unused output of future returned by `bar` that must be used --> $DIR/unused-async.rs:36:5 | LL | bar().await; From f57713b010775afd4061a7bd03c8be3c90465e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 10 Nov 2022 19:01:33 -0800 Subject: [PATCH 17/17] Fix tests after rebase --- src/test/ui/lint/unused/unused-async.stderr | 2 +- src/test/ui/lint/unused/unused-supertrait.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/lint/unused/unused-async.stderr b/src/test/ui/lint/unused/unused-async.stderr index abc49599309ca..4bcb26dc16586 100644 --- a/src/test/ui/lint/unused/unused-async.stderr +++ b/src/test/ui/lint/unused/unused-async.stderr @@ -4,12 +4,12 @@ error: unused implementer of `Future` that must be used LL | foo(); | ^^^^^ | + = note: futures do nothing unless you `.await` or poll them note: the lint level is defined here --> $DIR/unused-async.rs:2:9 | LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ - = note: futures do nothing unless you `.await` or poll them error: unused return value of `foo` that must be used --> $DIR/unused-async.rs:31:5 diff --git a/src/test/ui/lint/unused/unused-supertrait.stderr b/src/test/ui/lint/unused/unused-supertrait.stderr index d2f8c00784817..cb45add9c2b1b 100644 --- a/src/test/ui/lint/unused/unused-supertrait.stderr +++ b/src/test/ui/lint/unused/unused-supertrait.stderr @@ -2,7 +2,7 @@ error: unused implementer of `Iterator` that must be used --> $DIR/unused-supertrait.rs:9:5 | LL | it(); - | ^^^^^ + | ^^^^ | = note: iterators are lazy and do nothing unless consumed note: the lint level is defined here