From 31e3f56e26e97cc319ae2cf7d66ad12fdb005ebb Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 17 Jun 2023 16:06:27 -0700 Subject: [PATCH 001/169] rustdoc: Fix --test-run-directory and relative paths. --- src/librustdoc/doctest.rs | 16 +++++++++++++++ .../run-make/doctests-keep-binaries/Makefile | 13 +++++++++++- tests/run-make/doctests-runtool/Makefile | 20 +++++++++++++++++++ tests/run-make/doctests-runtool/runtool.rs | 3 +++ tests/run-make/doctests-runtool/t.rs | 11 ++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/doctests-runtool/Makefile create mode 100644 tests/run-make/doctests-runtool/runtool.rs create mode 100644 tests/run-make/doctests-runtool/t.rs diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f6631b66f5b6..b409515c5ea0 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -463,7 +463,9 @@ fn run_test( // Run the code! let mut cmd; + let output_file = make_maybe_absolute_path(output_file); if let Some(tool) = runtool { + let tool = make_maybe_absolute_path(tool.into()); cmd = Command::new(tool); cmd.args(runtool_args); cmd.arg(output_file); @@ -497,6 +499,20 @@ fn run_test( Ok(()) } +/// Converts a path intended to use as a command to absolute if it is +/// relative, and not a single component. +/// +/// This is needed to deal with relative paths interacting with +/// `Command::current_dir` in a platform-specific way. +fn make_maybe_absolute_path(path: PathBuf) -> PathBuf { + if path.components().count() == 1 { + // Look up process via PATH. + path + } else { + std::env::current_dir().map(|c| c.join(&path)).unwrap_or_else(|_| path) + } +} + /// Transforms a test into code that can be compiled into a Rust binary, and returns the number of /// lines before the test code begins as well as if the output stream supports colors or not. pub(crate) fn make_test( diff --git a/tests/run-make/doctests-keep-binaries/Makefile b/tests/run-make/doctests-keep-binaries/Makefile index 6254e93d3334..2c647851ad0b 100644 --- a/tests/run-make/doctests-keep-binaries/Makefile +++ b/tests/run-make/doctests-keep-binaries/Makefile @@ -3,7 +3,9 @@ include ../tools.mk # Check that valid binaries are persisted by running them, regardless of whether the --run or --no-run option is used. -all: run no_run +MY_SRC_DIR := ${CURDIR} + +all: run no_run test_run_directory run: mkdir -p $(TMPDIR)/doctests @@ -20,3 +22,12 @@ no_run: $(TMPDIR)/doctests/t_rs_2_0/rust_out $(TMPDIR)/doctests/t_rs_8_0/rust_out rm -rf $(TMPDIR)/doctests + +# Behavior with --test-run-directory with relative paths. +test_run_directory: + mkdir -p $(TMPDIR)/doctests + mkdir -p $(TMPDIR)/rundir + $(RUSTC) --crate-type rlib t.rs + ( cd $(TMPDIR); \ + $(RUSTDOC) -Zunstable-options --test --persist-doctests doctests --test-run-directory rundir --extern t=libt.rlib $(MY_SRC_DIR)/t.rs ) + rm -rf $(TMPDIR)/doctests $(TMPDIR)/rundir diff --git a/tests/run-make/doctests-runtool/Makefile b/tests/run-make/doctests-runtool/Makefile new file mode 100644 index 000000000000..7d5df1e307fb --- /dev/null +++ b/tests/run-make/doctests-runtool/Makefile @@ -0,0 +1,20 @@ +# ignore-cross-compile +include ../tools.mk + +# Tests behavior of rustdoc --runtool + +MY_SRC_DIR := ${CURDIR} + +all: with_test_run_directory + +# Behavior with --runtool with relative paths and --test-run-directory. +with_test_run_directory: + mkdir -p $(TMPDIR)/rundir + mkdir -p $(TMPDIR)/runtool + $(RUSTC) --crate-type rlib t.rs + $(RUSTC) runtool.rs -o $(TMPDIR)/runtool/runtool + ( cd $(TMPDIR); \ + $(RUSTDOC) -Zunstable-options --test --test-run-directory rundir \ + --runtool runtool/runtool --extern t=libt.rlib $(MY_SRC_DIR)/t.rs \ + ) + rm -rf $(TMPDIR)/rundir $(TMPDIR)/runtool diff --git a/tests/run-make/doctests-runtool/runtool.rs b/tests/run-make/doctests-runtool/runtool.rs new file mode 100644 index 000000000000..f5e3afdf212e --- /dev/null +++ b/tests/run-make/doctests-runtool/runtool.rs @@ -0,0 +1,3 @@ +fn main() { + eprintln!("{:?}", std::env::args().collect::>()); +} diff --git a/tests/run-make/doctests-runtool/t.rs b/tests/run-make/doctests-runtool/t.rs new file mode 100644 index 000000000000..c38cf0a0b25d --- /dev/null +++ b/tests/run-make/doctests-runtool/t.rs @@ -0,0 +1,11 @@ +/// Fungle the foople. +/// ``` +/// t::foople(); +/// ``` +pub fn foople() {} + +/// Flomble the florp +/// ``` +/// t::florp(); +/// ``` +pub fn florp() {} From 976aea34eebd7f3453bfbe3380517f5831829684 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 28 Jun 2023 06:12:19 +0200 Subject: [PATCH 002/169] we are migrating to askama --- src/librustdoc/html/templates/STYLE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md index 0281b1c47f8c..c573d9752adb 100644 --- a/src/librustdoc/html/templates/STYLE.md +++ b/src/librustdoc/html/templates/STYLE.md @@ -32,7 +32,7 @@ Askama templates support quite sophisticated control flow. To keep our templates simple and understandable, we use only a subset: `if` and `for`. In particular we avoid [assignments in the template logic][assignments] and [Askama macros][macros]. This also may make things easier if we switch to a different -Jinja-style template system, like Askama, in the future. +Jinja-style template system in future. [assignments]: https://djc.github.io/askama/template_syntax.html#assignments [macros]: https://djc.github.io/askama/template_syntax.html#macros From 545cd1bd5bcb62fb70e0e8e12076478cb41bdc8b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 28 Jun 2023 18:34:35 +0200 Subject: [PATCH 003/169] accept review suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dániel Buga --- src/librustdoc/html/templates/STYLE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md index c573d9752adb..38aac2a60e94 100644 --- a/src/librustdoc/html/templates/STYLE.md +++ b/src/librustdoc/html/templates/STYLE.md @@ -32,7 +32,7 @@ Askama templates support quite sophisticated control flow. To keep our templates simple and understandable, we use only a subset: `if` and `for`. In particular we avoid [assignments in the template logic][assignments] and [Askama macros][macros]. This also may make things easier if we switch to a different -Jinja-style template system in future. +Jinja-style template system in the future. [assignments]: https://djc.github.io/askama/template_syntax.html#assignments [macros]: https://djc.github.io/askama/template_syntax.html#macros From 10ef96f6a5e71746968417892feeddd0a099774d Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sat, 10 Jun 2023 18:54:46 +0200 Subject: [PATCH 004/169] add macro test cases to extra arguments test --- .../argument-suggestions/extra_arguments.rs | 18 ++- .../extra_arguments.stderr | 111 +++++++++++++++--- 2 files changed, 108 insertions(+), 21 deletions(-) diff --git a/tests/ui/argument-suggestions/extra_arguments.rs b/tests/ui/argument-suggestions/extra_arguments.rs index 1442062326d1..0831d737a8f7 100644 --- a/tests/ui/argument-suggestions/extra_arguments.rs +++ b/tests/ui/argument-suggestions/extra_arguments.rs @@ -4,9 +4,15 @@ fn two_arg_same(_a: i32, _b: i32) {} fn two_arg_diff(_a: i32, _b: &str) {} macro_rules! foo { - ($x:expr) => { + ($x:expr, ~) => { empty($x, 1); //~ ERROR function takes - } + }; + ($x:expr, $y:expr) => { + empty($x, $y); //~ ERROR function takes + }; + (~, $y:expr) => { + empty(1, $y); //~ ERROR function takes + }; } fn main() { @@ -39,5 +45,11 @@ fn main() { 1, "" ); - foo!(1); + + // Check with macro expansions + foo!(1, ~); + foo!(~, 1); + foo!(1, 1); + one_arg(1, panic!()); //~ ERROR function takes + one_arg(panic!(), 1); //~ ERROR function takes } diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index 11c710997435..a32101e2518c 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -1,5 +1,5 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/extra_arguments.rs:13:3 + --> $DIR/extra_arguments.rs:19:3 | LL | empty(""); | ^^^^^ -- @@ -14,7 +14,7 @@ LL | fn empty() {} | ^^^^^ error[E0061]: this function takes 0 arguments but 2 arguments were supplied - --> $DIR/extra_arguments.rs:14:3 + --> $DIR/extra_arguments.rs:20:3 | LL | empty(1, 1); | ^^^^^ - - unexpected argument of type `{integer}` @@ -33,7 +33,7 @@ LL + empty(); | error[E0061]: this function takes 1 argument but 2 arguments were supplied - --> $DIR/extra_arguments.rs:16:3 + --> $DIR/extra_arguments.rs:22:3 | LL | one_arg(1, 1); | ^^^^^^^ --- @@ -48,7 +48,7 @@ LL | fn one_arg(_a: i32) {} | ^^^^^^^ ------- error[E0061]: this function takes 1 argument but 2 arguments were supplied - --> $DIR/extra_arguments.rs:17:3 + --> $DIR/extra_arguments.rs:23:3 | LL | one_arg(1, ""); | ^^^^^^^ ---- @@ -63,7 +63,7 @@ LL | fn one_arg(_a: i32) {} | ^^^^^^^ ------- error[E0061]: this function takes 1 argument but 3 arguments were supplied - --> $DIR/extra_arguments.rs:18:3 + --> $DIR/extra_arguments.rs:24:3 | LL | one_arg(1, "", 1.0); | ^^^^^^^ -- --- unexpected argument of type `{float}` @@ -82,7 +82,7 @@ LL + one_arg(1); | error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:20:3 + --> $DIR/extra_arguments.rs:26:3 | LL | two_arg_same(1, 1, 1); | ^^^^^^^^^^^^ --- @@ -97,7 +97,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} | ^^^^^^^^^^^^ ------- ------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:21:3 + --> $DIR/extra_arguments.rs:27:3 | LL | two_arg_same(1, 1, 1.0); | ^^^^^^^^^^^^ ----- @@ -112,7 +112,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} | ^^^^^^^^^^^^ ------- ------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:23:3 + --> $DIR/extra_arguments.rs:29:3 | LL | two_arg_diff(1, 1, ""); | ^^^^^^^^^^^^ --- @@ -127,7 +127,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} | ^^^^^^^^^^^^ ------- -------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:24:3 + --> $DIR/extra_arguments.rs:30:3 | LL | two_arg_diff(1, "", ""); | ^^^^^^^^^^^^ ---- @@ -142,7 +142,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} | ^^^^^^^^^^^^ ------- -------- error[E0061]: this function takes 2 arguments but 4 arguments were supplied - --> $DIR/extra_arguments.rs:25:3 + --> $DIR/extra_arguments.rs:31:3 | LL | two_arg_diff(1, 1, "", ""); | ^^^^^^^^^^^^ - -- unexpected argument of type `&'static str` @@ -161,7 +161,7 @@ LL + two_arg_diff(1, ""); | error[E0061]: this function takes 2 arguments but 4 arguments were supplied - --> $DIR/extra_arguments.rs:26:3 + --> $DIR/extra_arguments.rs:32:3 | LL | two_arg_diff(1, "", 1, ""); | ^^^^^^^^^^^^ - -- unexpected argument of type `&'static str` @@ -180,7 +180,7 @@ LL + two_arg_diff(1, ""); | error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:29:3 + --> $DIR/extra_arguments.rs:35:3 | LL | two_arg_same(1, 1, ""); | ^^^^^^^^^^^^ -------- @@ -195,7 +195,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} | ^^^^^^^^^^^^ ------- ------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:30:3 + --> $DIR/extra_arguments.rs:36:3 | LL | two_arg_diff(1, 1, ""); | ^^^^^^^^^^^^ --- @@ -210,7 +210,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} | ^^^^^^^^^^^^ ------- -------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:31:3 + --> $DIR/extra_arguments.rs:37:3 | LL | two_arg_same( | ^^^^^^^^^^^^ @@ -230,7 +230,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} | ^^^^^^^^^^^^ ------- ------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> $DIR/extra_arguments.rs:37:3 + --> $DIR/extra_arguments.rs:43:3 | LL | two_arg_diff( | ^^^^^^^^^^^^ @@ -254,8 +254,8 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied LL | empty($x, 1); | ^^^^^ - unexpected argument of type `{integer}` ... -LL | foo!(1); - | ------- +LL | foo!(1, ~); + | ---------- | | | | | unexpected argument of type `{integer}` | | help: remove the extra argument @@ -268,6 +268,81 @@ LL | fn empty() {} | ^^^^^ = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 16 previous errors +error[E0061]: this function takes 0 arguments but 2 arguments were supplied + --> $DIR/extra_arguments.rs:14:9 + | +LL | empty(1, $y); + | ^^^^^ ----- help: remove the extra argument + | | + | unexpected argument of type `{integer}` +... +LL | foo!(~, 1); + | ---------- + | | | + | | unexpected argument of type `{integer}` + | in this macro invocation + | +note: function defined here + --> $DIR/extra_arguments.rs:1:4 + | +LL | fn empty() {} + | ^^^^^ + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0061]: this function takes 0 arguments but 2 arguments were supplied + --> $DIR/extra_arguments.rs:11:9 + | +LL | empty($x, $y); + | ^^^^^ +... +LL | foo!(1, 1); + | ---------- + | | | | + | | | unexpected argument of type `{integer}` + | | unexpected argument of type `{integer}` + | in this macro invocation + | +note: function defined here + --> $DIR/extra_arguments.rs:1:4 + | +LL | fn empty() {} + | ^^^^^ + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the extra arguments + | +LL ~ empty($x, $y; +LL | }; + ... +LL | foo!(~, 1); +LL ~ foo!(, 1); + | + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/extra_arguments.rs:53:3 + | +LL | one_arg(1, panic!()); + | ^^^^^^^ -------- unexpected argument + | +note: function defined here + --> $DIR/extra_arguments.rs:2:4 + | +LL | fn one_arg(_a: i32) {} + | ^^^^^^^ ------- + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/extra_arguments.rs:54:3 + | +LL | one_arg(panic!(), 1); + | ^^^^^^^ - - unexpected argument of type `{integer}` + | | + | help: remove the extra argument + | +note: function defined here + --> $DIR/extra_arguments.rs:2:4 + | +LL | fn one_arg(_a: i32) {} + | ^^^^^^^ ------- + +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0061`. From 3694fd08e6e9d0828369ac1c9ee205cd0de71287 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sat, 10 Jun 2023 19:13:42 +0200 Subject: [PATCH 005/169] introduce `Span::find_ancestor_inside_same_ctxt` and use it for function argument diagnostics --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 33 +++++++++-------- compiler/rustc_span/src/lib.rs | 37 +++++++++++++++++-- .../extra_arguments.stderr | 10 +++-- tests/ui/issues/issue-48364.stderr | 1 - 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e102c51c7eec..8e49aa3e656d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -519,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // suggestions and labels are (more) correct when an arg is a // macro invocation. let normalize_span = |span: Span| -> Span { - let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span); + let normalized_span = span.find_ancestor_inside_same_ctxt(error_span).unwrap_or(span); // Sometimes macros mess up the spans, so do not normalize the // arg span to equal the error span, because that's less useful // than pointing out the arg expr in the wrong context. @@ -1220,22 +1220,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(suggestion_text) = suggestion_text { let source_map = self.sess().source_map(); - let (mut suggestion, suggestion_span) = - if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) { - ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) - } else { - ( - format!( - "{}(", - source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { - fn_def_id.map_or("".to_string(), |fn_def_id| { - tcx.item_name(fn_def_id).to_string() - }) + let (mut suggestion, suggestion_span) = if let Some(call_span) = + full_call_span.find_ancestor_inside_same_ctxt(error_span) + { + ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) + } else { + ( + format!( + "{}(", + source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { + fn_def_id.map_or("".to_string(), |fn_def_id| { + tcx.item_name(fn_def_id).to_string() }) - ), - error_span, - ) - }; + }) + ), + error_span, + ) + }; let mut needs_comma = false; for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { if needs_comma { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ecaa82874a3c..02a5d6966a74 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -685,6 +685,12 @@ impl Span { } /// Walk down the expansion ancestors to find a span that's contained within `outer`. + /// + /// The span returned by this method may have a different [`SyntaxContext`] as `outer`. + /// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead, + /// because joining spans with different syntax contexts can create unexpected results. + /// + /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt pub fn find_ancestor_inside(mut self, outer: Span) -> Option { while !outer.contains(self) { self = self.parent_callsite()?; @@ -692,11 +698,34 @@ impl Span { Some(self) } - /// Like `find_ancestor_inside`, but specifically for when spans might not - /// overlaps. Take care when using this, and prefer `find_ancestor_inside` - /// when you know that the spans are nested (modulo macro expansion). + /// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as + /// `other`. + /// + /// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not + /// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or + /// [`find_ancestor_inside_same_ctxt`] when you know that the spans are nested (modulo + /// macro expansion). + /// + /// [`find_ancestor_inside`]: Self::find_ancestor_inside + /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option { - while !Span::eq_ctxt(self, other) { + while !self.eq_ctxt(other) { + self = self.parent_callsite()?; + } + Some(self) + } + + /// Walk down the expansion ancestors to find a span that's contained within `outer` and + /// has the same [`SyntaxContext`] as `outer`. + /// + /// This method is the combination of [`find_ancestor_inside`] and + /// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span. + /// If you do not need to modify the span, use [`find_ancestor_inside`] instead. + /// + /// [`find_ancestor_inside`]: Self::find_ancestor_inside + /// [`find_ancestor_in_same_ctxt`]: Self::find_ancestor_in_same_ctxt + pub fn find_ancestor_inside_same_ctxt(mut self, outer: Span) -> Option { + while !outer.contains(self) || !self.eq_ctxt(outer) { self = self.parent_callsite()?; } Some(self) diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index a32101e2518c..1016c7ba4381 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -321,7 +321,10 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:53:3 | LL | one_arg(1, panic!()); - | ^^^^^^^ -------- unexpected argument + | ^^^^^^^ ---------- + | | | + | | unexpected argument + | help: remove the extra argument | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -333,8 +336,9 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:54:3 | LL | one_arg(panic!(), 1); - | ^^^^^^^ - - unexpected argument of type `{integer}` - | | + | ^^^^^^^ --- + | | | + | | unexpected argument of type `{integer}` | help: remove the extra argument | note: function defined here diff --git a/tests/ui/issues/issue-48364.stderr b/tests/ui/issues/issue-48364.stderr index cac4af6a7f3c..3f2e1b83ad57 100644 --- a/tests/ui/issues/issue-48364.stderr +++ b/tests/ui/issues/issue-48364.stderr @@ -10,7 +10,6 @@ LL | b"".starts_with(stringify!(foo)) found reference `&'static str` note: method defined here --> $SRC_DIR/core/src/slice/mod.rs:LL:COL - = note: this error originates in the macro `stringify` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error From 37d62fbf9e5bd2010896a28d6b363bd85cbecb33 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sat, 10 Jun 2023 19:23:40 +0200 Subject: [PATCH 006/169] don't remove args for function calls coming from macro expansions --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 +++- .../ui/argument-suggestions/extra_arguments.stderr | 13 +------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 8e49aa3e656d..15bb67db6e98 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -929,7 +929,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; labels.push((provided_span, format!("unexpected argument{provided_ty_name}"))); let mut span = provided_span; - if span.can_be_used_for_suggestions() { + if span.can_be_used_for_suggestions() + && error_span.can_be_used_for_suggestions() + { if arg_idx.index() > 0 && let Some((_, prev)) = provided_arg_tys .get(ProvidedIdx::from_usize(arg_idx.index() - 1) diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index 1016c7ba4381..bd32780c88f9 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -258,7 +258,6 @@ LL | foo!(1, ~); | ---------- | | | | | unexpected argument of type `{integer}` - | | help: remove the extra argument | in this macro invocation | note: function defined here @@ -272,9 +271,7 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/extra_arguments.rs:14:9 | LL | empty(1, $y); - | ^^^^^ ----- help: remove the extra argument - | | - | unexpected argument of type `{integer}` + | ^^^^^ - unexpected argument of type `{integer}` ... LL | foo!(~, 1); | ---------- @@ -308,14 +305,6 @@ note: function defined here LL | fn empty() {} | ^^^^^ = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -help: remove the extra arguments - | -LL ~ empty($x, $y; -LL | }; - ... -LL | foo!(~, 1); -LL ~ foo!(, 1); - | error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:53:3 From 985036b5a125ceb66e4a96bedf65a9fd69a9baad Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 30 Jul 2023 19:19:43 +0200 Subject: [PATCH 007/169] add more tests for argument removal with wacky spans --- .../argument-suggestions/extra_arguments.rs | 8 ++- .../extra_arguments.stderr | 52 +++++++++++++++---- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/tests/ui/argument-suggestions/extra_arguments.rs b/tests/ui/argument-suggestions/extra_arguments.rs index 0831d737a8f7..4f2f3517ddd7 100644 --- a/tests/ui/argument-suggestions/extra_arguments.rs +++ b/tests/ui/argument-suggestions/extra_arguments.rs @@ -1,5 +1,5 @@ fn empty() {} -fn one_arg(_a: i32) {} +fn one_arg(_a: T) {} fn two_arg_same(_a: i32, _b: i32) {} fn two_arg_diff(_a: i32, _b: &str) {} @@ -52,4 +52,10 @@ fn main() { foo!(1, 1); one_arg(1, panic!()); //~ ERROR function takes one_arg(panic!(), 1); //~ ERROR function takes + one_arg(stringify!($e), 1); //~ ERROR function takes + + // Not a macro, but this also has multiple spans with equal source code, + // but different expansion contexts. + // https://github.com/rust-lang/rust/issues/114255 + one_arg(for _ in 1.. {}, 1); //~ ERROR function takes } diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index bd32780c88f9..5ad8e35920a1 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -44,8 +44,8 @@ LL | one_arg(1, 1); note: function defined here --> $DIR/extra_arguments.rs:2:4 | -LL | fn one_arg(_a: i32) {} - | ^^^^^^^ ------- +LL | fn one_arg(_a: T) {} + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:23:3 @@ -59,8 +59,8 @@ LL | one_arg(1, ""); note: function defined here --> $DIR/extra_arguments.rs:2:4 | -LL | fn one_arg(_a: i32) {} - | ^^^^^^^ ------- +LL | fn one_arg(_a: T) {} + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:24:3 @@ -73,8 +73,8 @@ LL | one_arg(1, "", 1.0); note: function defined here --> $DIR/extra_arguments.rs:2:4 | -LL | fn one_arg(_a: i32) {} - | ^^^^^^^ ------- +LL | fn one_arg(_a: T) {} + | ^^^^^^^ ----- help: remove the extra arguments | LL - one_arg(1, "", 1.0); @@ -318,8 +318,8 @@ LL | one_arg(1, panic!()); note: function defined here --> $DIR/extra_arguments.rs:2:4 | -LL | fn one_arg(_a: i32) {} - | ^^^^^^^ ------- +LL | fn one_arg(_a: T) {} + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:54:3 @@ -333,9 +333,39 @@ LL | one_arg(panic!(), 1); note: function defined here --> $DIR/extra_arguments.rs:2:4 | -LL | fn one_arg(_a: i32) {} - | ^^^^^^^ ------- +LL | fn one_arg(_a: T) {} + | ^^^^^^^ ----- -error: aborting due to 20 previous errors +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/extra_arguments.rs:55:3 + | +LL | one_arg(stringify!($e), 1); + | ^^^^^^^ --- + | | | + | | unexpected argument of type `{integer}` + | help: remove the extra argument + | +note: function defined here + --> $DIR/extra_arguments.rs:2:4 + | +LL | fn one_arg(_a: T) {} + | ^^^^^^^ ----- + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/extra_arguments.rs:60:3 + | +LL | one_arg(for _ in 1.. {}, 1); + | ^^^^^^^ --- + | | | + | | unexpected argument of type `{integer}` + | help: remove the extra argument + | +note: function defined here + --> $DIR/extra_arguments.rs:2:4 + | +LL | fn one_arg(_a: T) {} + | ^^^^^^^ ----- + +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0061`. From 7c6bbdbd95873c8f9b7873be1da462f11391324f Mon Sep 17 00:00:00 2001 From: kadiwa Date: Sat, 15 Jul 2023 09:47:49 +0200 Subject: [PATCH 008/169] unstable book: update lang_items page and split it --- .../src/error_codes/E0132.md | 2 +- .../src/error_codes/E0152.md | 4 +- .../src/language-features/lang-items.md | 311 ++++-------------- .../src/language-features/start.md | 59 ++++ 4 files changed, 121 insertions(+), 255 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/start.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md index a23cc988bdb6..51258739b89c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0132.md +++ b/compiler/rustc_error_codes/src/error_codes/E0132.md @@ -13,7 +13,7 @@ It is not possible to declare type parameters on a function that has the `start` attribute. Such a function must have the following type signature (for more information, view [the unstable book][1]): -[1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib +[1]: https://doc.rust-lang.org/unstable-book/language-features/start.html ``` # let _: diff --git a/compiler/rustc_error_codes/src/error_codes/E0152.md b/compiler/rustc_error_codes/src/error_codes/E0152.md index ef17b8b4c75c..d862766571df 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0152.md +++ b/compiler/rustc_error_codes/src/error_codes/E0152.md @@ -20,6 +20,6 @@ attributes: #![no_std] ``` -See also the [unstable book][1]. +See also [this section of the Rustonomicon][beneath std]. -[1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib +[beneath std]: https://doc.rust-lang.org/nomicon/beneath-std.html diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 1f3d472c3aa8..9e20662fff37 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -9,26 +9,60 @@ functionality that isn't hard-coded into the language, but is implemented in libraries, with a special marker to tell the compiler it exists. The marker is the attribute `#[lang = "..."]` and there are various different values of `...`, i.e. various different 'lang -items'. +items'. Most of them can only be defined once. -For example, `Box` pointers require a lang item for allocation. -A freestanding program that uses the `Box` -sugar for dynamic allocations via `malloc` and `free`: +Lang items are loaded lazily by the compiler; e.g. if one never uses `Box` +then there is no need to define a function for `exchange_malloc`. +`rustc` will emit an error when an item is needed but not found in the current +crate or any that it depends on. + +Some features provided by lang items: + +- overloadable operators via traits: the traits corresponding to the + `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all + marked with lang items; those specific four are `eq`, `partial_ord`, + `deref`/`deref_mut`, and `add` respectively. +- panicking: the `panic` and `panic_impl` lang items, among others. +- stack unwinding: the lang item `eh_personality` is a function used by the + failure mechanisms of the compiler. This is often mapped to GCC's personality + function (see the [`std` implementation][personality] for more information), + but programs which don't trigger a panic can be assured that this function is + never called. Additionally, a `eh_catch_typeinfo` static is needed for certain + targets which implement Rust panics on top of C++ exceptions. +- the traits in `core::marker` used to indicate types of + various kinds; e.g. lang items `sized`, `sync` and `copy`. +- memory allocation, see below. + +Most lang items are defined by `core`, but if you're trying to build +an executable without the `std` crate, you might run into the need +for lang item definitions. + +[personality]: https://github.com/rust-lang/rust/blob/master/library/std/src/personality/gcc.rs + +## Example: Implementing a `Box` + +`Box` pointers require two lang items: one for the type itself and one for +allocation. A freestanding program that uses the `Box` sugar for dynamic +allocations via `malloc` and `free`: ```rust,ignore (libc-is-finicky) -#![feature(lang_items, start, libc, core_intrinsics, rustc_private, rustc_attrs)] +#![feature(lang_items, start, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)] #![allow(internal_features)] #![no_std] + +extern crate libc; +extern crate unwind; + +use core::ffi::c_void; use core::intrinsics; use core::panic::PanicInfo; use core::ptr::NonNull; -extern crate libc; - +pub struct Global; // the global allocator struct Unique(NonNull); #[lang = "owned_box"] -pub struct Box(Unique); +pub struct Box(Unique, A); impl Box { pub fn new(x: T) -> Self { @@ -37,24 +71,26 @@ impl Box { } } +impl Drop for Box { + fn drop(&mut self) { + unsafe { + libc::free(self.0.0.as_ptr() as *mut c_void); + } + } +} + #[lang = "exchange_malloc"] unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - let p = libc::malloc(size as libc::size_t) as *mut u8; + let p = libc::malloc(size) as *mut u8; // Check if `malloc` failed: - if p as usize == 0 { + if p.is_null() { intrinsics::abort(); } p } -impl Drop for Box { - fn drop(&mut self) { - libc::free(self.0.0.0 as *mut libc::c_void) - } -} - #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { let _x = Box::new(1); @@ -62,247 +98,18 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } -#[lang = "eh_personality"] extern fn rust_eh_personality() {} -#[lang = "panic_impl"] extern fn rust_begin_panic(_info: &PanicInfo) -> ! { intrinsics::abort() } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} +#[lang = "eh_personality"] +fn rust_eh_personality() {} + +#[panic_handler] +fn panic_handler(_info: &PanicInfo) -> ! { intrinsics::abort() } ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to return a valid pointer, and so needs to do the check internally. -Other features provided by lang items include: - -- overloadable operators via traits: the traits corresponding to the - `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all - marked with lang items; those specific four are `eq`, `ord`, - `deref`, and `add` respectively. -- stack unwinding and general failure; the `eh_personality`, - `panic` and `panic_bounds_check` lang items. -- the traits in `std::marker` used to indicate types of - various kinds; lang items `send`, `sync` and `copy`. -- the marker types and variance indicators found in - `std::marker`; lang items `covariant_type`, - `contravariant_lifetime`, etc. - -Lang items are loaded lazily by the compiler; e.g. if one never uses -`Box` then there is no need to define a function for `exchange_malloc`. -`rustc` will emit an error when an item is needed -but not found in the current crate or any that it depends on. - -Most lang items are defined by `libcore`, but if you're trying to build -an executable without the standard library, you'll run into the need -for lang items. The rest of this page focuses on this use-case, even though -lang items are a bit broader than that. - -### Using libc - -In order to build a `#[no_std]` executable we will need libc as a dependency. -We can specify this using our `Cargo.toml` file: - -```toml -[dependencies] -libc = { version = "0.2.14", default-features = false } -``` - -Note that the default features have been disabled. This is a critical step - -**the default features of libc include the standard library and so must be -disabled.** - -### Writing an executable without stdlib - -Controlling the entry point is possible in two ways: the `#[start]` attribute, -or overriding the default shim for the C `main` function with your own. - -The function marked `#[start]` is passed the command line parameters -in the same format as C: - -```rust,ignore (libc-is-finicky) -#![feature(lang_items, core_intrinsics, rustc_private)] -#![feature(start)] -#![allow(internal_features)] -#![no_std] -use core::intrinsics; -use core::panic::PanicInfo; - -// Pull in the system libc library for what crt0.o likely requires. -extern crate libc; - -// Entry point for this program. -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} - -// These functions are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "eh_personality"] -#[no_mangle] -pub extern fn rust_eh_personality() { -} - -#[lang = "panic_impl"] -#[no_mangle] -pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { - unsafe { intrinsics::abort() } -} -``` - -To override the compiler-inserted `main` shim, one has to disable it -with `#![no_main]` and then create the appropriate symbol with the -correct ABI and the correct name, which requires overriding the -compiler's name mangling too: - -```rust,ignore (libc-is-finicky) -#![feature(lang_items, core_intrinsics, rustc_private)] -#![feature(start)] -#![allow(internal_features)] -#![no_std] -#![no_main] -use core::intrinsics; -use core::panic::PanicInfo; - -// Pull in the system libc library for what crt0.o likely requires. -extern crate libc; - -// Entry point for this program. -#[no_mangle] // ensure that this symbol is called `main` in the output -pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 { - 0 -} - -// These functions are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "eh_personality"] -#[no_mangle] -pub extern fn rust_eh_personality() { -} - -#[lang = "panic_impl"] -#[no_mangle] -pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { - unsafe { intrinsics::abort() } -} -``` - -In many cases, you may need to manually link to the `compiler_builtins` crate -when building a `no_std` binary. You may observe this via linker error messages -such as "```undefined reference to `__rust_probestack'```". - -## More about the language items - -The compiler currently makes a few assumptions about symbols which are -available in the executable to call. Normally these functions are provided by -the standard library, but without it you must define your own. These symbols -are called "language items", and they each have an internal name, and then a -signature that an implementation must conform to. - -The first of these functions, `rust_eh_personality`, is used by the failure -mechanisms of the compiler. This is often mapped to GCC's personality function -(see the [libstd implementation][unwind] for more information), but crates -which do not trigger a panic can be assured that this function is never -called. The language item's name is `eh_personality`. - -[unwind]: https://github.com/rust-lang/rust/blob/master/library/panic_unwind/src/gcc.rs - -The second function, `rust_begin_panic`, is also used by the failure mechanisms of the -compiler. When a panic happens, this controls the message that's displayed on -the screen. While the language item's name is `panic_impl`, the symbol name is -`rust_begin_panic`. - -Finally, a `eh_catch_typeinfo` static is needed for certain targets which -implement Rust panics on top of C++ exceptions. - ## List of all language items -This is a list of all language items in Rust along with where they are located in -the source code. +An up-to-date list of all language items can be found [here] in the compiler code. -- Primitives - - `i8`: `libcore/num/mod.rs` - - `i16`: `libcore/num/mod.rs` - - `i32`: `libcore/num/mod.rs` - - `i64`: `libcore/num/mod.rs` - - `i128`: `libcore/num/mod.rs` - - `isize`: `libcore/num/mod.rs` - - `u8`: `libcore/num/mod.rs` - - `u16`: `libcore/num/mod.rs` - - `u32`: `libcore/num/mod.rs` - - `u64`: `libcore/num/mod.rs` - - `u128`: `libcore/num/mod.rs` - - `usize`: `libcore/num/mod.rs` - - `f32`: `libstd/f32.rs` - - `f64`: `libstd/f64.rs` - - `char`: `libcore/char.rs` - - `slice`: `liballoc/slice.rs` - - `str`: `liballoc/str.rs` - - `const_ptr`: `libcore/ptr.rs` - - `mut_ptr`: `libcore/ptr.rs` - - `unsafe_cell`: `libcore/cell.rs` -- Runtime - - `start`: `libstd/rt.rs` - - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC) - - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU) - - `eh_personality`: `libpanic_unwind/seh.rs` (SEH) - - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC) - - `panic`: `libcore/panicking.rs` - - `panic_bounds_check`: `libcore/panicking.rs` - - `panic_impl`: `libcore/panicking.rs` - - `panic_impl`: `libstd/panicking.rs` -- Allocations - - `owned_box`: `liballoc/boxed.rs` - - `exchange_malloc`: `liballoc/heap.rs` -- Operands - - `not`: `libcore/ops/bit.rs` - - `bitand`: `libcore/ops/bit.rs` - - `bitor`: `libcore/ops/bit.rs` - - `bitxor`: `libcore/ops/bit.rs` - - `shl`: `libcore/ops/bit.rs` - - `shr`: `libcore/ops/bit.rs` - - `bitand_assign`: `libcore/ops/bit.rs` - - `bitor_assign`: `libcore/ops/bit.rs` - - `bitxor_assign`: `libcore/ops/bit.rs` - - `shl_assign`: `libcore/ops/bit.rs` - - `shr_assign`: `libcore/ops/bit.rs` - - `deref`: `libcore/ops/deref.rs` - - `deref_mut`: `libcore/ops/deref.rs` - - `index`: `libcore/ops/index.rs` - - `index_mut`: `libcore/ops/index.rs` - - `add`: `libcore/ops/arith.rs` - - `sub`: `libcore/ops/arith.rs` - - `mul`: `libcore/ops/arith.rs` - - `div`: `libcore/ops/arith.rs` - - `rem`: `libcore/ops/arith.rs` - - `neg`: `libcore/ops/arith.rs` - - `add_assign`: `libcore/ops/arith.rs` - - `sub_assign`: `libcore/ops/arith.rs` - - `mul_assign`: `libcore/ops/arith.rs` - - `div_assign`: `libcore/ops/arith.rs` - - `rem_assign`: `libcore/ops/arith.rs` - - `eq`: `libcore/cmp.rs` - - `ord`: `libcore/cmp.rs` -- Functions - - `fn`: `libcore/ops/function.rs` - - `fn_mut`: `libcore/ops/function.rs` - - `fn_once`: `libcore/ops/function.rs` - - `generator_state`: `libcore/ops/generator.rs` - - `generator`: `libcore/ops/generator.rs` -- Other - - `coerce_unsized`: `libcore/ops/unsize.rs` - - `drop`: `libcore/ops/drop.rs` - - `drop_in_place`: `libcore/ptr.rs` - - `clone`: `libcore/clone.rs` - - `copy`: `libcore/marker.rs` - - `send`: `libcore/marker.rs` - - `sized`: `libcore/marker.rs` - - `unsize`: `libcore/marker.rs` - - `sync`: `libcore/marker.rs` - - `phantom_data`: `libcore/marker.rs` - - `discriminant_kind`: `libcore/marker.rs` - - `freeze`: `libcore/marker.rs` - - `debug_trait`: `libcore/fmt/mod.rs` - - `non_zero`: `libcore/nonzero.rs` - - `arc`: `liballoc/sync.rs` - - `rc`: `liballoc/rc.rs` +[here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir/src/lang_items.rs diff --git a/src/doc/unstable-book/src/language-features/start.md b/src/doc/unstable-book/src/language-features/start.md new file mode 100644 index 000000000000..09e4875a2e4f --- /dev/null +++ b/src/doc/unstable-book/src/language-features/start.md @@ -0,0 +1,59 @@ +# `start` + +The tracking issue for this feature is: [#29633] + +[#29633]: https://github.com/rust-lang/rust/issues/29633 + +------------------------ + +Allows you to mark a function as the entry point of the executable, which is +necessary in `#![no_std]` environments. + +The function marked `#[start]` is passed the command line parameters in the same +format as the C main function (aside from the integer types being used). +It has to be non-generic and have the following signature: + +```rust,ignore (only-for-syntax-highlight) +# let _: +fn(isize, *const *const u8) -> isize +# ; +``` + +This feature should not be confused with the `start` *lang item* which is +defined by the `std` crate and is written `#[lang = "start"]`. + +## Usage together with the `std` crate + +`#[start]` can be used in combination with the `std` crate, in which case the +normal `main` function (which would get called from the `std` crate) won't be +used as an entry point. +The initialization code in `std` will be skipped this way. + +Example: + +```rust +#![feature(start)] + +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +``` + +Unwinding the stack past the `#[start]` function is currently considered +Undefined Behavior (for any unwinding implementation): + +```rust,ignore (UB) +#![feature(start)] + +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + std::panic::catch_unwind(|| { + panic!(); // panic safely gets caught or safely aborts execution + }); + + panic!(); // UB! + + 0 +} +``` From 0d99f1d09f48c5894defe25f9425483b3a84388d Mon Sep 17 00:00:00 2001 From: kadiwa Date: Fri, 4 Aug 2023 18:09:57 +0200 Subject: [PATCH 009/169] update rust book --- src/doc/book | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book b/src/doc/book index 668c64760b5c..72187f5cd0be 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 668c64760b5c7ea654facb4ba5fe9faddfda27cc +Subproject commit 72187f5cd0beaaa9c6f584156bcd88f921871e83 From 4e2a9b6b6ee7b9fead19931f1e0ae3cd5d2add98 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 6 Aug 2023 10:31:02 +0000 Subject: [PATCH 010/169] Do not mark shallow_lint_levels_on as eval_always. --- compiler/rustc_middle/src/query/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 35fe6ab99fb9..88e32e9f3a76 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -388,7 +388,6 @@ rustc_queries! { } query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap { - eval_always // fetches `resolutions` arena_cache desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key) } } From fd9fcc580a40bdf398576199c5e8c3ebe12de9c6 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 7 Aug 2023 19:13:34 +0200 Subject: [PATCH 011/169] std: synchronize with all calls to `unpark` in id-based thread parker --- library/std/src/sys_common/thread_parking/id.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys_common/thread_parking/id.rs b/library/std/src/sys_common/thread_parking/id.rs index 15042fc3beec..046674396603 100644 --- a/library/std/src/sys_common/thread_parking/id.rs +++ b/library/std/src/sys_common/thread_parking/id.rs @@ -56,18 +56,14 @@ impl Parker { self.init_tid(); // Changes NOTIFIED to EMPTY and EMPTY to PARKED. - let mut state = self.state.fetch_sub(1, Acquire).wrapping_sub(1); - if state == PARKED { + let state = self.state.fetch_sub(1, Acquire); + if state == EMPTY { // Loop to guard against spurious wakeups. - while state == PARKED { + // The state must be reset with acquire ordering to ensure that all + // calls to `unpark` synchronize with this thread. + while self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed).is_err() { park(self.state.as_ptr().addr()); - state = self.state.load(Acquire); } - - // Since the state change has already been observed with acquire - // ordering, the state can be reset with a relaxed store instead - // of a swap. - self.state.store(EMPTY, Relaxed); } } @@ -78,8 +74,7 @@ impl Parker { if state == PARKED { park_timeout(dur, self.state.as_ptr().addr()); // Swap to ensure that we observe all state changes with acquire - // ordering, even if the state has been changed after the timeout - // occurred. + // ordering. self.state.swap(EMPTY, Acquire); } } From 98e434a01eafce54fc862fa36f44e0392a6fb9f7 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:29:50 -0600 Subject: [PATCH 012/169] Increase clarity about Hash - Eq consistency in HashMap and HashSet docs --- library/std/src/collections/hash/map.rs | 6 ++++-- library/std/src/collections/hash/set.rs | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index a083b65604d4..be173a7ace6d 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -49,12 +49,14 @@ use crate::sys; /// ``` /// /// In other words, if two keys are equal, their hashes must be equal. +/// Violating this property is a logic error. /// -/// It is a logic error for a key to be modified in such a way that the key's +/// It is also a logic error for a key to be modified in such a way that the key's /// hash, as determined by the [`Hash`] trait, or its equality, as determined by /// the [`Eq`] trait, changes while it is in the map. This is normally only /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. -/// The behavior resulting from such a logic error is not specified, but will +/// +/// The behavior resulting from either logic error is not specified, but will /// be encapsulated to the `HashMap` that observed the logic error and not /// result in undefined behavior. This could include panics, incorrect results, /// aborts, memory leaks, and non-termination. diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 959403e16447..6d85b26af5fa 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -24,13 +24,14 @@ use super::map::{map_try_reserve_error, RandomState}; /// ``` /// /// In other words, if two keys are equal, their hashes must be equal. +/// Violating this property is a logic error. /// -/// -/// It is a logic error for a key to be modified in such a way that the key's +/// It is also a logic error for a key to be modified in such a way that the key's /// hash, as determined by the [`Hash`] trait, or its equality, as determined by /// the [`Eq`] trait, changes while it is in the map. This is normally only /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. -/// The behavior resulting from such a logic error is not specified, but will +/// +/// The behavior resulting from either logic error is not specified, but will /// be encapsulated to the `HashSet` that observed the logic error and not /// result in undefined behavior. This could include panics, incorrect results, /// aborts, memory leaks, and non-termination. From 1c583c0b914eb46164f233f9ba2d0d351e64da1f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Aug 2023 14:22:34 +1000 Subject: [PATCH 013/169] Simplify the boolean logic in a closure. And rename a closure argument. --- compiler/rustc_trait_selection/src/traits/project.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 3d800421b764..4b13abb87902 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1230,12 +1230,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( }; let mut deduped: SsoHashSet<_> = Default::default(); - result.obligations.retain(|projected_obligation| { - if !deduped.insert(projected_obligation.clone()) { - return false; - } - true - }); + result.obligations.retain(|obligation| deduped.insert(obligation.clone())); if use_cache { infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); From 3c99b3dbd01389be9c6f320f179bd3fdf68913f5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Aug 2023 14:24:29 +1000 Subject: [PATCH 014/169] Size the `deduped` set appropriately. Avoids lots of resizing as the set fills up. --- compiler/rustc_trait_selection/src/traits/project.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 4b13abb87902..519b5f80d260 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1229,7 +1229,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( Normalized { value: projected_term, obligations: projected_obligations } }; - let mut deduped: SsoHashSet<_> = Default::default(); + let mut deduped = SsoHashSet::with_capacity(projected_obligations.len()); result.obligations.retain(|obligation| deduped.insert(obligation.clone())); if use_cache { From 8378487f2796571da288ac54a4696bd67c0933b8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Aug 2023 14:25:03 +1000 Subject: [PATCH 015/169] Only dedup obligation after new ones have been added. --- compiler/rustc_trait_selection/src/traits/project.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 519b5f80d260..06a1027e5dfd 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1214,7 +1214,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term); - let mut result = if projected_term.has_projections() { + let result = if projected_term.has_projections() { let mut normalizer = AssocTypeNormalizer::new( selcx, param_env, @@ -1224,14 +1224,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ); let normalized_ty = normalizer.fold(projected_term); + let mut deduped = SsoHashSet::with_capacity(projected_obligations.len()); + projected_obligations.retain(|obligation| deduped.insert(obligation.clone())); + Normalized { value: normalized_ty, obligations: projected_obligations } } else { Normalized { value: projected_term, obligations: projected_obligations } }; - let mut deduped = SsoHashSet::with_capacity(projected_obligations.len()); - result.obligations.retain(|obligation| deduped.insert(obligation.clone())); - if use_cache { infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } From 698f0e39e161cb0fdabb06ac34401ee87cfc5c9e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Aug 2023 13:41:50 +1000 Subject: [PATCH 016/169] Ignore `cause` and `recursion_depth` in `Obligation::{eq,hash}`. This gives massive (~7x) compile time and memory usage reductions for the trait system stress test in https://github.com/rust-lang/rustc-perf/pull/1680. --- compiler/rustc_infer/src/traits/mod.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index dc41630196b9..a5b2ccce85e1 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -9,6 +9,7 @@ mod structural_impls; pub mod util; use std::cmp; +use std::hash::{Hash, Hasher}; use hir::def_id::LocalDefId; use rustc_hir as hir; @@ -36,7 +37,7 @@ pub use rustc_middle::traits::*; /// either identifying an `impl` (e.g., `impl Eq for i32`) that /// satisfies the obligation, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone)] pub struct Obligation<'tcx, T> { /// The reason we have to prove this thing. pub cause: ObligationCause<'tcx>, @@ -55,6 +56,27 @@ pub struct Obligation<'tcx, T> { pub recursion_depth: usize, } +impl<'tcx, T: PartialEq> PartialEq> for Obligation<'tcx, T> { + #[inline] + fn eq(&self, other: &Obligation<'tcx, T>) -> bool { + // Ignore `cause` and `recursion_depth`. This is a small performance + // win for a few crates, and a huge performance win for the crate in + // https://github.com/rust-lang/rustc-perf/pull/1680, which greatly + // stresses the trait system. + self.param_env == other.param_env && self.predicate == other.predicate + } +} + +impl Eq for Obligation<'_, T> {} + +impl Hash for Obligation<'_, T> { + fn hash(&self, state: &mut H) -> () { + // See the comment on `Obligation::eq`. + self.param_env.hash(state); + self.predicate.hash(state); + } +} + impl<'tcx, P> From> for solve::Goal<'tcx, P> { fn from(value: Obligation<'tcx, P>) -> Self { solve::Goal { param_env: value.param_env, predicate: value.predicate } From b75351e98ee0a33dbd4dfe2b40e54e191d16dde5 Mon Sep 17 00:00:00 2001 From: danflapjax <12000932+danflapjax@users.noreply.github.com> Date: Thu, 10 Aug 2023 22:38:30 -0700 Subject: [PATCH 017/169] Optimized implementations of max, min, and clamp for bool --- library/core/src/cmp.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index faf48ae570fd..3c127efb390a 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1406,6 +1406,22 @@ mod impls { _ => unsafe { unreachable_unchecked() }, } } + + #[inline] + fn min(self, other: bool) -> bool { + self & other + } + + #[inline] + fn max(self, other: bool) -> bool { + self | other + } + + #[inline] + fn clamp(self, min: bool, max: bool) -> bool { + assert!(min <= max); + self.max(min).min(max) + } } ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } From e4cf708d2fff1ebc8aa7a21a1be152b5247206a1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 11 Aug 2023 21:27:52 +0000 Subject: [PATCH 018/169] Don't add associated type bound for non-types --- compiler/rustc_hir_analysis/messages.ftl | 3 ++ .../rustc_hir_analysis/src/astconv/bounds.rs | 29 ++++++++++++------- compiler/rustc_hir_analysis/src/errors.rs | 9 ++++++ tests/ui/associated-type-bounds/consts.rs | 10 +++++++ tests/ui/associated-type-bounds/consts.stderr | 10 +++++++ 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 tests/ui/associated-type-bounds/consts.rs create mode 100644 tests/ui/associated-type-bounds/consts.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 166760166c10..597cae6ff33c 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,6 +1,9 @@ hir_analysis_ambiguous_lifetime_bound = ambiguous lifetime bound, explicit lifetime bound required +hir_analysis_assoc_bound_on_const = expected associated type, found {$descr} + .note = trait bounds not allowed on {$descr} + hir_analysis_assoc_type_binding_not_allowed = associated type bindings are not allowed here .label = associated type not allowed here diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 30145b1a185a..ba152cd48dea 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -13,7 +13,7 @@ use crate::astconv::{ AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter, }; use crate::bounds::Bounds; -use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified}; +use crate::errors; impl<'tcx> dyn AstConv<'tcx> + '_ { /// Sets `implicitly_sized` to true on `Bounds` if necessary @@ -35,7 +35,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { if unbound.is_none() { unbound = Some(&ptr.trait_ref); } else { - tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); + tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { span }); } } } @@ -326,7 +326,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { dup_bindings .entry(assoc_item.def_id) .and_modify(|prev_span| { - tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified { + tcx.sess.emit_err(errors::ValueOfAssociatedStructAlreadySpecified { span: binding.span, prev_span: *prev_span, item_name: binding.item_name, @@ -488,6 +488,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } } + let assoc_item_def_id = projection_ty.skip_binder().def_id; + let def_kind = tcx.def_kind(assoc_item_def_id); match binding.kind { ConvertedBindingKind::Equality(..) if return_type_notation => { return Err(self.tcx().sess.emit_err( @@ -499,11 +501,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // the "projection predicate" for: // // `::Item = u32` - let assoc_item_def_id = projection_ty.skip_binder().def_id; - let def_kind = tcx.def_kind(assoc_item_def_id); match (def_kind, term.unpack()) { - (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_)) - | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (), + (DefKind::AssocTy, ty::TermKind::Ty(_)) + | (DefKind::AssocConst, ty::TermKind::Const(_)) => (), (_, _) => { let got = if let Some(_) = term.ty() { "type" } else { "constant" }; let expected = tcx.def_descr(assoc_item_def_id); @@ -516,7 +516,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { format!("{expected} defined here"), ); - if let hir::def::DefKind::AssocConst = def_kind + if let DefKind::AssocConst = def_kind && let Some(t) = term.ty() && (t.is_enum() || t.references_error()) && tcx.features().associated_const_equality { err.span_suggestion( @@ -528,8 +528,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } let reported = err.emit(); term = match def_kind { - hir::def::DefKind::AssocTy => Ty::new_error(tcx, reported).into(), - hir::def::DefKind::AssocConst => ty::Const::new_error( + DefKind::AssocTy => Ty::new_error(tcx, reported).into(), + DefKind::AssocConst => ty::Const::new_error( tcx, reported, tcx.type_of(assoc_item_def_id) @@ -548,6 +548,15 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ); } ConvertedBindingKind::Constraint(ast_bounds) => { + match def_kind { + DefKind::AssocTy => {} + _ => { + return Err(tcx.sess.emit_err(errors::AssocBoundOnConst { + span: assoc_ident.span, + descr: tcx.def_descr(assoc_item_def_id), + })); + } + } // "Desugar" a constraint like `T: Iterator` to // // `::Item: Debug` diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 0babdf7e5b3e..9471ad9ca906 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -918,3 +918,12 @@ pub struct UnusedAssociatedTypeBounds { #[suggestion(code = "")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_assoc_bound_on_const)] +#[note] +pub struct AssocBoundOnConst { + #[primary_span] + pub span: Span, + pub descr: &'static str, +} diff --git a/tests/ui/associated-type-bounds/consts.rs b/tests/ui/associated-type-bounds/consts.rs new file mode 100644 index 000000000000..9b95b1b52c05 --- /dev/null +++ b/tests/ui/associated-type-bounds/consts.rs @@ -0,0 +1,10 @@ +#![feature(associated_type_bounds)] + +pub fn accept(_: impl Trait) {} +//~^ ERROR expected associated type, found associated constant + +pub trait Trait { + const K: i32; +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/consts.stderr b/tests/ui/associated-type-bounds/consts.stderr new file mode 100644 index 000000000000..ddfb6612b081 --- /dev/null +++ b/tests/ui/associated-type-bounds/consts.stderr @@ -0,0 +1,10 @@ +error: expected associated type, found associated constant + --> $DIR/consts.rs:3:29 + | +LL | pub fn accept(_: impl Trait) {} + | ^ + | + = note: trait bounds not allowed on associated constant + +error: aborting due to previous error + From 0af9dfc0a39cfcd679d7ef33afe84a2a41cf5c3c Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Sat, 12 Aug 2023 09:20:56 +0530 Subject: [PATCH 019/169] Update Sender documentation for Sync --- library/std/src/sync/mpsc/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index c00134c8b954..f92bb1a4b1f7 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -303,12 +303,11 @@ pub struct IntoIter { rx: Receiver, } -/// The sending-half of Rust's asynchronous [`channel`] type. This half can only be -/// owned by one thread, but it can be cloned to send to other threads. +/// The sending-half of Rust's asynchronous [`channel`] type. /// /// Messages can be sent through this channel with [`send`]. /// -/// Note: all senders (the original and the clones) need to be dropped for the receiver +/// Note: all senders (the original and its clones) need to be dropped for the receiver /// to stop blocking to receive messages with [`Receiver::recv`]. /// /// [`send`]: Sender::send From b1ddd57b5c0d306c02d06fbf8c3750f1c5a16d3c Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Sun, 13 Aug 2023 20:34:36 +0800 Subject: [PATCH 020/169] Add check before suggest removing parens --- compiler/rustc_hir_typeck/src/callee.rs | 1 + tests/ui/suggestions/issue-114701.rs | 15 ++++++++ tests/ui/suggestions/issue-114701.stderr | 48 ++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 tests/ui/suggestions/issue-114701.rs create mode 100644 tests/ui/suggestions/issue-114701.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index dd79d1afc62f..02371f85ac3b 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -599,6 +599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) // Only suggest removing parens if there are no arguments && arg_exprs.is_empty() + && call_expr.span.contains(callee_expr.span) { let descr = match kind { def::CtorOf::Struct => "struct", diff --git a/tests/ui/suggestions/issue-114701.rs b/tests/ui/suggestions/issue-114701.rs new file mode 100644 index 000000000000..09d573f054bd --- /dev/null +++ b/tests/ui/suggestions/issue-114701.rs @@ -0,0 +1,15 @@ +enum Enum { , SVariant { v: T }, UVariant } //~ ERROR expected identifier, found `,` + +macro_rules! is_variant { + (TSVariant, ) => (!); + (SVariant, ) => (!); + (UVariant, $expr:expr) => (is_variant!(@check UVariant, {}, $expr)); + (@check $variant:ident, $matcher:tt, $expr:expr) => ( + assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, //~ ERROR this `if` expression + ); + ); +} + +fn main() { + is_variant!(UVariant, Enum::<()>::UVariant); //~ ERROR expected function +} diff --git a/tests/ui/suggestions/issue-114701.stderr b/tests/ui/suggestions/issue-114701.stderr new file mode 100644 index 000000000000..bccc98e06088 --- /dev/null +++ b/tests/ui/suggestions/issue-114701.stderr @@ -0,0 +1,48 @@ +error: expected identifier, found `,` + --> $DIR/issue-114701.rs:1:16 + | +LL | enum Enum { , SVariant { v: T }, UVariant } + | ^ + | | + | expected identifier + | help: remove this comma + +error: this `if` expression is missing a block after the condition + --> $DIR/issue-114701.rs:8:17 + | +LL | assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, + | ^^ +... +LL | is_variant!(UVariant, Enum::<()>::UVariant); + | ------------------------------------------- in this macro invocation + | +help: add a block here + --> $DIR/issue-114701.rs:8:64 + | +LL | assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, + | ^ +... +LL | is_variant!(UVariant, Enum::<()>::UVariant); + | ------------------------------------------- in this macro invocation + = note: this error originates in the macro `is_variant` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the `if` if you meant to write a `let...else` statement + | +LL - assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, +LL + assert!(let Enum::$variant::<()> $matcher = $expr () else { false }, + | + +error[E0618]: expected function, found `Enum<()>` + --> $DIR/issue-114701.rs:14:27 + | +LL | enum Enum { , SVariant { v: T }, UVariant } + | -------- `Enum::UVariant` defined here +... +LL | assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, + | -------- call expression requires function +... +LL | is_variant!(UVariant, Enum::<()>::UVariant); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0618`. From f2172ea4e25021cae0efb9ef078373a8cca43885 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Aug 2023 10:15:25 +0200 Subject: [PATCH 021/169] avoid transmuting Box when we can just cast raw pointers instead --- library/alloc/src/boxed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 8697a77db3bc..96b93830f960 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2183,7 +2183,7 @@ impl dyn Error + Send { let err: Box = self; ::downcast(err).map_err(|s| unsafe { // Reapply the `Send` marker. - mem::transmute::, Box>(s) + Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send)) }) } } @@ -2197,7 +2197,7 @@ impl dyn Error + Send + Sync { let err: Box = self; ::downcast(err).map_err(|s| unsafe { // Reapply the `Send + Sync` marker. - mem::transmute::, Box>(s) + Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync)) }) } } From 67b1d2aec171b4971c8133c459edde277222d66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 3 Mar 2023 06:20:24 +0100 Subject: [PATCH 022/169] Optimize DroplessArena arena allocation --- compiler/rustc_arena/src/lib.rs | 70 ++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index f4900ece1cc5..7ab195a7c2df 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -11,6 +11,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] +#![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(new_uninit)] #![feature(maybe_uninit_slice)] @@ -30,11 +31,11 @@ use smallvec::SmallVec; use std::alloc::Layout; use std::cell::{Cell, RefCell}; -use std::cmp; use std::marker::PhantomData; use std::mem::{self, MaybeUninit}; use std::ptr::{self, NonNull}; use std::slice; +use std::{cmp, intrinsics}; #[inline(never)] #[cold] @@ -363,6 +364,20 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { unsafe impl Send for TypedArena {} +#[inline(always)] +fn align_down(val: usize, align: usize) -> usize { + assert!(align.is_power_of_two()); + val & !(align - 1) +} + +#[inline(always)] +fn align(val: usize, align: usize) -> usize { + assert!(align.is_power_of_two()); + (val + align - 1) & !(align - 1) +} + +const DROPLESS_ALIGNMENT: usize = mem::align_of::(); + /// An arena that can hold objects of multiple different types that impl `Copy` /// and/or satisfy `!mem::needs_drop`. pub struct DroplessArena { @@ -395,8 +410,6 @@ impl Default for DroplessArena { } impl DroplessArena { - #[inline(never)] - #[cold] fn grow(&self, additional: usize) { unsafe { let mut chunks = self.chunks.borrow_mut(); @@ -418,11 +431,30 @@ impl DroplessArena { let mut chunk = ArenaChunk::new(new_cap); self.start.set(chunk.start()); - self.end.set(chunk.end()); + + // Align the end to DROPLESS_ALIGNMENT + let end = align_down(chunk.end().addr(), DROPLESS_ALIGNMENT); + // Make sure we don't go past `start` + let end = cmp::max(chunk.start().addr(), end); + self.end.set(chunk.end().with_addr(end)); + chunks.push(chunk); } } + #[inline(never)] + #[cold] + fn grow_and_alloc_raw(&self, layout: Layout) -> *mut u8 { + self.grow(layout.size()); + self.alloc_raw(layout) + } + + #[inline(never)] + #[cold] + fn grow_and_alloc(&self) -> *mut u8 { + self.grow_and_alloc_raw(Layout::new::()) + } + /// Allocates a byte slice with specified layout from the current memory /// chunk. Returns `None` if there is no free space left to satisfy the /// request. @@ -432,10 +464,13 @@ impl DroplessArena { let old_end = self.end.get(); let end = old_end.addr(); - let align = layout.align(); - let bytes = layout.size(); + // Align allocated bytes so that `self.end` stays aligned to DROPLESS_ALIGNMENT + let bytes = align(layout.size(), DROPLESS_ALIGNMENT); - let new_end = end.checked_sub(bytes)? & !(align - 1); + // Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT + unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) }; + + let new_end = align_down(end.checked_sub(bytes)?, layout.align()); if start <= new_end { let new_end = old_end.with_addr(new_end); self.end.set(new_end); @@ -448,21 +483,26 @@ impl DroplessArena { #[inline] pub fn alloc_raw(&self, layout: Layout) -> *mut u8 { assert!(layout.size() != 0); - loop { - if let Some(a) = self.alloc_raw_without_grow(layout) { - break a; - } - // No free space left. Allocate a new chunk to satisfy the request. - // On failure the grow will panic or abort. - self.grow(layout.size()); + if let Some(a) = self.alloc_raw_without_grow(layout) { + return a; } + // No free space left. Allocate a new chunk to satisfy the request. + // On failure the grow will panic or abort. + self.grow_and_alloc_raw(layout) } #[inline] pub fn alloc(&self, object: T) -> &mut T { assert!(!mem::needs_drop::()); + assert!(mem::size_of::() != 0); - let mem = self.alloc_raw(Layout::for_value::(&object)) as *mut T; + let mem = if let Some(a) = self.alloc_raw_without_grow(Layout::for_value::(&object)) { + a + } else { + // No free space left. Allocate a new chunk to satisfy the request. + // On failure the grow will panic or abort. + self.grow_and_alloc::() + } as *mut T; unsafe { // Write into uninitialized memory. From d5d72168fa325e3cbd893803c46564974e67a517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 5 Mar 2023 06:26:51 +0100 Subject: [PATCH 023/169] Allocate extra space to account for alignment losses --- compiler/rustc_arena/src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 7ab195a7c2df..108476a499f8 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -410,7 +410,11 @@ impl Default for DroplessArena { } impl DroplessArena { - fn grow(&self, additional: usize) { + fn grow(&self, layout: Layout) { + // Add some padding so we can align `self.end` while + // stilling fitting in a `layout` allocation. + let additional = layout.size() + cmp::max(DROPLESS_ALIGNMENT, layout.align()) - 1; + unsafe { let mut chunks = self.chunks.borrow_mut(); let mut new_cap; @@ -429,7 +433,7 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = ArenaChunk::new(new_cap); + let mut chunk = ArenaChunk::new(align(new_cap, PAGE)); self.start.set(chunk.start()); // Align the end to DROPLESS_ALIGNMENT @@ -445,8 +449,8 @@ impl DroplessArena { #[inline(never)] #[cold] fn grow_and_alloc_raw(&self, layout: Layout) -> *mut u8 { - self.grow(layout.size()); - self.alloc_raw(layout) + self.grow(layout); + self.alloc_raw_without_grow(layout).unwrap() } #[inline(never)] From 6f86591b8795fc45aad3dd59863c3b3afd246506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 14 Aug 2023 21:29:19 +0200 Subject: [PATCH 024/169] Address comments --- compiler/rustc_arena/src/lib.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 108476a499f8..e45b7c154faf 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -366,16 +366,18 @@ unsafe impl Send for TypedArena {} #[inline(always)] fn align_down(val: usize, align: usize) -> usize { - assert!(align.is_power_of_two()); + debug_assert!(align.is_power_of_two()); val & !(align - 1) } #[inline(always)] -fn align(val: usize, align: usize) -> usize { - assert!(align.is_power_of_two()); +fn align_up(val: usize, align: usize) -> usize { + debug_assert!(align.is_power_of_two()); (val + align - 1) & !(align - 1) } +// Pointer alignment is common in compiler types, so keep `DroplessArena` aligned to them +// to optimize away alignment code. const DROPLESS_ALIGNMENT: usize = mem::align_of::(); /// An arena that can hold objects of multiple different types that impl `Copy` @@ -390,6 +392,8 @@ pub struct DroplessArena { /// start. (This is slightly simpler and faster than allocating upwards, /// see .) /// When this pointer crosses the start pointer, a new chunk is allocated. + /// + /// This is kept aligned to DROPLESS_ALIGNMENT. end: Cell<*mut u8>, /// A vector of arena chunks. @@ -433,13 +437,16 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = ArenaChunk::new(align(new_cap, PAGE)); + let mut chunk = ArenaChunk::new(align_up(new_cap, PAGE)); self.start.set(chunk.start()); // Align the end to DROPLESS_ALIGNMENT let end = align_down(chunk.end().addr(), DROPLESS_ALIGNMENT); - // Make sure we don't go past `start` - let end = cmp::max(chunk.start().addr(), end); + + // Make sure we don't go past `start`. This should not happen since the allocation + // should be at least DROPLESS_ALIGNMENT - 1 bytes. + debug_assert!(chunk.start().addr() <= end); + self.end.set(chunk.end().with_addr(end)); chunks.push(chunk); @@ -469,7 +476,7 @@ impl DroplessArena { let end = old_end.addr(); // Align allocated bytes so that `self.end` stays aligned to DROPLESS_ALIGNMENT - let bytes = align(layout.size(), DROPLESS_ALIGNMENT); + let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT); // Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) }; @@ -477,6 +484,8 @@ impl DroplessArena { let new_end = align_down(end.checked_sub(bytes)?, layout.align()); if start <= new_end { let new_end = old_end.with_addr(new_end); + // `new_end` is aligned to DROPLESS_ALIGNMENT as `align_down` preserves alignment + // as both `end` and `bytes` are already aligned to DROPLESS_ALIGNMENT. self.end.set(new_end); Some(new_end) } else { From 6933848fbff3da5bfcd78ab836cda15e3f649ffc Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 14 Aug 2023 11:47:42 +0200 Subject: [PATCH 025/169] Add diagnostic items for `<*const _>::cast` and `<*mut _>::cast_const` --- compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/ptr/const_ptr.rs | 1 + library/core/src/ptr/mut_ptr.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 745a3590720a..f66b1e8970bc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -543,6 +543,7 @@ symbols! { const_panic_fmt, const_param_ty, const_precise_live_drops, + const_ptr_cast, const_raw_ptr_deref, const_raw_ptr_to_usize_cast, const_refs_to_cell, @@ -1159,6 +1160,7 @@ symbols! { profiler_runtime, ptr, ptr_cast, + ptr_cast_const, ptr_cast_mut, ptr_const_is_null, ptr_from_mut, diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 502f8a75863a..ee69d89a4b72 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -55,6 +55,7 @@ impl *const T { /// Casts to a pointer of another type. #[stable(feature = "ptr_cast", since = "1.38.0")] #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")] + #[rustc_diagnostic_item = "const_ptr_cast"] #[inline(always)] pub const fn cast(self) -> *const U { self as _ diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index d129e1d645f5..9dbb3f9d322c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -112,6 +112,7 @@ impl *mut T { /// [`cast_mut`]: #method.cast_mut #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_diagnostic_item = "ptr_cast_const"] #[inline(always)] pub const fn cast_const(self) -> *const T { self as _ From 91b05f8e098b310a27fa1b1eaeb7d830790d513a Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 13 Aug 2023 17:08:33 +0200 Subject: [PATCH 026/169] Improve `invalid_reference_casting` lint --- compiler/rustc_lint/src/reference_casting.rs | 49 +++++++---- tests/ui/lint/reference_casting.rs | 29 +++++++ tests/ui/lint/reference_casting.stderr | 90 ++++++++++++++++---- 3 files changed, 133 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 43f50a04aadd..2577cabb3f0f 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -100,7 +100,7 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) fn from_casts<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { // as *mut ... - let e = if let ExprKind::Cast(e, t) = e.kind + let mut e = if let ExprKind::Cast(e, t) = e.kind && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() { e // .cast_mut() @@ -112,23 +112,36 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) return None; }; - let e = e.peel_blocks(); - - // as *const ... - let e = if let ExprKind::Cast(e, t) = e.kind - && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = cx.typeck_results().node_type(t.hir_id).kind() { - e - // ptr::from_ref() - } else if let ExprKind::Call(path, [arg]) = e.kind - && let ExprKind::Path(ref qpath) = path.kind - && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) { - arg - } else { - return None; - }; - - Some(e) + let mut had_at_least_one_cast = false; + loop { + e = e.peel_blocks(); + // as *mut/const ... or as + e = if let ExprKind::Cast(expr, t) = e.kind + && matches!(cx.typeck_results().node_type(t.hir_id).kind(), ty::RawPtr(_) | ty::Uint(_)) { + had_at_least_one_cast = true; + expr + // .cast(), .cast_mut() or .cast_const() + } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_cast | sym::const_ptr_cast | sym::ptr_cast_mut | sym::ptr_cast_const) + ) + { + had_at_least_one_cast = true; + expr + // ptr::from_ref() + } else if let ExprKind::Call(path, [arg]) = e.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) { + return Some(arg); + } else if had_at_least_one_cast { + return Some(e); + } else { + return None; + }; + } } fn from_transmute<'tcx>( diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index f4e463b67c07..6c38bca3daa9 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -9,6 +9,10 @@ extern "C" { fn int_ffi(c: *mut i32); } +fn static_u8() -> &'static u8 { + &8 +} + unsafe fn ref_to_mut() { let num = &3i32; @@ -24,12 +28,28 @@ unsafe fn ref_to_mut() { //~^ ERROR casting `&T` to `&mut T` is undefined behavior let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32); //~^ ERROR casting `&T` to `&mut T` is undefined behavior + let _num = &mut *(num as *const i32).cast::().cast_mut(); + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + let _num = &mut *(num as *const i32).cast::().cast_mut().cast_const().cast_mut(); + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32); + //~^ ERROR casting `&T` to `&mut T` is undefined behavior let _num = &mut *std::mem::transmute::<_, *mut i32>(num); //~^ ERROR casting `&T` to `&mut T` is undefined behavior let deferred = num as *const i32 as *mut i32; let _num = &mut *deferred; //~^ ERROR casting `&T` to `&mut T` is undefined behavior + let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32; + let _num = &mut *deferred; + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + let _num = &mut *(num as *const _ as usize as *mut i32); + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + + unsafe fn generic_ref_cast_mut(this: &T) -> &mut T { + &mut *((this as *const _) as *mut _) + //~^ ERROR casting `&T` to `&mut T` is undefined behavior + } } unsafe fn assign_to_ref() { @@ -55,6 +75,15 @@ unsafe fn assign_to_ref() { let value = num as *const i32 as *mut i32; *value = 1; //~^ ERROR assigning to `&T` is undefined behavior + *(num as *const i32).cast::().cast_mut() = 2; + //~^ ERROR assigning to `&T` is undefined behavior + *(num as *const _ as usize as *mut i32) = 2; + //~^ ERROR assigning to `&T` is undefined behavior + + unsafe fn generic_assign_to_ref(this: &T, a: T) { + *(this as *const _ as *mut _) = a; + //~^ ERROR assigning to `&T` is undefined behavior + } } unsafe fn no_warn() { diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr index e8bb0557ca8a..7ff9b76a85e9 100644 --- a/tests/ui/lint/reference_casting.stderr +++ b/tests/ui/lint/reference_casting.stderr @@ -1,5 +1,5 @@ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:15:16 + --> $DIR/reference_casting.rs:19:16 | LL | let _num = &mut *(num as *const i32 as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,98 +7,154 @@ LL | let _num = &mut *(num as *const i32 as *mut i32); = note: `#[deny(invalid_reference_casting)]` on by default error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:17:16 + --> $DIR/reference_casting.rs:21:16 | LL | let _num = &mut *(num as *const i32).cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:19:16 + --> $DIR/reference_casting.rs:23:16 | LL | let _num = &mut *std::ptr::from_ref(num).cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:21:16 + --> $DIR/reference_casting.rs:25:16 | LL | let _num = &mut *std::ptr::from_ref({ num }).cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:23:16 + --> $DIR/reference_casting.rs:27:16 | LL | let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:25:16 + --> $DIR/reference_casting.rs:29:16 | LL | let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:27:16 + --> $DIR/reference_casting.rs:31:16 + | +LL | let _num = &mut *(num as *const i32).cast::().cast_mut(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:33:16 + | +LL | let _num = &mut *(num as *const i32).cast::().cast_mut().cast_const().cast_mut(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:35:16 + | +LL | let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:37:16 | LL | let _num = &mut *std::mem::transmute::<_, *mut i32>(num); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:31:16 + --> $DIR/reference_casting.rs:41:16 | LL | let deferred = num as *const i32 as *mut i32; | ----------------------------- casting happend here LL | let _num = &mut *deferred; | ^^^^^^^^^^^^^^ +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:44:16 + | +LL | let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32; + | ---------------------------------------------------------------------------- casting happend here +LL | let _num = &mut *deferred; + | ^^^^^^^^^^^^^^ + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:46:16 + | +LL | let _num = &mut *(num as *const _ as usize as *mut i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:50:9 + | +LL | &mut *((this as *const _) as *mut _) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:40:5 + --> $DIR/reference_casting.rs:60:5 | LL | *(a as *const _ as *mut _) = String::from("Replaced"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:42:5 + --> $DIR/reference_casting.rs:62:5 | LL | *(a as *const _ as *mut String) += " world"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:44:5 + --> $DIR/reference_casting.rs:64:5 | LL | *std::ptr::from_ref(num).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:46:5 + --> $DIR/reference_casting.rs:66:5 | LL | *std::ptr::from_ref({ num }).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:48:5 + --> $DIR/reference_casting.rs:68:5 | LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:50:5 + --> $DIR/reference_casting.rs:70:5 | LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:52:5 + --> $DIR/reference_casting.rs:72:5 | LL | *std::mem::transmute::<_, *mut i32>(num) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:56:5 + --> $DIR/reference_casting.rs:76:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here LL | *value = 1; | ^^^^^^^^^^ -error: aborting due to 16 previous errors +error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` + --> $DIR/reference_casting.rs:78:5 + | +LL | *(num as *const i32).cast::().cast_mut() = 2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` + --> $DIR/reference_casting.rs:80:5 + | +LL | *(num as *const _ as usize as *mut i32) = 2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` + --> $DIR/reference_casting.rs:84:9 + | +LL | *(this as *const _ as *mut _) = a; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 25 previous errors From 64cc56b31d9f0b624733afeb7465e93901257ebd Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 15 Aug 2023 11:14:01 +0200 Subject: [PATCH 027/169] Update LLVM submodule --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 7c612e1732f3..1833c2be108a 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 7c612e1732f3976fcfe29526ad796cbb6174b829 +Subproject commit 1833c2be108aefcb5d25f6280cf9763b1feb8005 From 62ca87f45d57b98c79b76d00a6d6a49fd28e3b1e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 15 Aug 2023 11:30:36 +0200 Subject: [PATCH 028/169] Add test for #114691 --- tests/ui/match/issue-114691.rs | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/ui/match/issue-114691.rs diff --git a/tests/ui/match/issue-114691.rs b/tests/ui/match/issue-114691.rs new file mode 100644 index 000000000000..cc17d9ecf05c --- /dev/null +++ b/tests/ui/match/issue-114691.rs @@ -0,0 +1,39 @@ +// run-pass + +// This test used to be miscompiled by LLVM 17. +#![allow(dead_code)] + +enum Pass { + Opaque { + clear_color: [f32; 4], + with_depth_pre_pass: bool, + }, + Transparent, +} + +enum LoadOp { + Clear, + Load, +} + +#[inline(never)] +fn check(x: Option) { + assert!(x.is_none()); +} + +#[inline(never)] +fn test(mode: Pass) { + check(match mode { + Pass::Opaque { + with_depth_pre_pass: true, + .. + } + | Pass::Transparent => None, + _ => Some(LoadOp::Clear), + }); +} + +fn main() { + println!("Hello, world!"); + test(Pass::Transparent); +} From c12c0841ad01d1239a1bd009610da2263ecde40b Mon Sep 17 00:00:00 2001 From: DianQK Date: Sat, 12 Aug 2023 00:24:25 +0800 Subject: [PATCH 029/169] Cherry-pick test for issue #114312 --- tests/codegen/issues/issue-114312.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/codegen/issues/issue-114312.rs diff --git a/tests/codegen/issues/issue-114312.rs b/tests/codegen/issues/issue-114312.rs new file mode 100644 index 000000000000..e2fbcef721ef --- /dev/null +++ b/tests/codegen/issues/issue-114312.rs @@ -0,0 +1,27 @@ +// compile-flags: -O +// min-llvm-version: 17 +// only-x86_64-unknown-linux-gnu + +// We want to check that this function does not mis-optimize to loop jumping. + +#![crate_type = "lib"] + +#[repr(C)] +pub enum Expr { + Sum, + // must have more than usize data + Sub(usize, u8), +} + +#[no_mangle] +pub extern "C" fn issue_114312(expr: Expr) { + // CHECK-LABEL: @issue_114312( + // CHECK-NOT: readonly + // CHECK-SAME: byval + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + match expr { + Expr::Sum => {} + Expr::Sub(_, _) => issue_114312(Expr::Sum), + } +} From 860fc246088c349bd95ce2da3e8637bb0c590105 Mon Sep 17 00:00:00 2001 From: r0cky Date: Tue, 15 Aug 2023 10:58:33 +0000 Subject: [PATCH 030/169] Remove extra errors --- tests/ui/suggestions/issue-114701.rs | 4 +-- tests/ui/suggestions/issue-114701.stderr | 41 +++--------------------- 2 files changed, 6 insertions(+), 39 deletions(-) diff --git a/tests/ui/suggestions/issue-114701.rs b/tests/ui/suggestions/issue-114701.rs index 09d573f054bd..81d7803ec8ce 100644 --- a/tests/ui/suggestions/issue-114701.rs +++ b/tests/ui/suggestions/issue-114701.rs @@ -1,11 +1,11 @@ -enum Enum { , SVariant { v: T }, UVariant } //~ ERROR expected identifier, found `,` +enum Enum { SVariant { v: T }, UVariant } macro_rules! is_variant { (TSVariant, ) => (!); (SVariant, ) => (!); (UVariant, $expr:expr) => (is_variant!(@check UVariant, {}, $expr)); (@check $variant:ident, $matcher:tt, $expr:expr) => ( - assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, //~ ERROR this `if` expression + assert!(if let Enum::$variant::<()> $matcher = $expr () { true } else { false }, ); ); } diff --git a/tests/ui/suggestions/issue-114701.stderr b/tests/ui/suggestions/issue-114701.stderr index bccc98e06088..67462a09c78d 100644 --- a/tests/ui/suggestions/issue-114701.stderr +++ b/tests/ui/suggestions/issue-114701.stderr @@ -1,48 +1,15 @@ -error: expected identifier, found `,` - --> $DIR/issue-114701.rs:1:16 - | -LL | enum Enum { , SVariant { v: T }, UVariant } - | ^ - | | - | expected identifier - | help: remove this comma - -error: this `if` expression is missing a block after the condition - --> $DIR/issue-114701.rs:8:17 - | -LL | assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, - | ^^ -... -LL | is_variant!(UVariant, Enum::<()>::UVariant); - | ------------------------------------------- in this macro invocation - | -help: add a block here - --> $DIR/issue-114701.rs:8:64 - | -LL | assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, - | ^ -... -LL | is_variant!(UVariant, Enum::<()>::UVariant); - | ------------------------------------------- in this macro invocation - = note: this error originates in the macro `is_variant` (in Nightly builds, run with -Z macro-backtrace for more info) -help: remove the `if` if you meant to write a `let...else` statement - | -LL - assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, -LL + assert!(let Enum::$variant::<()> $matcher = $expr () else { false }, - | - error[E0618]: expected function, found `Enum<()>` --> $DIR/issue-114701.rs:14:27 | -LL | enum Enum { , SVariant { v: T }, UVariant } - | -------- `Enum::UVariant` defined here +LL | enum Enum { SVariant { v: T }, UVariant } + | -------- `Enum::UVariant` defined here ... -LL | assert!(if let Enum::$variant::<()> $matcher = $expr () else { false }, +LL | assert!(if let Enum::$variant::<()> $matcher = $expr () { true } else { false }, | -------- call expression requires function ... LL | is_variant!(UVariant, Enum::<()>::UVariant); | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0618`. From ddcd7cac41b05995426b97f0f0bbca0866a1dd96 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 14 Aug 2023 17:51:19 +0800 Subject: [PATCH 031/169] Fix bad suggestion when wrong parentheses around a dyn trait --- compiler/rustc_parse/messages.ftl | 4 +- compiler/rustc_parse/src/errors.rs | 19 ++++++---- compiler/rustc_parse/src/parser/ty.rs | 22 ++++++----- tests/ui/parser/trait-object-delimiters.rs | 4 +- .../ui/parser/trait-object-delimiters.stderr | 12 +++--- ...sue-114797-bad-parentheses-dyn-trait.fixed | 17 +++++++++ .../issue-114797-bad-parentheses-dyn-trait.rs | 17 +++++++++ ...ue-114797-bad-parentheses-dyn-trait.stderr | 38 +++++++++++++++++++ 8 files changed, 105 insertions(+), 28 deletions(-) create mode 100644 tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed create mode 100644 tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs create mode 100644 tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 6888127f36c0..34cc0998c9b8 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -310,8 +310,8 @@ parse_inclusive_range_no_end = inclusive range with no end .suggestion_open_range = use `..` instead .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`) -parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds - .suggestion = remove the parentheses +parse_incorrect_parens_trait_bounds = incorrect parentheses around trait bounds +parse_incorrect_parens_trait_bounds_sugg = fix the parentheses parse_incorrect_semicolon = expected item, found `;` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 26f38c9156aa..e0b1e3678e41 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2636,21 +2636,24 @@ pub(crate) struct MissingPlusBounds { } #[derive(Diagnostic)] -#[diag(parse_incorrect_braces_trait_bounds)] -pub(crate) struct IncorrectBracesTraitBounds { +#[diag(parse_incorrect_parens_trait_bounds)] +pub(crate) struct IncorrectParensTraitBounds { #[primary_span] pub span: Vec, #[subdiagnostic] - pub sugg: IncorrectBracesTraitBoundsSugg, + pub sugg: IncorrectParensTraitBoundsSugg, } #[derive(Subdiagnostic)] -#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] -pub(crate) struct IncorrectBracesTraitBoundsSugg { +#[multipart_suggestion( + parse_incorrect_parens_trait_bounds_sugg, + applicability = "machine-applicable" +)] +pub(crate) struct IncorrectParensTraitBoundsSugg { #[suggestion_part(code = " ")] - pub l: Span, - #[suggestion_part(code = "")] - pub r: Span, + pub wrong_span: Span, + #[suggestion_part(code = "(")] + pub new_span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 3bb50b05aa34..27b1e9c0f112 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -714,6 +714,7 @@ impl<'a> Parser<'a> { /// ``` fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let lo = self.token.span; + let leading_token = self.prev_token.clone(); let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis)); let inner_lo = self.token.span; @@ -722,7 +723,7 @@ impl<'a> Parser<'a> { self.error_lt_bound_with_modifiers(modifiers); self.parse_generic_lt_bound(lo, inner_lo, has_parens)? } else { - self.parse_generic_ty_bound(lo, has_parens, modifiers)? + self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)? }; Ok(bound) @@ -827,6 +828,7 @@ impl<'a> Parser<'a> { lo: Span, has_parens: bool, modifiers: BoundModifiers, + leading_token: &Token, ) -> PResult<'a, GenericBound> { let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?; let mut path = if self.token.is_keyword(kw::Fn) @@ -873,18 +875,18 @@ impl<'a> Parser<'a> { } if has_parens { - if self.token.is_like_plus() { - // Someone has written something like `&dyn (Trait + Other)`. The correct code - // would be `&(dyn Trait + Other)`, but we don't have access to the appropriate - // span to suggest that. When written as `&dyn Trait + Other`, an appropriate - // suggestion is given. + // Someone has written something like `&dyn (Trait + Other)`. The correct code + // would be `&(dyn Trait + Other)` + if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) { let bounds = vec![]; self.parse_remaining_bounds(bounds, true)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; - let sp = vec![lo, self.prev_token.span]; - self.sess.emit_err(errors::IncorrectBracesTraitBounds { - span: sp, - sugg: errors::IncorrectBracesTraitBoundsSugg { l: lo, r: self.prev_token.span }, + self.sess.emit_err(errors::IncorrectParensTraitBounds { + span: vec![lo, self.prev_token.span], + sugg: errors::IncorrectParensTraitBoundsSugg { + wrong_span: leading_token.span.shrink_to_hi().to(lo), + new_span: leading_token.span.shrink_to_lo(), + }, }); } else { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index c41cda18743c..e9b13defe038 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -3,9 +3,9 @@ fn foo1(_: &dyn Drop + AsRef) {} //~ ERROR ambiguous `+` in a type //~^ ERROR only auto traits can be used as additional traits in a trait object -fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect braces around trait bounds +fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect parentheses around trait bounds -fn foo2_no_space(_: &dyn(Drop + AsRef)) {} //~ ERROR incorrect braces around trait bounds +fn foo2_no_space(_: &dyn(Drop + AsRef)) {} //~ ERROR incorrect parentheses around trait bounds fn foo3(_: &dyn {Drop + AsRef}) {} //~ ERROR expected parameter name, found `{` //~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index ccce3a8053e7..519546750938 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -4,28 +4,28 @@ error: ambiguous `+` in a type LL | fn foo1(_: &dyn Drop + AsRef) {} | ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef)` -error: incorrect braces around trait bounds +error: incorrect parentheses around trait bounds --> $DIR/trait-object-delimiters.rs:6:17 | LL | fn foo2(_: &dyn (Drop + AsRef)) {} | ^ ^ | -help: remove the parentheses +help: fix the parentheses | LL - fn foo2(_: &dyn (Drop + AsRef)) {} -LL + fn foo2(_: &dyn Drop + AsRef) {} +LL + fn foo2(_: &(dyn Drop + AsRef)) {} | -error: incorrect braces around trait bounds +error: incorrect parentheses around trait bounds --> $DIR/trait-object-delimiters.rs:8:25 | LL | fn foo2_no_space(_: &dyn(Drop + AsRef)) {} | ^ ^ | -help: remove the parentheses +help: fix the parentheses | LL - fn foo2_no_space(_: &dyn(Drop + AsRef)) {} -LL + fn foo2_no_space(_: &dyn Drop + AsRef) {} +LL + fn foo2_no_space(_: &(dyn Drop + AsRef)) {} | error: expected parameter name, found `{` diff --git a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed new file mode 100644 index 000000000000..57387936a4ca --- /dev/null +++ b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed @@ -0,0 +1,17 @@ +//run-rustfix +#![allow(dead_code)] + +trait Trait {} + +fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) { + //~^ ERROR incorrect parentheses around trait bounds + ptr as _ +} + +fn foo2(_: &(dyn Trait + Send)) {} +//~^ ERROR incorrect parentheses around trait bounds + +fn foo3(_: &(dyn Trait + Send)) {} +//~^ ERROR incorrect parentheses around trait bounds + +fn main() {} diff --git a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs new file mode 100644 index 000000000000..8a1939bcfe93 --- /dev/null +++ b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs @@ -0,0 +1,17 @@ +//run-rustfix +#![allow(dead_code)] + +trait Trait {} + +fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) { + //~^ ERROR incorrect parentheses around trait bounds + ptr as _ +} + +fn foo2(_: &dyn (Trait + Send)) {} +//~^ ERROR incorrect parentheses around trait bounds + +fn foo3(_: &dyn(Trait + Send)) {} +//~^ ERROR incorrect parentheses around trait bounds + +fn main() {} diff --git a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr new file mode 100644 index 000000000000..2d1abe91a1eb --- /dev/null +++ b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr @@ -0,0 +1,38 @@ +error: incorrect parentheses around trait bounds + --> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:6:49 + | +LL | fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) { + | ^ ^ + | +help: fix the parentheses + | +LL - fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) { +LL + fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) { + | + +error: incorrect parentheses around trait bounds + --> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:11:17 + | +LL | fn foo2(_: &dyn (Trait + Send)) {} + | ^ ^ + | +help: fix the parentheses + | +LL - fn foo2(_: &dyn (Trait + Send)) {} +LL + fn foo2(_: &(dyn Trait + Send)) {} + | + +error: incorrect parentheses around trait bounds + --> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:14:16 + | +LL | fn foo3(_: &dyn(Trait + Send)) {} + | ^ ^ + | +help: fix the parentheses + | +LL - fn foo3(_: &dyn(Trait + Send)) {} +LL + fn foo3(_: &(dyn Trait + Send)) {} + | + +error: aborting due to 3 previous errors + From 826471e93bda7a2cbf2213d1cf8f76a2cd77ec2c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 15 Aug 2023 13:37:47 -0300 Subject: [PATCH 032/169] Add trait related queries to SMIR's rustc_internal --- compiler/rustc_smir/src/stable_mir/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs index a74975cefc2c..19061742b64b 100644 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -85,6 +85,22 @@ pub fn all_local_items() -> CrateItems { with(|cx| cx.all_local_items()) } +pub fn all_trait_decls() -> TraitDecls { + with(|cx| cx.all_trait_decls()) +} + +pub fn trait_decl(trait_def: &TraitDef) -> TraitDecl { + with(|cx| cx.trait_decl(trait_def)) +} + +pub fn all_trait_impls() -> ImplTraitDecls { + with(|cx| cx.all_trait_impls()) +} + +pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait { + with(|cx| cx.trait_impl(trait_impl)) +} + pub trait Context { fn entry_fn(&mut self) -> Option; /// Retrieve all items of the local crate that have a MIR associated with them. From e1e6c002d826117806f55247c239fe7f40324c1c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 15 Aug 2023 19:30:09 +0200 Subject: [PATCH 033/169] fix typo: affect -> effect --- library/alloc/src/lib.rs | 2 +- library/core/src/lib.rs | 2 +- library/std/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cb8691aac138..41aac02eaa97 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -58,7 +58,7 @@ // To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be // able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. +// rustc itself never sets the feature, so this line has no effect there. #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] // #![allow(unused_attributes)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ded799160bf8..48c3c1f21234 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -51,7 +51,7 @@ #![cfg(not(test))] // To run core tests without x.py without ending up with two copies of core, Miri needs to be // able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. +// rustc itself never sets the feature, so this line has no effect there. #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] #![stable(feature = "core", since = "1.6.0")] #![doc( diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c07aa5cd91fe..ac4ce222fbaa 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -190,7 +190,7 @@ // To run std tests without x.py without ending up with two copies of std, Miri needs to be // able to "empty" this crate. See . -// rustc itself never sets the feature, so this line has no affect there. +// rustc itself never sets the feature, so this line has no effect there. #![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] // miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. #![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] From 785ebd9b21b15ab1b90b7e8765b9a5072a08a7e4 Mon Sep 17 00:00:00 2001 From: Taras Tsugrii Date: Tue, 15 Aug 2023 14:26:14 -0500 Subject: [PATCH 034/169] [nit] Fix a comment typo. --- library/alloc/src/str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 921ce850d1eb..38f9f39fbf89 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -612,7 +612,7 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { } /// Converts the bytes while the bytes are still ascii. -/// For better average performance, this is happens in chunks of `2*size_of::()`. +/// For better average performance, this happens in chunks of `2*size_of::()`. /// Returns a vec with the converted bytes. #[inline] #[cfg(not(test))] From e6ab5f72a2fa62158e29df30b0e9c6b3ec0c2b9b Mon Sep 17 00:00:00 2001 From: Tim Kurdov Date: Tue, 15 Aug 2023 22:37:48 +0100 Subject: [PATCH 035/169] Update the link in the docs of `std::intrinsics` The previous link in that place, https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs, no longer points to an existing file. --- library/core/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 9ef2c7cde02e..676d4f2f38ca 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -9,7 +9,7 @@ //! This includes changes in the stability of the constness. //! //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation -//! from to +//! from to //! and add a //! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration. //! From c31aedf47f946e616169d4e0b95f898981b4e84b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 16 Aug 2023 00:45:02 +0000 Subject: [PATCH 036/169] Don't ICE in is_trivially_sized when encountering late-bound self ty --- compiler/rustc_middle/src/ty/sty.rs | 4 ++-- .../sized-late-bound-issue-114872.rs | 19 +++++++++++++++++++ .../sized-late-bound-issue-114872.stderr | 11 +++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs create mode 100644 tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.stderr diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e6baa6242052..0291cdd6c579 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2827,11 +2827,11 @@ impl<'tcx> Ty<'tcx> { ty::Adt(def, _args) => def.sized_constraint(tcx).skip_binder().is_empty(), - ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false, + ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, ty::Infer(ty::TyVar(_)) => false, - ty::Bound(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("`is_trivially_sized` applied to unexpected type: {:?}", self) } } diff --git a/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs b/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs new file mode 100644 index 000000000000..ba55ab071852 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.rs @@ -0,0 +1,19 @@ +// check-pass + +#![feature(non_lifetime_binders)] +//~^ WARN is incomplete and may not be safe + +pub fn foo() +where + for V: Sized, +{ + bar(); +} + +pub fn bar() +where + for V: Sized, +{ +} + +pub fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.stderr b/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.stderr new file mode 100644 index 000000000000..e75d81270529 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/sized-late-bound-issue-114872.stderr @@ -0,0 +1,11 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/sized-late-bound-issue-114872.rs:3:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + From 50ca860b5fbcbc6f2c98fcc6b90e6511341d90be Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 16 Aug 2023 06:33:31 +0200 Subject: [PATCH 037/169] rustc book: make more pleasant to search --- src/doc/rustc/book.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml index 14ae1a7207ac..167aece0ed6a 100644 --- a/src/doc/rustc/book.toml +++ b/src/doc/rustc/book.toml @@ -7,5 +7,8 @@ title = "The rustc book" git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc" edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}" +[output.html.search] +use-boolean-and = true + [output.html.playground] runnable = false From 8d514f2e9876426c76178b7dcf2d9ddb9a9c6078 Mon Sep 17 00:00:00 2001 From: khei4 Date: Tue, 15 Aug 2023 20:52:54 +0900 Subject: [PATCH 038/169] add codegen test for issue 107554 specify llvm-version and bit width for int arg add missing percent simbol --- tests/codegen/trailing_zeros.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/codegen/trailing_zeros.rs diff --git a/tests/codegen/trailing_zeros.rs b/tests/codegen/trailing_zeros.rs new file mode 100644 index 000000000000..2ea0e447abe2 --- /dev/null +++ b/tests/codegen/trailing_zeros.rs @@ -0,0 +1,22 @@ +// compile-flags: -O +// min-llvm-version: 17 + +#![crate_type = "lib"] + +// CHECK-LABEL: @trailing_zeros_ge +#[no_mangle] +pub fn trailing_zeros_ge(val: u32) -> bool { + // CHECK: %[[AND:.*]] = and i32 %val, 7 + // CHECK: %[[ICMP:.*]] = icmp eq i32 %[[AND]], 0 + // CHECK: ret i1 %[[ICMP]] + val.trailing_zeros() >= 3 +} + +// CHECK-LABEL: @trailing_zeros_gt +#[no_mangle] +pub fn trailing_zeros_gt(val: u64) -> bool { + // CHECK: %[[AND:.*]] = and i64 %val, 15 + // CHECK: %[[ICMP:.*]] = icmp eq i64 %[[AND]], 0 + // CHECK: ret i1 %[[ICMP]] + val.trailing_zeros() > 3 +} From 3e9679e86106648eb32f9a5a495cb1ed708c0f50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Aug 2023 09:37:06 +0200 Subject: [PATCH 039/169] clarify CStr lack of layout guarnatees --- library/core/src/ffi/c_str.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 4082b208c126..92e38df40498 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -20,10 +20,10 @@ use crate::str; /// in each pair are borrowed references; the latter are owned /// strings. /// -/// Note that this structure is **not** `repr(C)` and is not recommended to be -/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI -/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide -/// a safe interface to other consumers. +/// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)` +/// notwithstanding) and is not recommended to be placed in the signatures of FFI functions. +/// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor +/// to provide a safe interface to other consumers. /// /// [`CString`]: ../../std/ffi/struct.CString.html /// [`String`]: ../../std/string/struct.String.html From 176a9392d130e0f5476852cd8a5b00cdf63899ae Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 8 Aug 2023 16:21:42 +0800 Subject: [PATCH 040/169] proc_macro: Update docs for `Spacing` Brings the docs more in line with reality --- library/proc_macro/src/lib.rs | 38 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index b641e73f4f83..83d637b685ac 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -916,21 +916,34 @@ impl !Send for Punct {} #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Sync for Punct {} -/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or -/// by a different token or whitespace ([`Spacing::Alone`]). +/// Indicates whether a `Punct` token can join with the following token +/// to form a multi-character operator. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub enum Spacing { - /// A `Punct` is not immediately followed by another `Punct`. - /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. - #[stable(feature = "proc_macro_lib2", since = "1.29.0")] - Alone, - /// A `Punct` is immediately followed by another `Punct`. - /// E.g. `+` is `Joint` in `+=` and `++`. + /// A `Punct` token can join with the following token to form a multi-character operator. /// - /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. + /// In token streams constructed using proc macro interfaces `Joint` punctuation tokens can be + /// followed by any other tokens. \ + /// However, in token streams parsed from source code compiler will only set spacing to `Joint` + /// in the following cases: + /// - A `Punct` is immediately followed by another `Punct` without a whitespace. \ + /// E.g. `+` is `Joint` in `+=` and `++`. + /// - A single quote `'` is immediately followed by an identifier without a whitespace. \ + /// E.g. `'` is `Joint` in `'lifetime`. + /// + /// This list may be extended in the future to enable more token combinations. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Joint, + /// A `Punct` token cannot join with the following token to form a multi-character operator. + /// + /// `Alone` punctuation tokens can be followed by any other tokens. \ + /// In token streams parsed from source code compiler will set spacing to `Alone` in all cases + /// not covered by the conditions for `Joint` above. \ + /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. + /// In particular, token not followed by anything will also be marked as `Alone`. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Alone, } impl Punct { @@ -962,10 +975,9 @@ impl Punct { self.0.ch as char } - /// Returns the spacing of this punctuation character, indicating whether it's immediately - /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace - /// (`Alone`) so the operator has certainly ended. + /// Returns the spacing of this punctuation character, indicating whether it can be potentially + /// combined into a multi-character operator with the following token (`Joint`), or the operator + /// has certainly ended (`Alone`). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn spacing(&self) -> Spacing { if self.0.joint { Spacing::Joint } else { Spacing::Alone } From a4e55f140b1c99ed27f6fb583388396a7a39c472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 16 Aug 2023 14:16:05 +0200 Subject: [PATCH 041/169] Remove conditional use of `Sharded` from query caches --- .../rustc_query_system/src/query/caches.rs | 56 +++---------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 9a09f516ec92..4ba9d53a92f7 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -1,9 +1,7 @@ use crate::dep_graph::DepNodeIndex; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sharded; -#[cfg(parallel_compiler)] -use rustc_data_structures::sharded::Sharded; +use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::sync::Lock; use rustc_index::{Idx, IndexVec}; use std::fmt::Debug; @@ -37,10 +35,7 @@ impl<'tcx, K: Eq + Hash, V: 'tcx> CacheSelector<'tcx, V> for DefaultCacheSelecto } pub struct DefaultCache { - #[cfg(parallel_compiler)] cache: Sharded>, - #[cfg(not(parallel_compiler))] - cache: Lock>, } impl Default for DefaultCache { @@ -60,10 +55,7 @@ where #[inline(always)] fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { let key_hash = sharded::make_hash(key); - #[cfg(parallel_compiler)] let lock = self.cache.get_shard_by_hash(key_hash).lock(); - #[cfg(not(parallel_compiler))] - let lock = self.cache.lock(); let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key); if let Some((_, value)) = result { Some(*value) } else { None } @@ -71,29 +63,16 @@ where #[inline] fn complete(&self, key: K, value: V, index: DepNodeIndex) { - #[cfg(parallel_compiler)] let mut lock = self.cache.get_shard_by_value(&key).lock(); - #[cfg(not(parallel_compiler))] - let mut lock = self.cache.lock(); // We may be overwriting another value. This is all right, since the dep-graph // will check that the fingerprint matches. lock.insert(key, (value, index)); } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - #[cfg(parallel_compiler)] - { - let shards = self.cache.lock_shards(); - for shard in shards.iter() { - for (k, v) in shard.iter() { - f(k, &v.0, v.1); - } - } - } - #[cfg(not(parallel_compiler))] - { - let map = self.cache.lock(); - for (k, v) in map.iter() { + let shards = self.cache.lock_shards(); + for shard in shards.iter() { + for (k, v) in shard.iter() { f(k, &v.0, v.1); } } @@ -151,10 +130,7 @@ impl<'tcx, K: Idx, V: 'tcx> CacheSelector<'tcx, V> for VecCacheSelector { } pub struct VecCache { - #[cfg(parallel_compiler)] cache: Sharded>>, - #[cfg(not(parallel_compiler))] - cache: Lock>>, } impl Default for VecCache { @@ -173,38 +149,20 @@ where #[inline(always)] fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { - #[cfg(parallel_compiler)] let lock = self.cache.get_shard_by_hash(key.index() as u64).lock(); - #[cfg(not(parallel_compiler))] - let lock = self.cache.lock(); if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None } } #[inline] fn complete(&self, key: K, value: V, index: DepNodeIndex) { - #[cfg(parallel_compiler)] let mut lock = self.cache.get_shard_by_hash(key.index() as u64).lock(); - #[cfg(not(parallel_compiler))] - let mut lock = self.cache.lock(); lock.insert(key, (value, index)); } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - #[cfg(parallel_compiler)] - { - let shards = self.cache.lock_shards(); - for shard in shards.iter() { - for (k, v) in shard.iter_enumerated() { - if let Some(v) = v { - f(&k, &v.0, v.1); - } - } - } - } - #[cfg(not(parallel_compiler))] - { - let map = self.cache.lock(); - for (k, v) in map.iter_enumerated() { + let shards = self.cache.lock_shards(); + for shard in shards.iter() { + for (k, v) in shard.iter_enumerated() { if let Some(v) = v { f(&k, &v.0, v.1); } From a1a94b1c0f0b990fa5dc0ecf05ba3acaa17a1d9a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 14 Aug 2023 22:25:32 +0200 Subject: [PATCH 042/169] Improve code readability by moving fmt args directly into the string --- src/librustdoc/clean/auto_trait.rs | 14 +-- src/librustdoc/clean/blanket_impl.rs | 4 +- src/librustdoc/clean/cfg.rs | 28 +++--- src/librustdoc/clean/inline.rs | 6 +- src/librustdoc/clean/mod.rs | 8 +- src/librustdoc/clean/types.rs | 6 +- src/librustdoc/clean/utils.rs | 18 ++-- src/librustdoc/config.rs | 26 +++--- src/librustdoc/core.rs | 9 +- src/librustdoc/docfs.rs | 2 +- src/librustdoc/doctest.rs | 10 +-- src/librustdoc/externalfiles.rs | 8 +- src/librustdoc/html/format.rs | 55 ++++++------ src/librustdoc/html/highlight.rs | 21 +++-- src/librustdoc/html/highlight/tests.rs | 2 +- src/librustdoc/html/length_limit.rs | 7 +- src/librustdoc/html/markdown.rs | 32 +++---- src/librustdoc/html/render/context.rs | 19 ++-- src/librustdoc/html/render/mod.rs | 14 ++- src/librustdoc/html/render/print_item.rs | 90 +++++++++---------- src/librustdoc/html/render/sidebar.rs | 14 +-- src/librustdoc/html/render/write_shared.rs | 19 ++-- src/librustdoc/html/sources.rs | 3 +- src/librustdoc/html/static_files.rs | 2 +- src/librustdoc/json/mod.rs | 6 +- src/librustdoc/lib.rs | 12 ++- src/librustdoc/markdown.rs | 10 +-- .../passes/calculate_doc_coverage.rs | 6 +- .../passes/check_doc_test_visibility.rs | 2 +- .../passes/collect_intra_doc_links.rs | 76 ++++++++-------- src/librustdoc/passes/lint/bare_urls.rs | 4 +- .../passes/lint/check_code_block_syntax.rs | 6 +- src/librustdoc/passes/lint/html_tags.rs | 10 +-- src/librustdoc/scrape_examples.rs | 6 +- src/librustdoc/visit_ast.rs | 6 +- 35 files changed, 261 insertions(+), 300 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 68d636b360ac..ec804bb98f01 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -46,7 +46,7 @@ where let tcx = self.cx.tcx; let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty])); if !self.cx.generated_synthetics.insert((ty, trait_def_id)) { - debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref); + debug!("get_auto_trait_impl_for({trait_ref:?}): already generated, aborting"); return None; } @@ -140,7 +140,7 @@ where let ty = tcx.type_of(item_def_id).instantiate_identity(); let f = auto_trait::AutoTraitFinder::new(tcx); - debug!("get_auto_trait_impls({:?})", ty); + debug!("get_auto_trait_impls({ty:?})"); let auto_traits: Vec<_> = self.cx.auto_traits.to_vec(); let mut auto_traits: Vec = auto_traits .into_iter() @@ -164,7 +164,7 @@ where region_name(region) .map(|name| { names_map.get(&name).unwrap_or_else(|| { - panic!("Missing lifetime with name {:?} for {:?}", name.as_str(), region) + panic!("Missing lifetime with name {:?} for {region:?}", name.as_str()) }) }) .unwrap_or(&Lifetime::statik()) @@ -372,7 +372,7 @@ where let output = output.as_ref().cloned().map(Box::new); if old_output.is_some() && old_output != output { - panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output); + panic!("Output mismatch for {ty:?} {old_output:?} {output:?}"); } let new_params = GenericArgs::Parenthesized { inputs: old_input, output }; @@ -462,7 +462,7 @@ where ); let mut generic_params = raw_generics.params; - debug!("param_env_to_generics({:?}): generic_params={:?}", item_def_id, generic_params); + debug!("param_env_to_generics({item_def_id:?}): generic_params={generic_params:?}"); let mut has_sized = FxHashSet::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); @@ -623,7 +623,7 @@ where // loop ty_to_traits.entry(ty.clone()).or_default().insert(trait_.clone()); } - _ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id), + _ => panic!("Unexpected LHS {lhs:?} for {item_def_id:?}"), } } }; @@ -710,7 +710,7 @@ where /// involved (impls rarely have more than a few bounds) means that it /// shouldn't matter in practice. fn unstable_debug_sort(&self, vec: &mut [T]) { - vec.sort_by_cached_key(|x| format!("{:?}", x)) + vec.sort_by_cached_key(|x| format!("{x:?}")) } fn is_fn_trait(&self, path: &Path) -> bool { diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 9d744237b577..dad2aa4061d6 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -17,7 +17,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { let param_env = cx.tcx.param_env(item_def_id); let ty = cx.tcx.type_of(item_def_id); - trace!("get_blanket_impls({:?})", ty); + trace!("get_blanket_impls({ty:?})"); let mut impls = Vec::new(); for trait_def_id in cx.tcx.all_traits() { if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id) @@ -72,7 +72,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .into_iter() .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx))); for predicate in predicates { - debug!("testing predicate {:?}", predicate); + debug!("testing predicate {predicate:?}"); let obligation = traits::Obligation::new( infcx.tcx, traits::ObligationCause::dummy(), diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 83886dd42aac..0bb8fcd24680 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -434,9 +434,9 @@ impl<'a> fmt::Display for Display<'a> { } if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { if self.1.is_html() { - write!(fmt, "{}", feat)?; + write!(fmt, "{feat}")?; } else { - write!(fmt, "`{}`", feat)?; + write!(fmt, "`{feat}`")?; } } else { write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; @@ -471,9 +471,9 @@ impl<'a> fmt::Display for Display<'a> { } if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { if self.1.is_html() { - write!(fmt, "{}", feat)?; + write!(fmt, "{feat}")?; } else { - write!(fmt, "`{}`", feat)?; + write!(fmt, "`{feat}`")?; } } else { write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?; @@ -551,21 +551,21 @@ impl<'a> fmt::Display for Display<'a> { "sgx" => "SGX", _ => "", }, - (sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian), - (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits), + (sym::target_endian, Some(endian)) => return write!(fmt, "{endian}-endian"), + (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{bits}-bit"), (sym::target_feature, Some(feat)) => match self.1 { Format::LongHtml => { - return write!(fmt, "target feature {}", feat); + return write!(fmt, "target feature {feat}"); } - Format::LongPlain => return write!(fmt, "target feature `{}`", feat), - Format::ShortHtml => return write!(fmt, "{}", feat), + Format::LongPlain => return write!(fmt, "target feature `{feat}`"), + Format::ShortHtml => return write!(fmt, "{feat}"), }, (sym::feature, Some(feat)) => match self.1 { Format::LongHtml => { - return write!(fmt, "crate feature {}", feat); + return write!(fmt, "crate feature {feat}"); } - Format::LongPlain => return write!(fmt, "crate feature `{}`", feat), - Format::ShortHtml => return write!(fmt, "{}", feat), + Format::LongPlain => return write!(fmt, "crate feature `{feat}`"), + Format::ShortHtml => return write!(fmt, "{feat}"), }, _ => "", }; @@ -580,12 +580,12 @@ impl<'a> fmt::Display for Display<'a> { Escape(v.as_str()) ) } else { - write!(fmt, r#"`{}="{}"`"#, name, v) + write!(fmt, r#"`{name}="{v}"`"#) } } else if self.1.is_html() { write!(fmt, "{}", Escape(name.as_str())) } else { - write!(fmt, "`{}`", name) + write!(fmt, "`{name}`") } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 389bac0f09db..5d5fb2ae2480 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -50,7 +50,7 @@ pub(crate) fn try_inline( } let mut ret = Vec::new(); - debug!("attrs={:?}", attrs); + debug!("attrs={attrs:?}"); let attrs_without_docs = attrs.map(|(attrs, def_id)| { (attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::>(), def_id) @@ -529,7 +529,7 @@ pub(crate) fn build_impl( } let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); - trace!("merged_attrs={:?}", merged_attrs); + trace!("merged_attrs={merged_attrs:?}"); trace!( "build_impl: impl {:?} for {:?}", @@ -781,7 +781,7 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { cx.active_extern_traits.insert(did); } - debug!("record_extern_trait: {:?}", did); + debug!("record_extern_trait: {did:?}"); let trait_ = build_external_trait(cx, did); cx.external_traits.borrow_mut().insert(did, trait_); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b6ba4c853d4c..51e454eac168 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -215,7 +215,7 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>( ) -> Path { let kind = cx.tcx.def_kind(trait_ref.def_id()).into(); if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { - span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {:?}", kind); + span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {kind:?}"); } inline::record_extern_fqn(cx, trait_ref.def_id(), kind); let path = @@ -304,7 +304,7 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option { - debug!("cannot clean region {:?}", region); + debug!("cannot clean region {region:?}"); None } } @@ -1867,11 +1867,11 @@ fn normalize<'tcx>( .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)); match normalized { Ok(normalized_value) => { - debug!("normalized {:?} to {:?}", ty, normalized_value); + debug!("normalized {ty:?} to {normalized_value:?}"); Some(normalized_value) } Err(err) => { - debug!("failed to normalize {:?}: {:?}", ty, err); + debug!("failed to normalize {ty:?}: {err:?}"); None } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cb089ddd09a3..49bde1d31526 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -78,7 +78,7 @@ impl ItemId { #[track_caller] pub(crate) fn expect_def_id(self) -> DefId { self.as_def_id() - .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{:?}` isn't a DefId", self)) + .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId")) } #[inline] @@ -352,7 +352,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { match tcx.def_kind(parent) { DefKind::Struct | DefKind::Union => false, DefKind::Variant => true, - parent_kind => panic!("unexpected parent kind: {:?}", parent_kind), + parent_kind => panic!("unexpected parent kind: {parent_kind:?}"), } } @@ -436,7 +436,7 @@ impl Item { attrs: Box, cfg: Option>, ) -> Item { - trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg); + trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}"); Item { item_id: def_id.into(), diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 3c79ce577822..a973538073c0 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -218,7 +218,7 @@ pub(crate) fn build_deref_target_impls( pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { use rustc_hir::*; - debug!("trying to get a name from pattern: {:?}", p); + debug!("trying to get a name from pattern: {p:?}"); Symbol::intern(&match p.kind { PatKind::Wild | PatKind::Struct(..) => return kw::Underscore, @@ -461,7 +461,7 @@ pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String { /// Given a type Path, resolve it to a Type using the TyCtxt pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { - debug!("resolve_type({:?})", path); + debug!("resolve_type({path:?})"); match path.res { Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), @@ -500,7 +500,7 @@ pub(crate) fn get_auto_trait_and_blanket_impls( /// [`href()`]: crate::html::format::href pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { use DefKind::*; - debug!("register_res({:?})", res); + debug!("register_res({res:?})"); let (kind, did) = match res { Res::Def( @@ -523,7 +523,7 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { did, ) => (kind.into(), did), - _ => panic!("register_res: unexpected {:?}", res), + _ => panic!("register_res: unexpected {res:?}"), }; if did.is_local() { return did; @@ -601,7 +601,7 @@ pub(super) fn render_macro_arms<'a>( ) -> String { let mut out = String::new(); for matcher in matchers { - writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim) + writeln!(out, " {} => {{ ... }}{arm_delim}", render_macro_matcher(tcx, matcher)) .unwrap(); } out @@ -618,20 +618,18 @@ pub(super) fn display_macro_source( let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]); if def.macro_rules { - format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";")) + format!("macro_rules! {name} {{\n{}}}", render_macro_arms(cx.tcx, matchers, ";")) } else { if matchers.len() <= 1 { format!( - "{}macro {}{} {{\n ...\n}}", + "{}macro {name}{} {{\n ...\n}}", visibility_to_src_with_space(Some(vis), cx.tcx, def_id), - name, matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::(), ) } else { format!( - "{}macro {} {{\n{}}}", + "{}macro {name} {{\n{}}}", visibility_to_src_with_space(Some(vis), cx.tcx, def_id), - name, render_macro_arms(cx.tcx, matchers, ","), ) } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 217f1a6ee6b6..81fb13f4166b 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -50,7 +50,7 @@ impl TryFrom<&str> for OutputFormat { match value { "json" => Ok(OutputFormat::Json), "html" => Ok(OutputFormat::Html), - _ => Err(format!("unknown output format `{}`", value)), + _ => Err(format!("unknown output format `{value}`")), } } } @@ -383,7 +383,7 @@ impl Options { match kind.parse() { Ok(kind) => emit.push(kind), Err(()) => { - diag.err(format!("unrecognized emission type: {}", kind)); + diag.err(format!("unrecognized emission type: {kind}")); return Err(1); } } @@ -415,7 +415,7 @@ impl Options { println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)"); for theme_file in to_check.iter() { - print!(" - Checking \"{}\"...", theme_file); + print!(" - Checking \"{theme_file}\"..."); let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag); if !differences.is_empty() || !success { println!(" FAILED"); @@ -556,30 +556,28 @@ impl Options { matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned())) { if !theme_file.is_file() { - diag.struct_err(format!("invalid argument: \"{}\"", theme_s)) + diag.struct_err(format!("invalid argument: \"{theme_s}\"")) .help("arguments to --theme must be files") .emit(); return Err(1); } if theme_file.extension() != Some(OsStr::new("css")) { - diag.struct_err(format!("invalid argument: \"{}\"", theme_s)) + diag.struct_err(format!("invalid argument: \"{theme_s}\"")) .help("arguments to --theme must have a .css extension") .emit(); return Err(1); } let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag); if !success { - diag.struct_err(format!("error loading theme file: \"{}\"", theme_s)).emit(); + diag.struct_err(format!("error loading theme file: \"{theme_s}\"")).emit(); return Err(1); } else if !ret.is_empty() { diag.struct_warn(format!( - "theme file \"{}\" is missing CSS rules from the default theme", - theme_s + "theme file \"{theme_s}\" is missing CSS rules from the default theme", )) .warn("the theme may appear incorrect when loaded") .help(format!( - "to see what rules are missing, call `rustdoc --check-theme \"{}\"`", - theme_s + "to see what rules are missing, call `rustdoc --check-theme \"{theme_s}\"`", )) .emit(); } @@ -608,7 +606,7 @@ impl Options { match matches.opt_str("r").as_deref() { Some("rust") | None => {} Some(s) => { - diag.struct_err(format!("unknown input format: {}", s)).emit(); + diag.struct_err(format!("unknown input format: {s}")).emit(); return Err(1); } } @@ -628,7 +626,7 @@ impl Options { let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { Ok(types) => types, Err(e) => { - diag.struct_err(format!("unknown crate type: {}", e)).emit(); + diag.struct_err(format!("unknown crate type: {e}")).emit(); return Err(1); } }; @@ -787,7 +785,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han for &flag in deprecated_flags.iter() { if matches.opt_present(flag) { - diag.struct_warn(format!("the `{}` flag is deprecated", flag)) + diag.struct_warn(format!("the `{flag}` flag is deprecated")) .note( "see issue #44136 \ for more information", @@ -800,7 +798,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han for &flag in removed_flags.iter() { if matches.opt_present(flag) { - let mut err = diag.struct_warn(format!("the `{}` flag no longer functions", flag)); + let mut err = diag.struct_warn(format!("the `{flag}` flag no longer functions")); err.note( "see issue #44136 \ for more information", diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index d7da81209969..4c8dab61f0cb 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -283,7 +283,7 @@ pub(crate) fn create_config( let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(def_id)); - debug!("visiting body for {:?}", def_id); + debug!("visiting body for {def_id:?}"); EmitIgnoredResolutionErrors::new(tcx).visit_body(body); (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) }; @@ -377,7 +377,7 @@ pub(crate) fn run_global_ctxt( fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler, sp: Span) { let mut msg = - diag.struct_span_warn(sp, format!("the `#![doc({})]` attribute is deprecated", name)); + diag.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated")); msg.note( "see issue #44136 \ for more information", @@ -470,7 +470,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { } fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { - debug!("visiting path {:?}", path); + debug!("visiting path {path:?}"); if path.res == Res::Err { // We have less context here than in rustc_resolve, // so we can only emit the name and span. @@ -487,8 +487,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { self.tcx.sess, path.span, E0433, - "failed to resolve: {}", - label + "failed to resolve: {label}", ); err.span_label(path.span, label); err.note("this error was originally ignored because you are running `rustdoc`"); diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs index d58b8dc6ad4a..2962517badcf 100644 --- a/src/librustdoc/docfs.rs +++ b/src/librustdoc/docfs.rs @@ -72,7 +72,7 @@ impl DocFS { let sender = self.errors.clone().expect("can't write after closing"); self.pool.execute(move || { fs::write(&path, contents).unwrap_or_else(|e| { - sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| { + sender.send(format!("\"{}\": {e}", path.display())).unwrap_or_else(|_| { panic!("failed to send error on \"{}\"", path.display()) }) }); diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3315ccad4d36..24333a21dd62 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -192,7 +192,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { // The allow lint level is not expected, // as if allow is specified, no message // is to be emitted. - v => unreachable!("Invalid lint level '{}'", v), + v => unreachable!("Invalid lint level '{v}'"), }) .unwrap_or("warn") .to_string(); @@ -404,7 +404,7 @@ fn run_test( compiler.stdin(Stdio::piped()); compiler.stderr(Stdio::piped()); - debug!("compiler invocation for doctest: {:?}", compiler); + debug!("compiler invocation for doctest: {compiler:?}"); let mut child = compiler.spawn().expect("Failed to spawn rustc process"); { @@ -933,7 +933,7 @@ impl Collector { if !item_path.is_empty() { item_path.push(' '); } - format!("{} - {}(line {})", filename.prefer_local(), item_path, line) + format!("{} - {item_path}(line {line})", filename.prefer_local()) } pub(crate) fn set_position(&mut self, position: Span) { @@ -1010,7 +1010,7 @@ impl Tester for Collector { path.push(&test_id); if let Err(err) = std::fs::create_dir_all(&path) { - eprintln!("Couldn't create directory for doctest executables: {}", err); + eprintln!("Couldn't create directory for doctest executables: {err}"); panic::resume_unwind(Box::new(())); } @@ -1079,7 +1079,7 @@ impl Tester for Collector { eprint!("Test executable succeeded, but it's marked `should_panic`."); } TestFailure::MissingErrorCodes(codes) => { - eprint!("Some expected error codes were not found: {:?}", codes); + eprint!("Some expected error codes were not found: {codes:?}"); } TestFailure::ExecutionError(err) => { eprint!("Couldn't run the test: {err}"); diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 88049c4ca005..ada5f0fadacb 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -37,8 +37,7 @@ impl ExternalHtml { let bc = load_external_files(before_content, diag)?; let m_bc = load_external_files(md_before_content, diag)?; let bc = format!( - "{}{}", - bc, + "{bc}{}", Markdown { content: &m_bc, links: &[], @@ -53,8 +52,7 @@ impl ExternalHtml { let ac = load_external_files(after_content, diag)?; let m_ac = load_external_files(md_after_content, diag)?; let ac = format!( - "{}{}", - ac, + "{ac}{}", Markdown { content: &m_ac, links: &[], @@ -83,7 +81,7 @@ pub(crate) fn load_string>( let contents = match fs::read(file_path) { Ok(bytes) => bytes, Err(e) => { - diag.struct_err(format!("error reading `{}`: {}", file_path.display(), e)).emit(); + diag.struct_err(format!("error reading `{}`: {e}", file_path.display())).emit(); return Err(LoadStringError::ReadFail); } }; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 58022046294b..b00b48c5d64c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -228,9 +228,9 @@ impl clean::GenericParamDef { if let Some(default) = default { if f.alternate() { - write!(f, " = {:#}", default)?; + write!(f, " = {default:#}")?; } else { - write!(f, " = {}", default)?; + write!(f, " = {default}")?; } } @@ -451,9 +451,9 @@ impl clean::GenericBound { hir::TraitBoundModifier::MaybeConst => "", }; if f.alternate() { - write!(f, "{}{:#}", modifier_str, ty.print(cx)) + write!(f, "{modifier_str}{:#}", ty.print(cx)) } else { - write!(f, "{}{}", modifier_str, ty.print(cx)) + write!(f, "{modifier_str}{}", ty.print(cx)) } } }) @@ -599,7 +599,7 @@ fn generate_macro_def_id_path( let cstore = CStore::from_tcx(tcx); // We need this to prevent a `panic` when this function is used from intra doc links... if !cstore.has_crate_data(def_id.krate) { - debug!("No data for crate {}", crate_name); + debug!("No data for crate {crate_name}"); return Err(HrefError::NotInExternalCache); } // Check to see if it is a macro 2.0 or built-in macro. @@ -631,19 +631,18 @@ fn generate_macro_def_id_path( let url = match cache.extern_locations[&def_id.krate] { ExternalLocation::Remote(ref s) => { // `ExternalLocation::Remote` always end with a `/`. - format!("{}{}", s, path.iter().map(|p| p.as_str()).join("/")) + format!("{s}{}", path.iter().map(|p| p.as_str()).join("/")) } ExternalLocation::Local => { // `root_path` always end with a `/`. format!( - "{}{}/{}", + "{}{crate_name}/{}", root_path.unwrap_or(""), - crate_name, path.iter().map(|p| p.as_str()).join("/") ) } ExternalLocation::Unknown => { - debug!("crate {} not in cache when linkifying macros", crate_name); + debug!("crate {crate_name} not in cache when linkifying macros"); return Err(HrefError::NotInExternalCache); } }; @@ -732,7 +731,7 @@ pub(crate) fn href_with_root_path( _ => { let prefix = shortty.as_str(); let last = fqp.last().unwrap(); - url_parts.push_fmt(format_args!("{}.{}.html", prefix, last)); + url_parts.push_fmt(format_args!("{prefix}.{last}.html")); } } Ok((url_parts.finish(), shortty, fqp.to_vec())) @@ -838,7 +837,7 @@ fn resolved_path<'cx>( } else { anchor(did, last.name, cx).to_string() }; - write!(w, "{}{}", path, last.args.print(cx))?; + write!(w, "{path}{}", last.args.print(cx))?; } Ok(()) } @@ -906,7 +905,7 @@ fn primitive_link_fragment( None => {} } } - write!(f, "{}", name)?; + f.write_str(name)?; if needs_termination { write!(f, "")?; } @@ -946,15 +945,11 @@ pub(crate) fn anchor<'a, 'cx: 'a>( if let Ok((url, short_ty, fqp)) = parts { write!( f, - r#"{}"#, - short_ty, - url, - short_ty, + r#"{text}"#, join_with_double_colon(&fqp), - text.as_str() ) } else { - write!(f, "{}", text) + f.write_str(text.as_str()) } }) } @@ -965,10 +960,10 @@ fn fmt_type<'cx>( use_absolute: bool, cx: &'cx Context<'_>, ) -> fmt::Result { - trace!("fmt_type(t = {:?})", t); + trace!("fmt_type(t = {t:?})"); match *t { - clean::Generic(name) => write!(f, "{}", name), + clean::Generic(name) => f.write_str(name.as_str()), clean::Type::Path { ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. let did = path.def_id(); @@ -1085,13 +1080,13 @@ fn fmt_type<'cx>( if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { let text = if f.alternate() { - format!("*{} {:#}", m, t.print(cx)) + format!("*{m} {:#}", t.print(cx)) } else { - format!("*{} {}", m, t.print(cx)) + format!("*{m} {}", t.print(cx)) }; primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx) } else { - primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?; + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{m} "), cx)?; fmt::Display::fmt(&t.print(cx), f) } } @@ -1446,10 +1441,10 @@ impl clean::FnDecl { write!(f, "self")?; } clean::SelfBorrowed(Some(ref lt), mtbl) => { - write!(f, "{}{} {}self", amp, lt.print(), mtbl.print_with_space())?; + write!(f, "{amp}{} {}self", lt.print(), mtbl.print_with_space())?; } clean::SelfBorrowed(None, mtbl) => { - write!(f, "{}{}self", amp, mtbl.print_with_space())?; + write!(f, "{amp}{}self", mtbl.print_with_space())?; } clean::SelfExplicit(ref typ) => { write!(f, "self: ")?; @@ -1523,7 +1518,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( "pub(super) ".into() } else { let path = cx.tcx().def_path(vis_did); - debug!("path={:?}", path); + debug!("path={path:?}"); // modified from `resolved_path()` to work with `DefPathData` let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); let anchor = anchor(vis_did, last_name, cx); @@ -1532,12 +1527,12 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( for seg in &path.data[..path.data.len() - 1] { let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap()); } - let _ = write!(s, "{}) ", anchor); + let _ = write!(s, "{anchor}) "); s.into() } } }; - display_fn(move |f| write!(f, "{}", to_print)) + display_fn(move |f| f.write_str(&to_print)) } /// This function is the same as print_with_space, except that it renders no links. @@ -1632,7 +1627,7 @@ impl clean::Import { if name == self.source.path.last() { write!(f, "use {};", self.source.print(cx)) } else { - write!(f, "use {} as {};", self.source.print(cx), name) + write!(f, "use {} as {name};", self.source.print(cx)) } } clean::ImportKind::Glob => { @@ -1661,7 +1656,7 @@ impl clean::ImportSource { if let hir::def::Res::PrimTy(p) = self.path.res { primitive_link(f, PrimitiveType::from(p), name.as_str(), cx)?; } else { - write!(f, "{}", name)?; + f.write_str(name.as_str())?; } Ok(()) } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index a99ac0f4e052..e5d1b2f060c0 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -929,15 +929,15 @@ fn string_without_closing_tag( open_tag: bool, ) -> Option<&'static str> { let Some(klass) = klass else { - write!(out, "{}", text).unwrap(); + write!(out, "{text}").unwrap(); return None; }; let Some(def_span) = klass.get_span() else { if !open_tag { - write!(out, "{}", text).unwrap(); + write!(out, "{text}").unwrap(); return None; } - write!(out, "{}", klass.as_html(), text).unwrap(); + write!(out, "{text}", klass.as_html()).unwrap(); return Some(""); }; @@ -947,14 +947,13 @@ fn string_without_closing_tag( match t { "self" | "Self" => write!( &mut path, - "{}", + "{t}", Class::Self_(DUMMY_SP).as_html(), - t ), "crate" | "super" => { - write!(&mut path, "{}", Class::KeyWord.as_html(), t) + write!(&mut path, "{t}", Class::KeyWord.as_html()) } - t => write!(&mut path, "{}", t), + t => write!(&mut path, "{t}"), } .expect("Failed to build source HTML path"); path @@ -997,13 +996,13 @@ fn string_without_closing_tag( if !open_tag { // We're already inside an element which has the same klass, no need to give it // again. - write!(out, "{}", href, text_s).unwrap(); + write!(out, "{text_s}").unwrap(); } else { let klass_s = klass.as_html(); if klass_s.is_empty() { - write!(out, "{}", href, text_s).unwrap(); + write!(out, "{text_s}").unwrap(); } else { - write!(out, "{}", klass_s, href, text_s).unwrap(); + write!(out, "{text_s}").unwrap(); } } return Some(""); @@ -1018,7 +1017,7 @@ fn string_without_closing_tag( out.write_str(&text_s).unwrap(); Some("") } else { - write!(out, "{}", klass_s, text_s).unwrap(); + write!(out, "{text_s}").unwrap(); Some("") } } diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 2c93b9a097f4..4c0874a686fe 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -23,7 +23,7 @@ fn test_html_highlighting() { let html = { let mut out = Buffer::new(); write_code(&mut out, src, None, None); - format!("{}
{}
\n", STYLE, out.into_inner()) + format!("{STYLE}
{}
\n", out.into_inner()) }; expect_file!["fixtures/sample.html"].assert_eq(&html); }); diff --git a/src/librustdoc/html/length_limit.rs b/src/librustdoc/html/length_limit.rs index 4c8db2c6784a..8562e103dc17 100644 --- a/src/librustdoc/html/length_limit.rs +++ b/src/librustdoc/html/length_limit.rs @@ -78,8 +78,7 @@ impl HtmlWithLimit { pub(super) fn open_tag(&mut self, tag_name: &'static str) { assert!( tag_name.chars().all(|c| ('a'..='z').contains(&c)), - "tag_name contained non-alphabetic chars: {:?}", - tag_name + "tag_name contained non-alphabetic chars: {tag_name:?}", ); self.queued_tags.push(tag_name); } @@ -88,7 +87,7 @@ impl HtmlWithLimit { pub(super) fn close_tag(&mut self) { match self.unclosed_tags.pop() { // Close the most recently opened tag. - Some(tag_name) => write!(self.buf, "", tag_name).unwrap(), + Some(tag_name) => write!(self.buf, "").unwrap(), // There are valid cases where `close_tag()` is called without // there being any tags to close. For example, this occurs when // a tag is opened after the length limit is exceeded; @@ -101,7 +100,7 @@ impl HtmlWithLimit { /// Write all queued tags and add them to the `unclosed_tags` list. fn flush_queue(&mut self) { for tag_name in self.queued_tags.drain(..) { - write!(self.buf, "<{}>", tag_name).unwrap(); + write!(self.buf, "<{tag_name}>").unwrap(); self.unclosed_tags.push(tag_name); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 3fb7122fad35..a31b228b7068 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -246,9 +246,8 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { return Some(Event::Html( format!( "
\ -
{}
\ +
{}
\
", - lang, Escape(&original_text), ) .into(), @@ -288,8 +287,9 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { let test_escaped = small_url_encode(test); Some(format!( - r#"Run"#, - url, test_escaped, channel, edition, + "Run", )) }); @@ -349,7 +349,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { dest, title, ))) => { - debug!("saw start of shortcut link to {} with title {}", dest, title); + debug!("saw start of shortcut link to {dest} with title {title}"); // If this is a shortcut link, it was resolved by the broken_link_callback. // So the URL will already be updated properly. let link = self.links.iter().find(|&link| *link.href == **dest); @@ -370,7 +370,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { dest, _, ))) => { - debug!("saw end of shortcut link to {}", dest); + debug!("saw end of shortcut link to {dest}"); if self.links.iter().any(|link| *link.href == **dest) { assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); self.shortcut_link = None; @@ -379,7 +379,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. // [`fn@f`] Some(Event::Code(text)) => { - trace!("saw code {}", text); + trace!("saw code {text}"); if let Some(link) = self.shortcut_link { // NOTE: this only replaces if the code block is the *entire* text. // If only part of the link has code highlighting, the disambiguator will not be removed. @@ -394,7 +394,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { l.href == link.href && Some(&**text) == l.original_text.get(1..l.original_text.len() - 1) }) { - debug!("replacing {} with {}", text, link.new_text); + debug!("replacing {text} with {}", link.new_text); *text = CowStr::Borrowed(&link.new_text); } } @@ -402,7 +402,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { // Replace plain text in links, but only in the middle of a shortcut link. // [fn@f] Some(Event::Text(text)) => { - trace!("saw text {}", text); + trace!("saw text {text}"); if let Some(link) = self.shortcut_link { // NOTE: same limitations as `Event::Code` if let Some(link) = self @@ -410,7 +410,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { .iter() .find(|l| l.href == link.href && **text == *l.original_text) { - debug!("replacing {} with {}", text, link.new_text); + debug!("replacing {text} with {}", link.new_text); *text = CowStr::Borrowed(&link.new_text); } } @@ -522,12 +522,12 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator let mut html_header = String::new(); html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone())); let sec = builder.push(level as u32, html_header, id.clone()); - self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0)); + self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0)); } let level = std::cmp::min(level as u32 + (self.heading_offset as u32), MAX_HEADER_LEVEL); - self.buf.push_back((Event::Html(format!("", level).into()), 0..0)); + self.buf.push_back((Event::Html(format!("").into()), 0..0)); let start_tags = format!( "\ @@ -681,14 +681,14 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { v.sort_by(|a, b| a.1.cmp(&b.1)); let mut ret = String::from("

    "); for (mut content, id) in v { - write!(ret, "
  1. ", id).unwrap(); + write!(ret, "
  2. ").unwrap(); let mut is_paragraph = false; if let Some(&Event::End(Tag::Paragraph)) = content.last() { content.pop(); is_paragraph = true; } html::push_html(&mut ret, content.into_iter()); - write!(ret, " ", id).unwrap(); + write!(ret, " ").unwrap(); if is_paragraph { ret.push_str("

    "); } @@ -959,7 +959,7 @@ impl LangString { } { if let Some(extra) = extra { extra.error_invalid_codeblock_attr( - format!("unknown attribute `{}`. Did you mean `{}`?", x, flag), + format!("unknown attribute `{x}`. Did you mean `{flag}`?"), help, ); } @@ -1038,7 +1038,7 @@ impl MarkdownWithToc<'_> { html::push_html(&mut s, p); } - format!("{}", toc.into_toc().print(), s) + format!("{s}", toc.into_toc().print()) } } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 991edbddc6f4..f1d207d99e73 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -206,15 +206,14 @@ impl<'tcx> Context<'tcx> { format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate) } else { format!( - "API documentation for the Rust `{}` {} in crate `{}`.", + "API documentation for the Rust `{}` {tyname} in crate `{}`.", it.name.as_ref().unwrap(), - tyname, self.shared.layout.krate ) }; let name; let tyname_s = if it.is_crate() { - name = format!("{} crate", tyname); + name = format!("{tyname} crate"); name.as_str() } else { tyname.as_str() @@ -264,7 +263,7 @@ impl<'tcx> Context<'tcx> { current_path.push_str(&item_path(ty, names.last().unwrap().as_str())); redirections.borrow_mut().insert(current_path, path); } - None => return layout::redirect(&format!("{}{}", self.root_path(), path)), + None => return layout::redirect(&format!("{}{path}", self.root_path())), } } } @@ -382,11 +381,7 @@ impl<'tcx> Context<'tcx> { let hiline = span.hi(self.sess()).line; format!( "#{}", - if loline == hiline { - loline.to_string() - } else { - format!("{}-{}", loline, hiline) - } + if loline == hiline { loline.to_string() } else { format!("{loline}-{hiline}") } ) } else { "".to_string() @@ -855,12 +850,12 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // If the item is a macro, redirect from the old macro URL (with !) // to the new one (without). if item_type == ItemType::Macro { - let redir_name = format!("{}.{}!.html", item_type, name); + let redir_name = format!("{item_type}.{name}!.html"); if let Some(ref redirections) = self.shared.redirections { let crate_name = &self.shared.layout.krate; redirections.borrow_mut().insert( - format!("{}/{}", crate_name, redir_name), - format!("{}/{}", crate_name, file_name), + format!("{crate_name}/{redir_name}"), + format!("{crate_name}/{file_name}"), ); } else { let v = layout::redirect(file_name); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8a6e0b1ed51f..f03aaf059058 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -85,7 +85,7 @@ use crate::DOC_RUST_LANG_ORG_CHANNEL; pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { crate::html::format::display_fn(move |f| { - if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) } + if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) } }) } @@ -416,7 +416,7 @@ fn document<'a, 'cx: 'a>( heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { if let Some(ref name) = item.name { - info!("Documenting {}", name); + info!("Documenting {name}"); } display_fn(move |f| { @@ -513,7 +513,7 @@ fn document_full_inner<'a, 'cx: 'a>( ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(move |f| { if let Some(s) = item.opt_doc_value() { - debug!("Doc block: =====\n{}\n=====", s); + debug!("Doc block: =====\n{s}\n====="); if is_collapsible { write!( f, @@ -565,12 +565,10 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option( ) -> impl fmt::Display + Captures<'a> + Captures<'b> { crate::html::format::display_fn(move |f| { for a in it.attributes(tcx, false) { - writeln!(f, "{}{}", prefix, a)?; + writeln!(f, "{prefix}{a}")?; } Ok(()) }) @@ -1245,7 +1243,7 @@ fn render_deref_methods( _ => None, }) .expect("Expected associated type binding"); - debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target); + debug!("Render deref methods for {:#?}, target {target:#?}", impl_.inner_impl().for_); let what = AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut }; if let Some(did) = target.def_id(cache) { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cfced799f1ec..f07c93ca58e7 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -310,9 +310,8 @@ fn toggle_open(mut w: impl fmt::Write, text: impl fmt::Display) { w, "
    \ \ - Show {}\ + Show {text}\ ", - text ) .unwrap(); } @@ -412,7 +411,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: ) }); - debug!("{:?}", indices); + debug!("{indices:?}"); let mut last_section = None; for &idx in &indices { @@ -431,8 +430,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: w, "

    \ {name}\ -

    {}", - ITEM_TABLE_OPEN, + {ITEM_TABLE_OPEN}", id = cx.derive_id(my_section.id()), name = my_section.name(), ); @@ -485,7 +483,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: w.write_str(ITEM_TABLE_ROW_OPEN); let id = match import.kind { clean::ImportKind::Simple(s) => { - format!(" id=\"{}\"", cx.derive_id(format!("reexport.{}", s))) + format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}"))) } clean::ImportKind::Glob => String::new(), }; @@ -583,10 +581,8 @@ fn extra_info_tags<'a, 'tcx: 'a>( display_fn(move |f| { write!( f, - r#"{}"#, - class, + r#"{contents}"#, Escape(title), - contents ) }) } @@ -614,7 +610,7 @@ fn extra_info_tags<'a, 'tcx: 'a>( (cfg, _) => cfg.as_deref().cloned(), }; - debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg); + debug!("Portability name={:?} {:?} - {:?} = {cfg:?}", item.name, item.cfg, parent.cfg); if let Some(ref cfg) = cfg { write!( f, @@ -689,14 +685,13 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: wrap_item(w, |mut w| { write!( w, - "{attrs}{}{}{}trait {}{}{}", - visibility_print_with_space(it.visibility(tcx), it.item_id, cx), - t.unsafety(tcx).print_with_space(), - if t.is_auto(tcx) { "auto " } else { "" }, - it.name.unwrap(), - t.generics.print(cx), - bounds, + "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}", attrs = render_attributes_in_pre(it, "", tcx), + vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), + unsafety = t.unsafety(tcx).print_with_space(), + is_auto = if t.is_auto(tcx) { "auto " } else { "" }, + name = it.name.unwrap(), + generics = t.generics.print(cx), ); if !t.generics.where_predicates.is_empty() { @@ -742,10 +737,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: toggle_open( &mut w, format_args!( - "{} associated constant{} and {} method{}", - count_consts, + "{count_consts} associated constant{} and {count_methods} method{}", pluralize(count_consts), - count_methods, pluralize(count_methods), ), ); @@ -768,7 +761,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } if !toggle && should_hide_fields(count_methods) { toggle = true; - toggle_open(&mut w, format_args!("{} methods", count_methods)); + toggle_open(&mut w, format_args!("{count_methods} methods")); } if count_consts != 0 && count_methods != 0 { w.write_str("\n"); @@ -837,9 +830,9 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::Item) { let name = m.name.unwrap(); - info!("Documenting {} on {:?}", name, t.name); + info!("Documenting {name} on {:?}", t.name); let item_type = m.type_(); - let id = cx.derive_id(format!("{}.{}", item_type, name)); + let id = cx.derive_id(format!("{item_type}.{name}")); let mut content = Buffer::empty_from(w); write!(&mut content, "{}", document(cx, m, Some(t), HeadingOffset::H5)); let toggled = !content.is_empty(); @@ -847,7 +840,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; write!(w, "
    "); } - write!(w, "
    ", id); + write!(w, "
    "); render_rightside(w, cx, m, t, RenderMode::Normal); write!(w, "

    "); render_assoc_item( @@ -1170,12 +1163,12 @@ fn item_trait_alias( wrap_item(w, |w| { write!( w, - "{attrs}trait {}{}{} = {};", - it.name.unwrap(), - t.generics.print(cx), - print_where_clause(&t.generics, cx, 0, Ending::Newline), - bounds(&t.bounds, true, cx), + "{attrs}trait {name}{generics}{where_b} = {bounds};", attrs = render_attributes_in_pre(it, "", cx.tcx()), + name = it.name.unwrap(), + generics = t.generics.print(cx), + where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline), + bounds = bounds(&t.bounds, true, cx), ) .unwrap(); }); @@ -1198,12 +1191,12 @@ fn item_opaque_ty( wrap_item(w, |w| { write!( w, - "{attrs}type {}{}{where_clause} = impl {bounds};", - it.name.unwrap(), - t.generics.print(cx), + "{attrs}type {name}{generics}{where_clause} = impl {bounds};", + attrs = render_attributes_in_pre(it, "", cx.tcx()), + name = it.name.unwrap(), + generics = t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), bounds = bounds(&t.bounds, false, cx), - attrs = render_attributes_in_pre(it, "", cx.tcx()), ) .unwrap(); }); @@ -1223,13 +1216,13 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea wrap_item(w, |w| { write!( w, - "{attrs}{}type {}{}{where_clause} = {type_};", - visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), - it.name.unwrap(), - t.generics.print(cx), + "{attrs}{vis}type {name}{generics}{where_clause} = {type_};", + attrs = render_attributes_in_pre(it, "", cx.tcx()), + vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), + name = it.name.unwrap(), + generics = t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), type_ = t.type_.print(cx), - attrs = render_attributes_in_pre(it, "", cx.tcx()), ); }); } @@ -1354,7 +1347,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w.write_str("{\n"); let toggle = should_hide_fields(count_variants); if toggle { - toggle_open(&mut w, format_args!("{} variants", count_variants)); + toggle_open(&mut w, format_args!("{count_variants} variants")); } for v in e.variants() { w.write_str(" "); @@ -1362,7 +1355,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: match *v.kind { // FIXME(#101337): Show discriminant clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => write!(w, "{}", name), + clean::VariantKind::CLike => w.write_str(name.as_str()), clean::VariantKind::Tuple(ref s) => { write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); } @@ -1418,7 +1411,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; if let clean::VariantKind::Tuple(ref s) = variant_data.kind { - write!(w, "({})", print_tuple_struct_fields(cx, s),); + write!(w, "({})", print_tuple_struct_fields(cx, s)); } w.write_str("

    "); @@ -1617,7 +1610,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean for (index, (field, ty)) in fields.enumerate() { let field_name = field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); - let id = cx.derive_id(format!("{}.{}", ItemType::StructField, field_name)); + let id = cx.derive_id(format!("{}.{field_name}", ItemType::StructField)); write!( w, "\ @@ -1722,7 +1715,7 @@ pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { pub(super) fn item_path(ty: ItemType, name: &str) -> String { match ty { ItemType::Module => format!("{}index.html", ensure_trailing_slash(name)), - _ => format!("{}.{}.html", ty, name), + _ => format!("{ty}.{name}.html"), } } @@ -1845,7 +1838,7 @@ fn render_union<'a, 'cx: 'a>( fields.iter().filter(|field| matches!(*field.kind, clean::StructFieldItem(..))).count(); let toggle = should_hide_fields(count_fields); if toggle { - toggle_open(&mut f, format_args!("{} fields", count_fields)); + toggle_open(&mut f, format_args!("{count_fields} fields")); } for field in fields { @@ -1908,14 +1901,13 @@ fn render_struct( let has_visible_fields = count_fields > 0; let toggle = should_hide_fields(count_fields); if toggle { - toggle_open(&mut w, format_args!("{} fields", count_fields)); + toggle_open(&mut w, format_args!("{count_fields} fields")); } for field in fields { if let clean::StructFieldItem(ref ty) = *field.kind { write!( w, - "\n{} {}{}: {},", - tab, + "\n{tab} {}{}: {},", visibility_print_with_space(field.visibility(tcx), field.item_id, cx), field.name.unwrap(), ty.print(cx), @@ -1925,9 +1917,9 @@ fn render_struct( if has_visible_fields { if it.has_stripped_entries().unwrap() { - write!(w, "\n{} /* private fields */", tab); + write!(w, "\n{tab} /* private fields */"); } - write!(w, "\n{}", tab); + write!(w, "\n{tab}"); } else if it.has_stripped_entries().unwrap() { write!(w, " /* private fields */ "); } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 455b4e9aefe5..e958721dc556 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -330,7 +330,7 @@ fn sidebar_deref_methods<'a>( ) { let c = cx.cache(); - debug!("found Deref: {:?}", impl_); + debug!("found Deref: {impl_:?}"); if let Some((target, real_target)) = impl_.inner_impl().items.iter().find_map(|item| match *item.kind { clean::AssocTypeItem(box ref t, _) => Some(match *t { @@ -340,7 +340,7 @@ fn sidebar_deref_methods<'a>( _ => None, }) { - debug!("found target, real_target: {:?} {:?}", target, real_target); + debug!("found target, real_target: {target:?} {real_target:?}"); if let Some(did) = target.def_id(c) && let Some(type_did) = impl_.inner_impl().for_.def_id(c) && // `impl Deref for S` @@ -357,7 +357,7 @@ fn sidebar_deref_methods<'a>( }) .and_then(|did| c.impls.get(&did)); if let Some(impls) = inner_impl { - debug!("found inner_impl: {:?}", impls); + debug!("found inner_impl: {impls:?}"); let mut ret = impls .iter() .filter(|i| i.inner_impl().trait_.is_none()) @@ -510,10 +510,10 @@ fn get_next_url(used_links: &mut FxHashSet, url: String) -> String { return url; } let mut add = 1; - while !used_links.insert(format!("{}-{}", url, add)) { + while !used_links.insert(format!("{url}-{add}")) { add += 1; } - format!("{}-{}", url, add) + format!("{url}-{add}") } fn get_methods<'a>( @@ -529,7 +529,7 @@ fn get_methods<'a>( Some(ref name) if !name.is_empty() && item.is_method() => { if !for_deref || super::should_render_item(item, deref_mut, tcx) { Some(Link::new( - get_next_url(used_links, format!("{}.{}", ItemType::Method, name)), + get_next_url(used_links, format!("{}.{name}", ItemType::Method)), name.as_str(), )) } else { @@ -549,7 +549,7 @@ fn get_associated_constants<'a>( .iter() .filter_map(|item| match item.name { Some(ref name) if !name.is_empty() && item.is_associated_const() => Some(Link::new( - get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)), + get_next_url(used_links, format!("{}.{name}", ItemType::AssocConst)), name.as_str(), )), _ => None, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 3f41765a5afb..2a37577b22b0 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -73,7 +73,7 @@ pub(super) fn write_shared( } let bytes = try_err!(fs::read(&entry.path), &entry.path); - let filename = format!("{}{}.{}", theme, cx.shared.resource_suffix, extension); + let filename = format!("{theme}{}.{extension}", cx.shared.resource_suffix); cx.shared.fs.write(cx.dst.join(filename), bytes)?; } @@ -112,7 +112,7 @@ pub(super) fn write_shared( let mut krates = Vec::new(); if path.exists() { - let prefix = format!("\"{}\"", krate); + let prefix = format!("\"{krate}\""); for line in BufReader::new(File::open(path)?).lines() { let line = line?; if !line.starts_with('"') { @@ -157,7 +157,7 @@ pub(super) fn write_shared( let mut krates = Vec::new(); if path.exists() { - let prefix = format!("\"{}\"", krate); + let prefix = format!("\"{krate}\""); for line in BufReader::new(File::open(path)?).lines() { let line = line?; if !line.starts_with('"') { @@ -213,10 +213,10 @@ pub(super) fn write_shared( let dirs = if subs.is_empty() && files.is_empty() { String::new() } else { - format!(",[{}]", subs) + format!(",[{subs}]") }; let files = files.join(","); - let files = if files.is_empty() { String::new() } else { format!(",[{}]", files) }; + let files = if files.is_empty() { String::new() } else { format!(",[{files}]") }; format!( "[\"{name}\"{dirs}{files}]", name = self.elem.to_str().expect("invalid osstring conversion"), @@ -319,8 +319,8 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; })?; write_invocation_specific("crates.js", &|| { - let krates = krates.iter().map(|k| format!("\"{}\"", k)).join(","); - Ok(format!("window.ALL_CRATES = [{}];", krates).into_bytes()) + let krates = krates.iter().map(|k| format!("\"{k}\"")).join(","); + Ok(format!("window.ALL_CRATES = [{krates}];").into_bytes()) })?; if options.enable_index_page { @@ -349,9 +349,8 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; .iter() .map(|s| { format!( - "
  3. {}
  4. ", + "
  5. {s}
  6. ", ensure_trailing_slash(s), - s ) }) .collect::() @@ -444,7 +443,7 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; mydst.push(part.to_string()); } cx.shared.ensure_dir(&mydst)?; - mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1])); + mydst.push(&format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); let (mut all_implementors, _) = try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst); diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 3e3fc8a0e720..5a221c0e1c79 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -146,9 +146,8 @@ impl DocVisitor for SourceCollector<'_, '_> { self.cx.shared.tcx.sess.span_err( span, format!( - "failed to render source code for `{}`: {}", + "failed to render source code for `{}`: {e}", filename.prefer_local(), - e, ), ); false diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 5d2e4b073c1f..a27aa2b58d24 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -53,7 +53,7 @@ pub(crate) fn suffix_path(filename: &str, suffix: &str) -> PathBuf { // which would result in `style.min-suffix.css` which isn't what we // want. let (base, ext) = filename.split_once('.').unwrap(); - let filename = format!("{}{}.{}", base, suffix, ext); + let filename = format!("{base}{suffix}.{ext}"); filename.into() } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 9392dd4d0882..cd791ce000bf 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -139,7 +139,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { fn item(&mut self, item: clean::Item) -> Result<(), Error> { let item_type = item.type_(); let item_name = item.name; - trace!("rendering {} {:?}", item_type, item_name); + trace!("rendering {item_type} {item_name:?}"); // Flatten items that recursively store other items. We include orphaned items from // stripped modules and etc that are otherwise reachable. @@ -203,11 +203,11 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { if !can_be_ignored { assert_eq!(old_item, new_item); } - trace!("replaced {:?}\nwith {:?}", old_item, new_item); + trace!("replaced {old_item:?}\nwith {new_item:?}"); } } - trace!("done rendering {} {:?}", item_type, item_name); + trace!("done rendering {item_type} {item_name:?}"); Ok(()) } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 36d087a7d5be..8220df5d4f37 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -192,8 +192,7 @@ fn init_logging(handler: &EarlyErrorHandler) { Ok("never") => false, Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(), Ok(value) => handler.early_error(format!( - "invalid log color value '{}': expected one of always, never, or auto", - value + "invalid log color value '{value}': expected one of always, never, or auto", )), Err(VarError::NotUnicode(value)) => handler.early_error(format!( "invalid log color value '{}': expected one of always, never, or auto", @@ -224,7 +223,7 @@ fn get_args(handler: &EarlyErrorHandler) -> Option> { .map(|(i, arg)| { arg.into_string() .map_err(|arg| { - handler.early_warn(format!("Argument {} is not valid Unicode: {:?}", i, arg)); + handler.early_warn(format!("Argument {i} is not valid Unicode: {arg:?}")); }) .ok() }) @@ -665,11 +664,10 @@ fn usage(argv0: &str) { for option in opts() { (option.apply)(&mut options); } - println!("{}", options.usage(&format!("{} [options] ", argv0))); + println!("{}", options.usage(&format!("{argv0} [options] "))); println!(" @path Read newline separated options from `path`\n"); println!( - "More information available at {}/rustdoc/what-is-rustdoc.html", - DOC_RUST_LANG_ORG_CHANNEL + "More information available at {DOC_RUST_LANG_ORG_CHANNEL}/rustdoc/what-is-rustdoc.html", ); } @@ -699,7 +697,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( tcx.sess.struct_err(format!("couldn't generate documentation: {}", e.error)); let file = e.file.display().to_string(); if !file.is_empty() { - msg.note(format!("failed to create or modify \"{}\"", file)); + msg.note(format!("failed to create or modify \"{file}\"")); } Err(msg.emit()) } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 4321d4aa343d..ca84b9152232 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -43,7 +43,7 @@ pub(crate) fn render>( edition: Edition, ) -> Result<(), String> { if let Err(e) = create_dir_all(&options.output) { - return Err(format!("{}: {}", options.output.display(), e)); + return Err(format!("{}: {e}", options.output.display())); } let input = input.as_ref(); @@ -57,11 +57,11 @@ pub(crate) fn render>( .expect("Writing to a String can't fail"); } - let input_str = read_to_string(input).map_err(|err| format!("{}: {}", input.display(), err))?; + let input_str = read_to_string(input).map_err(|err| format!("{}: {err}", input.display()))?; let playground_url = options.markdown_playground_url.or(options.playground_url); let playground = playground_url.map(|url| markdown::Playground { crate_name: None, url }); - let mut out = File::create(&output).map_err(|e| format!("{}: {}", output.display(), e))?; + let mut out = File::create(&output).map_err(|e| format!("{}: {e}", output.display()))?; let (metadata, text) = extract_leading_metadata(&input_str); if metadata.is_empty() { @@ -129,7 +129,7 @@ pub(crate) fn render>( ); match err { - Err(e) => Err(format!("cannot write to `{}`: {}", output.display(), e)), + Err(e) => Err(format!("cannot write to `{}`: {e}", output.display())), Ok(_) => Ok(()), } } @@ -137,7 +137,7 @@ pub(crate) fn render>( /// Runs any tests/code examples in the markdown file `input`. pub(crate) fn test(options: Options) -> Result<(), String> { let input_str = read_to_string(&options.input) - .map_err(|err| format!("{}: {}", options.input.display(), err))?; + .map_err(|err| format!("{}: {err}", options.input.display()))?; let mut opts = GlobalTestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new( diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 6ead0cd961a3..305d2e7c162f 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -146,8 +146,8 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { examples_percentage: f64, ) { println!( - "| {:<35} | {:>10} | {:>9.1}% | {:>10} | {:>9.1}% |", - name, count.with_docs, percentage, count.with_examples, examples_percentage, + "| {name:<35} | {:>10} | {percentage:>9.1}% | {:>10} | {:>9.1}% |", + count.with_docs, count.with_examples, examples_percentage, ); } @@ -249,7 +249,7 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> { if let Some(span) = i.span(self.ctx.tcx) { let filename = span.filename(self.ctx.sess()); - debug!("counting {:?} {:?} in {:?}", i.type_(), i.name, filename); + debug!("counting {:?} {:?} in {filename:?}", i.type_(), i.name); self.items.entry(filename).or_default().count_item( has_docs, has_doc_example, diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index e333a35e8ad2..e732a4057606 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -117,7 +117,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples { if should_have_doc_example(cx, item) { - debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); + debug!("reporting error for {item:?} (hir_id={hir_id:?})"); let sp = item.attr_span(cx.tcx); cx.tcx.struct_span_lint_hir( crate::lint::MISSING_DOC_CODE_EXAMPLES, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1b8d999024c4..f21b0999e87e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -150,7 +150,7 @@ impl TryFrom for Res { PrimTy(prim) => Ok(Res::Primitive(PrimitiveType::from_hir(prim))), // e.g. `#[derive]` ToolMod | NonMacroAttr(..) | Err => Result::Err(()), - other => bug!("unrecognized res {:?}", other), + other => bug!("unrecognized res {other:?}"), } } } @@ -224,7 +224,7 @@ impl UrlFragment { "structfield." } } - kind => bug!("unexpected associated item kind: {:?}", kind), + kind => bug!("unexpected associated item kind: {kind:?}"), }; s.push_str(kind); s.push_str(tcx.item_name(def_id).as_str()); @@ -279,7 +279,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { unresolved: path_str.into(), }; - debug!("looking for enum variant {}", path_str); + debug!("looking for enum variant {path_str}"); let mut split = path_str.rsplitn(3, "::"); let variant_field_name = split .next() @@ -410,7 +410,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) .and_then(|res| res.try_into().ok()) .or_else(|| resolve_primitive(path_str, ns)); - debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); + debug!("{path_str} resolved to {result:?} in namespace {ns:?}"); result } @@ -453,7 +453,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // If there's no `::`, it's not an associated item. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. .ok_or_else(|| { - debug!("found no `::`, assuming {} was correctly not in scope", item_name); + debug!("found no `::`, assuming {item_name} was correctly not in scope"); UnresolvedPath { item_id, module_id, @@ -603,7 +603,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy), did, ) => { - debug!("looking for associated item named {} for item {:?}", item_name, did); + debug!("looking for associated item named {item_name} for item {did:?}"); // Checks if item_name is a variant of the `SomeItem` enum if ns == TypeNS && def_kind == DefKind::Enum { match tcx.type_of(did).instantiate_identity().kind() { @@ -651,7 +651,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .collect::>(); } - debug!("got associated item {:?}", assoc_items); + debug!("got associated item {assoc_items:?}"); if !assoc_items.is_empty() { return assoc_items; @@ -660,7 +660,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if ns != Namespace::ValueNS { return Vec::new(); } - debug!("looking for fields named {} for {:?}", item_name, did); + debug!("looking for fields named {item_name} for {did:?}"); // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) // NOTE: it's different from variant_field because it only resolves struct fields, // not variant fields (2 path segments, not 3). @@ -727,7 +727,7 @@ fn resolve_associated_trait_item<'a>( // Give precedence to inherent impls. let traits = trait_impls_for(cx, ty, module); let tcx = cx.tcx; - debug!("considering traits {:?}", traits); + debug!("considering traits {traits:?}"); let candidates = traits .iter() .flat_map(|&(impl_, trait_)| { @@ -744,7 +744,7 @@ fn resolve_associated_trait_item<'a>( }) .collect::>(); // FIXME(#74563): warn about ambiguity - debug!("the candidates were {:?}", candidates); + debug!("the candidates were {candidates:?}"); candidates } @@ -790,10 +790,8 @@ fn trait_impls_for<'a>( // Check if these are the same type. let impl_type = trait_ref.skip_binder().self_ty(); trace!( - "comparing type {} with kind {:?} against type {:?}", - impl_type, + "comparing type {impl_type} with kind {:?} against type {ty:?}", impl_type.kind(), - ty ); // Fast path: if this is a primitive simple `==` will work // NOTE: the `match` is necessary; see #92662. @@ -940,7 +938,7 @@ fn preprocess_link( let path_str = match strip_generics_from_path(path_str) { Ok(path) => path, Err(err) => { - debug!("link has malformed generics: {}", path_str); + debug!("link has malformed generics: {path_str}"); return Some(Err(PreprocessingError::MalformedGenerics(err, path_str.to_owned()))); } }; @@ -987,7 +985,7 @@ impl LinkCollector<'_, '_> { if !may_have_doc_links(&doc) { continue; } - debug!("combined_docs={}", doc); + debug!("combined_docs={doc}"); // NOTE: if there are links that start in one crate and end in another, this will not resolve them. // This is a degenerate case and it's not supported by rustdoc. let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); @@ -1130,10 +1128,10 @@ impl LinkCollector<'_, '_> { item: &Item, diag_info: &DiagnosticInfo<'_>, ) -> Option<()> { - debug!("intra-doc link to {} resolved to {:?}", path_str, (kind, id)); + debug!("intra-doc link to {path_str} resolved to {:?}", (kind, id)); // Disallow e.g. linking to enums with `struct@` - debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); + debug!("saw kind {kind:?} with disambiguator {disambiguator:?}"); match (kind, disambiguator) { | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) // NOTE: this allows 'method' to mean both normal functions and associated functions @@ -1174,7 +1172,7 @@ impl LinkCollector<'_, '_> { diag_info: &DiagnosticInfo<'_>, ) { // The resolved item did not match the disambiguator; give a better error than 'not found' - let msg = format!("incompatible link kind for `{}`", path_str); + let msg = format!("incompatible link kind for `{path_str}`"); let callback = |diag: &mut Diagnostic, sp: Option, link_range| { let note = format!( "this link resolved to {} {}, which is not {} {}", @@ -1459,7 +1457,7 @@ impl Disambiguator { "value" => NS(Namespace::ValueNS), "macro" => NS(Namespace::MacroNS), "prim" | "primitive" => Primitive, - _ => return Err((format!("unknown disambiguator `{}`", prefix), 0..idx)), + _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)), }; Ok(Some((d, &rest[1..], &rest[1..]))) } else { @@ -1527,7 +1525,7 @@ enum Suggestion { impl Suggestion { fn descr(&self) -> Cow<'static, str> { match self { - Self::Prefix(x) => format!("prefix with `{}@`", x).into(), + Self::Prefix(x) => format!("prefix with `{x}@`").into(), Self::Function => "add parentheses".into(), Self::Macro => "add an exclamation mark".into(), Self::RemoveDisambiguator => "remove the disambiguator".into(), @@ -1537,9 +1535,9 @@ impl Suggestion { fn as_help(&self, path_str: &str) -> String { // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` match self { - Self::Prefix(prefix) => format!("{}@{}", prefix, path_str), - Self::Function => format!("{}()", path_str), - Self::Macro => format!("{}!", path_str), + Self::Prefix(prefix) => format!("{prefix}@{path_str}"), + Self::Function => format!("{path_str}()"), + Self::Macro => format!("{path_str}!"), Self::RemoveDisambiguator => path_str.into(), } } @@ -1574,7 +1572,7 @@ impl Suggestion { match self { Self::Prefix(prefix) => { // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` - let mut sugg = vec![(sp.with_hi(inner_sp.lo()), format!("{}@", prefix))]; + let mut sugg = vec![(sp.with_hi(inner_sp.lo()), format!("{prefix}@"))]; if sp.hi() != inner_sp.hi() { sugg.push((inner_sp.shrink_to_hi().with_hi(sp.hi()), String::new())); } @@ -1618,7 +1616,7 @@ fn report_diagnostic( ) { let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else { // If non-local, no need to check anything. - info!("ignoring warning from parent crate: {}", msg); + info!("ignoring warning from parent crate: {msg}"); return; }; @@ -1696,15 +1694,14 @@ fn resolution_failure( report_diagnostic( tcx, BROKEN_INTRA_DOC_LINKS, - format!("unresolved link to `{}`", path_str), + format!("unresolved link to `{path_str}`"), &diag_info, |diag, sp, link_range| { - let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),); + let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx)); let assoc_item_not_allowed = |res: Res| { let name = res.name(tcx); format!( - "`{}` is {} {}, not a module or type, and cannot have associated items", - name, + "`{name}` is {} {}, not a module or type, and cannot have associated items", res.article(), res.descr() ) @@ -1750,7 +1747,7 @@ fn resolution_failure( name = start; for ns in [TypeNS, ValueNS, MacroNS] { if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) { - debug!("found partial_res={:?}", v_res); + debug!("found partial_res={v_res:?}"); if !v_res.is_empty() { *partial_res = Some(full_res(tcx, v_res[0])); *unresolved = end.into(); @@ -1771,10 +1768,10 @@ fn resolution_failure( let note = if partial_res.is_some() { // Part of the link resolved; e.g. `std::io::nonexistent` let module_name = tcx.item_name(module); - format!("no item named `{}` in module `{}`", unresolved, module_name) + format!("no item named `{unresolved}` in module `{module_name}`") } else { // None of the link resolved; e.g. `Notimported` - format!("no item named `{}` in scope", unresolved) + format!("no item named `{unresolved}` in scope") }; if let Some(span) = sp { diag.span_label(span, note); @@ -1879,11 +1876,9 @@ fn resolution_failure( }; let name = res.name(tcx); let note = format!( - "the {} `{}` has no {} named `{}`", + "the {} `{name}` has no {} named `{unresolved}`", res.descr(), - name, disambiguator.map_or(path_description, |d| d.descr()), - unresolved, ); if let Some(span) = sp { diag.span_label(span, note); @@ -1978,7 +1973,7 @@ fn report_malformed_generics( report_diagnostic( cx.tcx, BROKEN_INTRA_DOC_LINKS, - format!("unresolved link to `{}`", path_str), + format!("unresolved link to `{path_str}`"), &diag_info, |diag, sp, _link_range| { let note = match err { @@ -2030,7 +2025,7 @@ fn ambiguity_error( return false; } - let mut msg = format!("`{}` is ", path_str); + let mut msg = format!("`{path_str}` is "); match kinds.as_slice() { [res1, res2] => { msg += &format!( @@ -2094,7 +2089,7 @@ fn suggest_disambiguator( diag.span_suggestion_verbose(sp, help, suggestion_text, Applicability::MaybeIncorrect); } } else { - diag.help(format!("{}: {}", help, suggestion.as_help(path_str))); + diag.help(format!("{help}: {}", suggestion.as_help(path_str))); } } @@ -2108,8 +2103,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: } None => "", }; - let msg = - format!("public documentation for `{}` links to private item `{}`", item_name, path_str); + let msg = format!("public documentation for `{item_name}` links to private item `{path_str}`"); report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, _link_range| { if let Some(sp) = sp { @@ -2160,6 +2154,6 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option { "never" | "!" => Never, _ => return None, }; - debug!("resolved primitives {:?}", prim); + debug!("resolved primitives {prim:?}"); Some(Res::Primitive(prim)) } diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 5658b31d9bb9..97078a5cb161 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -28,7 +28,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { .span_suggestion( sp, "use an automatic link instead", - format!("<{}>", url), + format!("<{url}>"), Applicability::MachineApplicable, ) }); @@ -74,7 +74,7 @@ fn find_raw_urls( range: Range, f: &impl Fn(&DocContext<'_>, &'static str, &str, Range), ) { - trace!("looking for raw urls in {}", text); + trace!("looking for raw urls in {text}"); // For now, we only check "full" URLs (meaning, starting with "http://" or "https://"). for match_ in URL_REGEX.find_iter(text) { let url = match_.as_str(); diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 8e5ee382c86d..37e28e1fbcab 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -107,7 +107,7 @@ fn check_rust_syntax( // just give a `help` instead. lint.span_help( sp.from_inner(InnerSpan::new(0, 3)), - format!("{}: ```text", explanation), + format!("{explanation}: ```text"), ); } else if empty_block { lint.span_suggestion( @@ -118,7 +118,7 @@ fn check_rust_syntax( ); } } else if empty_block || is_ignore { - lint.help(format!("{}: ```text", explanation)); + lint.help(format!("{explanation}: ```text")); } // FIXME(#67563): Provide more context for these errors by displaying the spans inline. @@ -160,7 +160,7 @@ impl Emitter for BufferEmitter { .translate_message(&diag.message[0].0, &fluent_args) .unwrap_or_else(|e| panic!("{e}")); - buffer.messages.push(format!("error from rustc: {}", translated_main_message)); + buffer.messages.push(format!("error from rustc: {translated_main_message}")); if diag.is_error() { buffer.has_errors = true; } diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 24f452b216c2..c135c584cec4 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -155,7 +155,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { let t = t.to_lowercase(); !ALLOWED_UNCLOSED.contains(&t.as_str()) }) { - report_diag(format!("unclosed HTML tag `{}`", tag), range, true); + report_diag(format!("unclosed HTML tag `{tag}`"), range, true); } if let Some(range) = is_in_comment { @@ -194,14 +194,14 @@ fn drop_tag( // `tags` is used as a queue, meaning that everything after `pos` is included inside it. // So `

    ` will look like `["h2", "h3"]`. So when closing `h2`, we will still // have `h3`, meaning the tag wasn't closed as it should have. - f(format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true); + f(format!("unclosed HTML tag `{last_tag_name}`"), &last_tag_span, true); } // Remove the `tag_name` that was originally closed tags.pop(); } else { // It can happen for example in this case: `

    ` (the `h2` tag isn't required // but it helps for the visualization). - f(format!("unopened HTML tag `{}`", tag_name), &range, false); + f(format!("unopened HTML tag `{tag_name}`"), &range, false); } } @@ -355,7 +355,7 @@ fn extract_html_tag( if let Some(quote_pos) = quote_pos { let qr = Range { start: quote_pos, end: quote_pos }; f( - format!("unclosed quoted HTML attribute on tag `{}`", tag_name), + format!("unclosed quoted HTML attribute on tag `{tag_name}`"), &qr, false, ); @@ -368,7 +368,7 @@ fn extract_html_tag( at == "svg" || at == "math" }); if !valid { - f(format!("invalid self-closing HTML tag `{}`", tag_name), &r, false); + f(format!("invalid self-closing HTML tag `{tag_name}`"), &r, false); } } else { tags.push((tag_name, r)); diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 647d83588401..534c6eebbdd5 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -255,7 +255,7 @@ where let fn_key = tcx.def_path_hash(*def_id); let fn_entries = self.calls.entry(fn_key).or_default(); - trace!("Including expr: {:?}", call_span); + trace!("Including expr: {call_span:?}"); let enclosing_item_span = source_map.span_extend_to_prev_char(enclosing_item_span, '\n', false); let location = @@ -345,7 +345,7 @@ pub(crate) fn load_call_locations( let inner = || { let mut all_calls: AllCallLocations = FxHashMap::default(); for path in with_examples { - let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?; + let bytes = fs::read(&path).map_err(|e| format!("{e} (for path {path})"))?; let mut decoder = MemDecoder::new(&bytes, 0); let calls = AllCallLocations::decode(&mut decoder); @@ -358,7 +358,7 @@ pub(crate) fn load_call_locations( }; inner().map_err(|e: String| { - diag.err(format!("failed to load examples: {}", e)); + diag.err(format!("failed to load examples: {e}")); 1 }) } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 3bad9ba4e4a7..549fd67e32ad 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -180,7 +180,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { /// 1. The items which are not glob imports/reexports. /// 2. The glob imports/reexports. fn visit_mod_contents(&mut self, def_id: LocalDefId, m: &'tcx hir::Mod<'tcx>) { - debug!("Going through module {:?}", m); + debug!("Going through module {m:?}"); // Keep track of if there were any private modules in the path. let orig_inside_public_path = self.inside_public_path; self.inside_public_path &= self.cx.tcx.local_visibility(def_id).is_public(); @@ -203,7 +203,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } self.inside_public_path = orig_inside_public_path; - debug!("Leaving module {:?}", m); + debug!("Leaving module {m:?}"); } /// Tries to resolve the target of a `pub use` statement and inlines the @@ -394,7 +394,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { renamed: Option, import_id: Option, ) { - debug!("visiting item {:?}", item); + debug!("visiting item {item:?}"); if self.inside_body { // Only impls can be "seen" outside a body. For example: // From 16b34bfae3f3a933b216dc6659ae4702168c723a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Aug 2023 14:27:29 +0200 Subject: [PATCH 043/169] Use more named format args --- src/librustdoc/clean/auto_trait.rs | 6 +-- src/librustdoc/clean/utils.rs | 24 +++++---- src/librustdoc/docfs.rs | 6 +-- src/librustdoc/externalfiles.rs | 6 ++- src/librustdoc/html/format.rs | 51 ++++++++++++------- src/librustdoc/html/highlight.rs | 12 +++-- src/librustdoc/html/markdown.rs | 12 ++--- src/librustdoc/html/render/context.rs | 13 +++-- src/librustdoc/html/render/mod.rs | 13 +++-- src/librustdoc/html/render/print_item.rs | 30 ++++++----- src/librustdoc/html/render/sidebar.rs | 4 +- src/librustdoc/html/render/write_shared.rs | 6 +-- src/librustdoc/html/sources.rs | 4 +- src/librustdoc/markdown.rs | 12 +++-- .../passes/calculate_doc_coverage.rs | 6 ++- .../passes/collect_intra_doc_links.rs | 10 ++-- 16 files changed, 130 insertions(+), 85 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index ec804bb98f01..a06f31a93291 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -163,9 +163,9 @@ where fn get_lifetime(region: Region<'_>, names_map: &FxHashMap) -> Lifetime { region_name(region) .map(|name| { - names_map.get(&name).unwrap_or_else(|| { - panic!("Missing lifetime with name {:?} for {region:?}", name.as_str()) - }) + names_map + .get(&name) + .unwrap_or_else(|| panic!("Missing lifetime with name {name:?} for {region:?}")) }) .unwrap_or(&Lifetime::statik()) .clone() diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a973538073c0..80a7a33d2bda 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -601,8 +601,12 @@ pub(super) fn render_macro_arms<'a>( ) -> String { let mut out = String::new(); for matcher in matchers { - writeln!(out, " {} => {{ ... }}{arm_delim}", render_macro_matcher(tcx, matcher)) - .unwrap(); + writeln!( + out, + " {matcher} => {{ ... }}{arm_delim}", + matcher = render_macro_matcher(tcx, matcher), + ) + .unwrap(); } out } @@ -618,19 +622,21 @@ pub(super) fn display_macro_source( let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]); if def.macro_rules { - format!("macro_rules! {name} {{\n{}}}", render_macro_arms(cx.tcx, matchers, ";")) + format!("macro_rules! {name} {{\n{arms}}}", arms = render_macro_arms(cx.tcx, matchers, ";")) } else { if matchers.len() <= 1 { format!( - "{}macro {name}{} {{\n ...\n}}", - visibility_to_src_with_space(Some(vis), cx.tcx, def_id), - matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::(), + "{vis}macro {name}{matchers} {{\n ...\n}}", + vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id), + matchers = matchers + .map(|matcher| render_macro_matcher(cx.tcx, matcher)) + .collect::(), ) } else { format!( - "{}macro {name} {{\n{}}}", - visibility_to_src_with_space(Some(vis), cx.tcx, def_id), - render_macro_arms(cx.tcx, matchers, ","), + "{vis}macro {name} {{\n{arms}}}", + vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id), + arms = render_macro_arms(cx.tcx, matchers, ","), ) } } diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs index 2962517badcf..82c1a503924c 100644 --- a/src/librustdoc/docfs.rs +++ b/src/librustdoc/docfs.rs @@ -72,9 +72,9 @@ impl DocFS { let sender = self.errors.clone().expect("can't write after closing"); self.pool.execute(move || { fs::write(&path, contents).unwrap_or_else(|e| { - sender.send(format!("\"{}\": {e}", path.display())).unwrap_or_else(|_| { - panic!("failed to send error on \"{}\"", path.display()) - }) + sender.send(format!("\"{path}\": {e}", path = path.display())).unwrap_or_else( + |_| panic!("failed to send error on \"{}\"", path.display()), + ) }); }); } else { diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index ada5f0fadacb..f0ebb8e5a390 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -81,7 +81,11 @@ pub(crate) fn load_string>( let contents = match fs::read(file_path) { Ok(bytes) => bytes, Err(e) => { - diag.struct_err(format!("error reading `{}`: {e}", file_path.display())).emit(); + diag.struct_err(format!( + "error reading `{file_path}`: {e}", + file_path = file_path.display() + )) + .emit(); return Err(LoadStringError::ReadFail); } }; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index b00b48c5d64c..2f611c31a074 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -109,6 +109,10 @@ impl Buffer { self.buffer } + pub(crate) fn push(&mut self, c: char) { + self.buffer.push(c); + } + pub(crate) fn push_str(&mut self, s: &str) { self.buffer.push_str(s); } @@ -451,9 +455,9 @@ impl clean::GenericBound { hir::TraitBoundModifier::MaybeConst => "", }; if f.alternate() { - write!(f, "{modifier_str}{:#}", ty.print(cx)) + write!(f, "{modifier_str}{ty:#}", ty = ty.print(cx)) } else { - write!(f, "{modifier_str}{}", ty.print(cx)) + write!(f, "{modifier_str}{ty}", ty = ty.print(cx)) } } }) @@ -631,14 +635,14 @@ fn generate_macro_def_id_path( let url = match cache.extern_locations[&def_id.krate] { ExternalLocation::Remote(ref s) => { // `ExternalLocation::Remote` always end with a `/`. - format!("{s}{}", path.iter().map(|p| p.as_str()).join("/")) + format!("{s}{path}", path = path.iter().map(|p| p.as_str()).join("/")) } ExternalLocation::Local => { // `root_path` always end with a `/`. format!( - "{}{crate_name}/{}", - root_path.unwrap_or(""), - path.iter().map(|p| p.as_str()).join("/") + "{root_path}{crate_name}/{path}", + root_path = root_path.unwrap_or(""), + path = path.iter().map(|p| p.as_str()).join("/") ) } ExternalLocation::Unknown => { @@ -827,9 +831,9 @@ fn resolved_path<'cx>( let path = if use_absolute { if let Ok((_, _, fqp)) = href(did, cx) { format!( - "{}::{}", - join_with_double_colon(&fqp[..fqp.len() - 1]), - anchor(did, *fqp.last().unwrap(), cx) + "{path}::{anchor}", + path = join_with_double_colon(&fqp[..fqp.len() - 1]), + anchor = anchor(did, *fqp.last().unwrap(), cx) ) } else { last.name.to_string() @@ -837,7 +841,7 @@ fn resolved_path<'cx>( } else { anchor(did, last.name, cx).to_string() }; - write!(w, "{path}{}", last.args.print(cx))?; + write!(w, "{path}{args}", args = last.args.print(cx))?; } Ok(()) } @@ -945,8 +949,8 @@ pub(crate) fn anchor<'a, 'cx: 'a>( if let Ok((url, short_ty, fqp)) = parts { write!( f, - r#"{text}"#, - join_with_double_colon(&fqp), + r#"{text}"#, + path = join_with_double_colon(&fqp), ) } else { f.write_str(text.as_str()) @@ -1080,9 +1084,9 @@ fn fmt_type<'cx>( if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { let text = if f.alternate() { - format!("*{m} {:#}", t.print(cx)) + format!("*{m} {ty:#}", ty = t.print(cx)) } else { - format!("*{m} {}", t.print(cx)) + format!("*{m} {ty}", ty = t.print(cx)) }; primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx) } else { @@ -1440,11 +1444,20 @@ impl clean::FnDecl { clean::SelfValue => { write!(f, "self")?; } - clean::SelfBorrowed(Some(ref lt), mtbl) => { - write!(f, "{amp}{} {}self", lt.print(), mtbl.print_with_space())?; + clean::SelfBorrowed(Some(ref lt), mutability) => { + write!( + f, + "{amp}{lifetime} {mutability}self", + lifetime = lt.print(), + mutability = mutability.print_with_space(), + )?; } - clean::SelfBorrowed(None, mtbl) => { - write!(f, "{amp}{}self", mtbl.print_with_space())?; + clean::SelfBorrowed(None, mutability) => { + write!( + f, + "{amp}{mutability}self", + mutability = mutability.print_with_space(), + )?; } clean::SelfExplicit(ref typ) => { write!(f, "self: ")?; @@ -1627,7 +1640,7 @@ impl clean::Import { if name == self.source.path.last() { write!(f, "use {};", self.source.print(cx)) } else { - write!(f, "use {} as {name};", self.source.print(cx)) + write!(f, "use {source} as {name};", source = self.source.print(cx)) } } clean::ImportKind::Glob => { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index e5d1b2f060c0..039e8cdb9873 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -937,7 +937,7 @@ fn string_without_closing_tag( write!(out, "{text}").unwrap(); return None; } - write!(out, "{text}", klass.as_html()).unwrap(); + write!(out, "{text}", klass = klass.as_html()).unwrap(); return Some(""); }; @@ -947,11 +947,15 @@ fn string_without_closing_tag( match t { "self" | "Self" => write!( &mut path, - "{t}", - Class::Self_(DUMMY_SP).as_html(), + "{t}", + klass = Class::Self_(DUMMY_SP).as_html(), ), "crate" | "super" => { - write!(&mut path, "{t}", Class::KeyWord.as_html()) + write!( + &mut path, + "{t}", + klass = Class::KeyWord.as_html(), + ) } t => write!(&mut path, "{t}"), } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a31b228b7068..0ba2d992392e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -246,9 +246,9 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { return Some(Event::Html( format!( "
    \ -
    {}
    \ +
    {text}
    \
    ", - Escape(&original_text), + text = Escape(&original_text), ) .into(), )); @@ -308,7 +308,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { // insert newline to clearly separate it from the // previous block so we can shorten the html output let mut s = Buffer::new(); - s.push_str("\n"); + s.push('\n'); highlight::render_example_with_highlighting( &text, @@ -394,7 +394,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { l.href == link.href && Some(&**text) == l.original_text.get(1..l.original_text.len() - 1) }) { - debug!("replacing {text} with {}", link.new_text); + debug!("replacing {text} with {new_text}", new_text = link.new_text); *text = CowStr::Borrowed(&link.new_text); } } @@ -410,7 +410,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { .iter() .find(|l| l.href == link.href && **text == *l.original_text) { - debug!("replacing {text} with {}", link.new_text); + debug!("replacing {text} with {new_text}", new_text = link.new_text); *text = CowStr::Borrowed(&link.new_text); } } @@ -1038,7 +1038,7 @@ impl MarkdownWithToc<'_> { html::push_html(&mut s, p); } - format!("{s}", toc.into_toc().print()) + format!("{s}", toc = toc.into_toc().print()) } } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index f1d207d99e73..d7ff248a9bff 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -206,9 +206,9 @@ impl<'tcx> Context<'tcx> { format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate) } else { format!( - "API documentation for the Rust `{}` {tyname} in crate `{}`.", - it.name.as_ref().unwrap(), - self.shared.layout.krate + "API documentation for the Rust `{name}` {tyname} in crate `{krate}`.", + name = it.name.as_ref().unwrap(), + krate = self.shared.layout.krate, ) }; let name; @@ -263,7 +263,12 @@ impl<'tcx> Context<'tcx> { current_path.push_str(&item_path(ty, names.last().unwrap().as_str())); redirections.borrow_mut().insert(current_path, path); } - None => return layout::redirect(&format!("{}{path}", self.root_path())), + None => { + return layout::redirect(&format!( + "{root}{path}", + root = self.root_path() + )); + } } } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f03aaf059058..ac9c180a6a86 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -565,10 +565,10 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option None, }) .expect("Expected associated type binding"); - debug!("Render deref methods for {:#?}, target {target:#?}", impl_.inner_impl().for_); + debug!( + "Render deref methods for {for_:#?}, target {target:#?}", + for_ = impl_.inner_impl().for_ + ); let what = AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut }; if let Some(did) = target.def_id(cache) { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f07c93ca58e7..6cab34986223 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -581,8 +581,8 @@ fn extra_info_tags<'a, 'tcx: 'a>( display_fn(move |f| { write!( f, - r#"{contents}"#, - Escape(title), + r#"{contents}"#, + title = Escape(title), ) }) } @@ -610,7 +610,12 @@ fn extra_info_tags<'a, 'tcx: 'a>( (cfg, _) => cfg.as_deref().cloned(), }; - debug!("Portability name={:?} {:?} - {:?} = {cfg:?}", item.name, item.cfg, parent.cfg); + debug!( + "Portability name={name:?} {cfg:?} - {parent_cfg:?} = {cfg:?}", + name = item.name, + cfg = item.cfg, + parent_cfg = parent.cfg + ); if let Some(ref cfg) = cfg { write!( f, @@ -737,9 +742,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: toggle_open( &mut w, format_args!( - "{count_consts} associated constant{} and {count_methods} method{}", - pluralize(count_consts), - pluralize(count_methods), + "{count_consts} associated constant{plural_const} and \ + {count_methods} method{plural_method}", + plural_const = pluralize(count_consts), + plural_method = pluralize(count_methods), ), ); } @@ -830,7 +836,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::Item) { let name = m.name.unwrap(); - info!("Documenting {name} on {:?}", t.name); + info!("Documenting {name} on {ty_name:?}", ty_name = t.name); let item_type = m.type_(); let id = cx.derive_id(format!("{item_type}.{name}")); let mut content = Buffer::empty_from(w); @@ -1610,7 +1616,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean for (index, (field, ty)) in fields.enumerate() { let field_name = field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); - let id = cx.derive_id(format!("{}.{field_name}", ItemType::StructField)); + let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField)); write!( w, "\ @@ -1907,10 +1913,10 @@ fn render_struct( if let clean::StructFieldItem(ref ty) = *field.kind { write!( w, - "\n{tab} {}{}: {},", - visibility_print_with_space(field.visibility(tcx), field.item_id, cx), - field.name.unwrap(), - ty.print(cx), + "\n{tab} {vis}{name}: {ty},", + vis = visibility_print_with_space(field.visibility(tcx), field.item_id, cx), + name = field.name.unwrap(), + ty = ty.print(cx), ); } } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index e958721dc556..f3da610565c4 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -529,7 +529,7 @@ fn get_methods<'a>( Some(ref name) if !name.is_empty() && item.is_method() => { if !for_deref || super::should_render_item(item, deref_mut, tcx) { Some(Link::new( - get_next_url(used_links, format!("{}.{name}", ItemType::Method)), + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)), name.as_str(), )) } else { @@ -549,7 +549,7 @@ fn get_associated_constants<'a>( .iter() .filter_map(|item| match item.name { Some(ref name) if !name.is_empty() && item.is_associated_const() => Some(Link::new( - get_next_url(used_links, format!("{}.{name}", ItemType::AssocConst)), + get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)), name.as_str(), )), _ => None, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 2a37577b22b0..e824651e727d 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -73,7 +73,7 @@ pub(super) fn write_shared( } let bytes = try_err!(fs::read(&entry.path), &entry.path); - let filename = format!("{theme}{}.{extension}", cx.shared.resource_suffix); + let filename = format!("{theme}{suffix}.{extension}", suffix = cx.shared.resource_suffix); cx.shared.fs.write(cx.dst.join(filename), bytes)?; } @@ -349,8 +349,8 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; .iter() .map(|s| { format!( - "
  7. {s}
  8. ", - ensure_trailing_slash(s), + "
  9. {s}
  10. ", + trailing_slash = ensure_trailing_slash(s), ) }) .collect::() diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 5a221c0e1c79..c4a1ebbec02e 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -146,8 +146,8 @@ impl DocVisitor for SourceCollector<'_, '_> { self.cx.shared.tcx.sess.span_err( span, format!( - "failed to render source code for `{}`: {e}", - filename.prefer_local(), + "failed to render source code for `{filename}`: {e}", + filename = filename.prefer_local(), ), ); false diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index ca84b9152232..526eea30478a 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -43,7 +43,7 @@ pub(crate) fn render>( edition: Edition, ) -> Result<(), String> { if let Err(e) = create_dir_all(&options.output) { - return Err(format!("{}: {e}", options.output.display())); + return Err(format!("{output}: {e}", output = options.output.display())); } let input = input.as_ref(); @@ -57,11 +57,13 @@ pub(crate) fn render>( .expect("Writing to a String can't fail"); } - let input_str = read_to_string(input).map_err(|err| format!("{}: {err}", input.display()))?; + let input_str = + read_to_string(input).map_err(|err| format!("{input}: {err}", input = input.display()))?; let playground_url = options.markdown_playground_url.or(options.playground_url); let playground = playground_url.map(|url| markdown::Playground { crate_name: None, url }); - let mut out = File::create(&output).map_err(|e| format!("{}: {e}", output.display()))?; + let mut out = + File::create(&output).map_err(|e| format!("{output}: {e}", output = output.display()))?; let (metadata, text) = extract_leading_metadata(&input_str); if metadata.is_empty() { @@ -129,7 +131,7 @@ pub(crate) fn render>( ); match err { - Err(e) => Err(format!("cannot write to `{}`: {e}", output.display())), + Err(e) => Err(format!("cannot write to `{output}`: {e}", output = output.display())), Ok(_) => Ok(()), } } @@ -137,7 +139,7 @@ pub(crate) fn render>( /// Runs any tests/code examples in the markdown file `input`. pub(crate) fn test(options: Options) -> Result<(), String> { let input_str = read_to_string(&options.input) - .map_err(|err| format!("{}: {err}", options.input.display()))?; + .map_err(|err| format!("{input}: {err}", input = options.input.display()))?; let mut opts = GlobalTestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new( diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 305d2e7c162f..592dd0a145cf 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -146,8 +146,10 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { examples_percentage: f64, ) { println!( - "| {name:<35} | {:>10} | {percentage:>9.1}% | {:>10} | {:>9.1}% |", - count.with_docs, count.with_examples, examples_percentage, + "| {name:<35} | {with_docs:>10} | {percentage:>9.1}% | {with_examples:>10} | \ + {examples_percentage:>9.1}% |", + with_docs = count.with_docs, + with_examples = count.with_examples, ); } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f21b0999e87e..26ff64f06a32 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -790,8 +790,8 @@ fn trait_impls_for<'a>( // Check if these are the same type. let impl_type = trait_ref.skip_binder().self_ty(); trace!( - "comparing type {impl_type} with kind {:?} against type {ty:?}", - impl_type.kind(), + "comparing type {impl_type} with kind {kind:?} against type {ty:?}", + kind = impl_type.kind(), ); // Fast path: if this is a primitive simple `==` will work // NOTE: the `match` is necessary; see #92662. @@ -1876,9 +1876,9 @@ fn resolution_failure( }; let name = res.name(tcx); let note = format!( - "the {} `{name}` has no {} named `{unresolved}`", - res.descr(), - disambiguator.map_or(path_description, |d| d.descr()), + "the {res} `{name}` has no {disamb_res} named `{unresolved}`", + res = res.descr(), + disamb_res = disambiguator.map_or(path_description, |d| d.descr()), ); if let Some(span) = sp { diag.span_label(span, note); From 5210f482d7309004c0ff3f6306f052f8d5adb67b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 16 Aug 2023 08:58:02 -0700 Subject: [PATCH 044/169] Partially revert #107200 `Ok(0)` is indeed something the caller may interpret as an error, but that's the *correct* thing to return if the writer can't accept any more bytes. --- library/std/src/io/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 5c1d2d8f46cd..71d91f21362e 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1425,9 +1425,9 @@ pub trait Write { /// /// If this method consumed `n > 0` bytes of `buf` it must return [`Ok(n)`]. /// If the return value is `Ok(n)` then `n` must satisfy `n <= buf.len()`. - /// Unless `buf` is empty, this function shouldn’t return `Ok(0)` since the - /// caller may interpret that as an error. To indicate lack of space, - /// implementors should return [`ErrorKind::StorageFull`] error instead. + /// A return value of `Ok(0)` typically means that the underlying object is + /// no longer able to accept bytes and will likely not be able to in the + /// future as well, or that the buffer provided is empty. /// /// # Errors /// From 66573b578130bca54eea2ec6fc853e05be974634 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 16 Aug 2023 13:10:52 -0300 Subject: [PATCH 045/169] Add missing Clone/Debug impls to SMIR Trait related tys --- compiler/rustc_smir/src/stable_mir/ty.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index f8ff6741208f..7a6601f09da4 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -432,12 +432,14 @@ pub struct UnevaluatedConst { pub promoted: Option, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TraitSpecializationKind { None, Marker, AlwaysApplicable, } +#[derive(Clone, Debug)] pub struct TraitDecl { pub def_id: TraitDef, pub unsafety: Safety, @@ -454,6 +456,7 @@ pub struct TraitDecl { pub type ImplTrait = EarlyBinder; +#[derive(Clone, Debug)] pub struct TraitRef { pub def_id: TraitDef, pub args: GenericArgs, From 9c97abd54cdcc76cfe2b92e2459f8017ed2db1fd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 May 2023 08:53:17 +0000 Subject: [PATCH 046/169] Simplify for_each_mut_borrow. --- compiler/rustc_mir_dataflow/src/impls/mod.rs | 67 +++----------------- 1 file changed, 9 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index 7ddd01e34aaa..52e236383f49 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -4,7 +4,6 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_index::Idx; -use rustc_middle::mir::visit::{MirVisitable, Visitor}; use rustc_middle::mir::{self, Body, Location}; use rustc_middle::ty::{self, TyCtxt}; @@ -316,43 +315,29 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { Self::update_bits(trans, path, s) }); - if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { - return; - } - // Mark all places as "maybe init" if they are mutably borrowed. See #90752. - for_each_mut_borrow(statement, location, |place| { - let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { - return; - }; + if self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration + && let Some((_, rvalue)) = statement.kind.as_assign() + && let mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place) + // FIXME: Does `&raw const foo` allow mutation? See #90413. + | mir::Rvalue::AddressOf(_, place) = rvalue + && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) + { on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| { trans.gen(child); }) - }) + } } fn terminator_effect( &mut self, trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, + _: &mir::Terminator<'tcx>, location: Location, ) { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }); - - if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { - return; - } - - for_each_mut_borrow(terminator, location, |place| { - let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { - return; - }; - on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| { - trans.gen(child); - }) - }) } fn call_return_effect( @@ -733,37 +718,3 @@ fn switch_on_enum_discriminant<'mir, 'tcx>( } None } - -struct OnMutBorrow(F); - -impl<'tcx, F> Visitor<'tcx> for OnMutBorrow -where - F: FnMut(&mir::Place<'tcx>), -{ - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { - // FIXME: Does `&raw const foo` allow mutation? See #90413. - match rvalue { - mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place) - | mir::Rvalue::AddressOf(_, place) => (self.0)(place), - - _ => {} - } - - self.super_rvalue(rvalue, location) - } -} - -/// Calls `f` for each mutable borrow or raw reference in the program. -/// -/// This DOES NOT call `f` for a shared borrow of a type with interior mutability. That's okay for -/// initializedness, because we cannot move from an `UnsafeCell` (outside of `core::cell`), but -/// other analyses will likely need to check for `!Freeze`. -fn for_each_mut_borrow<'tcx>( - mir: &impl MirVisitable<'tcx>, - location: Location, - f: impl FnMut(&mir::Place<'tcx>), -) { - let mut vis = OnMutBorrow(f); - - mir.apply(location, &mut vis); -} From 760881b29debf6b224b522fdd4d4ae2495380d99 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 May 2023 11:08:36 +0000 Subject: [PATCH 047/169] Create bottom on-the-fly instead of cloning it. --- compiler/rustc_mir_dataflow/src/framework/engine.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index c755d7588c25..1333b7de3b09 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -201,11 +201,12 @@ where analysis: A, apply_trans_for_block: Option>, ) -> Self { - let bottom_value = analysis.bottom_value(body); - let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), &body.basic_blocks); + let mut entry_sets = + IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len()); analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); - if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != bottom_value { + if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body) + { bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } From 8726cbc75fea8afb2fdffa2edf7a7031524de305 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 May 2023 14:13:12 +0000 Subject: [PATCH 048/169] Move initialization dataflow impls into their own module. --- .../src/impls/borrowed_locals.rs | 51 +- .../src/impls/initialized.rs | 705 +++++++++++++++++ compiler/rustc_mir_dataflow/src/impls/mod.rs | 711 +----------------- .../src/impls/storage_liveness.rs | 38 +- 4 files changed, 756 insertions(+), 749 deletions(-) create mode 100644 compiler/rustc_mir_dataflow/src/impls/initialized.rs diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index b88ed32b687f..d04d591fd90e 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -1,9 +1,10 @@ -use super::*; - -use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis}; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; +use crate::framework::CallReturnPlaces; +use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; + /// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points /// to a given local. /// @@ -23,12 +24,12 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals { type Domain = BitSet; const NAME: &'static str = "maybe_borrowed_locals"; - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain { // bottom = unborrowed BitSet::new_empty(body.local_decls().len()) } - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { + fn initialize_start_block(&self, _: &Body<'tcx>, _: &mut Self::Domain) { // No locals are aliased on function entry } } @@ -39,7 +40,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { fn statement_effect( &mut self, trans: &mut impl GenKill, - statement: &mir::Statement<'tcx>, + statement: &Statement<'tcx>, location: Location, ) { self.transfer_function(trans).visit_statement(statement, location); @@ -48,7 +49,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { fn terminator_effect( &mut self, trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, + terminator: &Terminator<'tcx>, location: Location, ) { self.transfer_function(trans).visit_terminator(terminator, location); @@ -57,7 +58,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { fn call_return_effect( &mut self, _trans: &mut impl GenKill, - _block: mir::BasicBlock, + _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, ) { } @@ -82,37 +83,37 @@ where } } - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); match rvalue { - mir::Rvalue::AddressOf(_, borrowed_place) | mir::Rvalue::Ref(_, _, borrowed_place) => { + Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { if !borrowed_place.is_indirect() { self.trans.gen(borrowed_place.local); } } - mir::Rvalue::Cast(..) - | mir::Rvalue::ShallowInitBox(..) - | mir::Rvalue::Use(..) - | mir::Rvalue::ThreadLocalRef(..) - | mir::Rvalue::Repeat(..) - | mir::Rvalue::Len(..) - | mir::Rvalue::BinaryOp(..) - | mir::Rvalue::CheckedBinaryOp(..) - | mir::Rvalue::NullaryOp(..) - | mir::Rvalue::UnaryOp(..) - | mir::Rvalue::Discriminant(..) - | mir::Rvalue::Aggregate(..) - | mir::Rvalue::CopyForDeref(..) => {} + Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) + | Rvalue::Use(..) + | Rvalue::ThreadLocalRef(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::NullaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) + | Rvalue::Aggregate(..) + | Rvalue::CopyForDeref(..) => {} } } - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { self.super_terminator(terminator, location); match terminator.kind { - mir::TerminatorKind::Drop { place: dropped_place, .. } => { + TerminatorKind::Drop { place: dropped_place, .. } => { // Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut // self` as a parameter. In the general case, a drop impl could launder that // reference into the surrounding environment through a raw pointer, thus creating diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs new file mode 100644 index 000000000000..73df9f77fde3 --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -0,0 +1,705 @@ +use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::Idx; +use rustc_middle::mir::{self, Body, Location}; +use rustc_middle::ty::{self, TyCtxt}; + +use crate::drop_flag_effects_for_function_entry; +use crate::drop_flag_effects_for_location; +use crate::elaborate_drops::DropFlagState; +use crate::framework::{CallReturnPlaces, SwitchIntEdgeEffects}; +use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; +use crate::on_lookup_result_bits; +use crate::MoveDataParamEnv; +use crate::{drop_flag_effects, on_all_children_bits}; +use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis}; + +/// `MaybeInitializedPlaces` tracks all places that might be +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-init: +/// // {} +/// let a = S; let mut b = S; let c; let d; // {a, b} +/// +/// if pred { +/// drop(a); // { b} +/// b = S; // { b} +/// +/// } else { +/// drop(b); // {a} +/// d = S; // {a, d} +/// +/// } // {a, b, d} +/// +/// c = S; // {a, b, c, d} +/// } +/// ``` +/// +/// To determine whether a place *must* be initialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeUninitializedPlaces` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeUninitializedPlaces` yields the set of +/// places that would require a dynamic drop-flag at that statement. +pub struct MaybeInitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, +} + +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + MaybeInitializedPlaces { tcx, body, mdpe } + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +/// `MaybeUninitializedPlaces` tracks all places that might be +/// uninitialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-uninit: +/// // {a, b, c, d} +/// let a = S; let mut b = S; let c; let d; // { c, d} +/// +/// if pred { +/// drop(a); // {a, c, d} +/// b = S; // {a, c, d} +/// +/// } else { +/// drop(b); // { b, c, d} +/// d = S; // { b, c } +/// +/// } // {a, b, c, d} +/// +/// c = S; // {a, b, d} +/// } +/// ``` +/// +/// To determine whether a place *must* be uninitialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeInitializedPlaces` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeInitializedPlaces` yields the set of +/// places that would require a dynamic drop-flag at that statement. +pub struct MaybeUninitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, + + mark_inactive_variants_as_uninit: bool, +} + +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false } + } + + /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an + /// enum discriminant. + /// + /// This is correct in a vacuum but is not the default because it causes problems in the borrow + /// checker, where this information gets propagated along `FakeEdge`s. + pub fn mark_inactive_variants_as_uninit(mut self) -> Self { + self.mark_inactive_variants_as_uninit = true; + self + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +/// `DefinitelyInitializedPlaces` tracks all places that are definitely +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // definite-init: +/// // { } +/// let a = S; let mut b = S; let c; let d; // {a, b } +/// +/// if pred { +/// drop(a); // { b, } +/// b = S; // { b, } +/// +/// } else { +/// drop(b); // {a, } +/// d = S; // {a, d} +/// +/// } // { } +/// +/// c = S; // { c } +/// } +/// ``` +/// +/// To determine whether a place *may* be uninitialized at a +/// particular control-flow point, one can take the set-complement +/// of this data. +/// +/// Similarly, at a given `drop` statement, the set-difference between +/// this data and `MaybeInitializedPlaces` yields the set of places +/// that would require a dynamic drop-flag at that statement. +pub struct DefinitelyInitializedPlaces<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, +} + +impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + DefinitelyInitializedPlaces { tcx, body, mdpe } + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +/// `EverInitializedPlaces` tracks all places that might have ever been +/// initialized upon reaching a particular point in the control flow +/// for a function, without an intervening `StorageDead`. +/// +/// This dataflow is used to determine if an immutable local variable may +/// be assigned to. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // ever-init: +/// // { } +/// let a = S; let mut b = S; let c; let d; // {a, b } +/// +/// if pred { +/// drop(a); // {a, b, } +/// b = S; // {a, b, } +/// +/// } else { +/// drop(b); // {a, b, } +/// d = S; // {a, b, d } +/// +/// } // {a, b, d } +/// +/// c = S; // {a, b, c, d } +/// } +/// ``` +pub struct EverInitializedPlaces<'a, 'tcx> { + #[allow(dead_code)] + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, +} + +impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { + EverInitializedPlaces { tcx, body, mdpe } + } +} + +impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { + &self.mdpe.move_data + } +} + +impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { + fn update_bits( + trans: &mut impl GenKill, + path: MovePathIndex, + state: DropFlagState, + ) { + match state { + DropFlagState::Absent => trans.kill(path), + DropFlagState::Present => trans.gen(path), + } + } +} + +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { + fn update_bits( + trans: &mut impl GenKill, + path: MovePathIndex, + state: DropFlagState, + ) { + match state { + DropFlagState::Absent => trans.gen(path), + DropFlagState::Present => trans.kill(path), + } + } +} + +impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { + fn update_bits( + trans: &mut impl GenKill, + path: MovePathIndex, + state: DropFlagState, + ) { + match state { + DropFlagState::Absent => trans.kill(path), + DropFlagState::Present => trans.gen(path), + } + } +} + +impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + type Domain = ChunkedBitSet; + const NAME: &'static str = "maybe_init"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = uninitialized + ChunkedBitSet::new_empty(self.move_data().move_paths.len()) + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { + assert!(s == DropFlagState::Present); + state.insert(path); + }); + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + + fn statement_effect( + &mut self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }); + + // Mark all places as "maybe init" if they are mutably borrowed. See #90752. + if self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration + && let Some((_, rvalue)) = statement.kind.as_assign() + && let mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place) + // FIXME: Does `&raw const foo` allow mutation? See #90413. + | mir::Rvalue::AddressOf(_, place) = rvalue + && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) + { + on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| { + trans.gen(child); + }) + } + } + + fn terminator_effect( + &mut self, + trans: &mut impl GenKill, + _: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }); + } + + fn call_return_effect( + &mut self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + return_places: CallReturnPlaces<'_, 'tcx>, + ) { + return_places.for_each(|place| { + // when a call returns successfully, that means we need to set + // the bits for that dest_place to 1 (initialized). + on_lookup_result_bits( + self.tcx, + self.body, + self.move_data(), + self.move_data().rev_lookup.find(place.as_ref()), + |mpi| { + trans.gen(mpi); + }, + ); + }); + } + + fn switch_int_edge_effects>( + &mut self, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { + return; + } + + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let Some((enum_place, enum_def)) = enum_ else { + return; + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let Some(value) = edge.value else { + return; + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Kill all move paths that correspond to variants we know to be inactive along this + // particular outgoing edge of a `SwitchInt`. + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.kill(mpi), + ); + }); + } +} + +impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + type Domain = ChunkedBitSet; + + const NAME: &'static str = "maybe_uninit"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = initialized (start_block_effect counters this at outset) + ChunkedBitSet::new_empty(self.move_data().move_paths.len()) + } + + // sets on_entry bits for Arg places + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + // set all bits to 1 (uninit) before gathering counter-evidence + state.insert_all(); + + drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { + assert!(s == DropFlagState::Present); + state.remove(path); + }); + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + + fn statement_effect( + &mut self, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }); + + // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a + // mutable borrow occurs. Places cannot become uninitialized through a mutable reference. + } + + fn terminator_effect( + &mut self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }); + } + + fn call_return_effect( + &mut self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + return_places: CallReturnPlaces<'_, 'tcx>, + ) { + return_places.for_each(|place| { + // when a call returns successfully, that means we need to set + // the bits for that dest_place to 0 (initialized). + on_lookup_result_bits( + self.tcx, + self.body, + self.move_data(), + self.move_data().rev_lookup.find(place.as_ref()), + |mpi| { + trans.kill(mpi); + }, + ); + }); + } + + fn switch_int_edge_effects>( + &mut self, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, + ) { + if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { + return; + } + + if !self.mark_inactive_variants_as_uninit { + return; + } + + let enum_ = discr.place().and_then(|discr| { + switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) + }); + + let Some((enum_place, enum_def)) = enum_ else { + return; + }; + + let mut discriminants = enum_def.discriminants(self.tcx); + edge_effects.apply(|trans, edge| { + let Some(value) = edge.value else { + return; + }; + + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let (variant, _) = discriminants + .find(|&(_, discr)| discr.val == value) + .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); + + // Mark all move paths that correspond to variants other than this one as maybe + // uninitialized (in reality, they are *definitely* uninitialized). + drop_flag_effects::on_all_inactive_variants( + self.tcx, + self.body, + self.move_data(), + enum_place, + variant, + |mpi| trans.gen(mpi), + ); + }); + } +} + +impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { + /// Use set intersection as the join operator. + type Domain = lattice::Dual>; + + const NAME: &'static str = "definite_init"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = initialized (start_block_effect counters this at outset) + lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len())) + } + + // sets on_entry bits for Arg places + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + state.0.clear(); + + drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { + assert!(s == DropFlagState::Present); + state.0.insert(path); + }); + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + + fn statement_effect( + &mut self, + trans: &mut impl GenKill, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn terminator_effect( + &mut self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { + Self::update_bits(trans, path, s) + }) + } + + fn call_return_effect( + &mut self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + return_places: CallReturnPlaces<'_, 'tcx>, + ) { + return_places.for_each(|place| { + // when a call returns successfully, that means we need to set + // the bits for that dest_place to 1 (initialized). + on_lookup_result_bits( + self.tcx, + self.body, + self.move_data(), + self.move_data().rev_lookup.find(place.as_ref()), + |mpi| { + trans.gen(mpi); + }, + ); + }); + } +} + +impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { + type Domain = ChunkedBitSet; + + const NAME: &'static str = "ever_init"; + + fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { + // bottom = no initialized variables by default + ChunkedBitSet::new_empty(self.move_data().inits.len()) + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { + for arg_init in 0..body.arg_count { + state.insert(InitIndex::new(arg_init)); + } + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { + type Idx = InitIndex; + + #[instrument(skip(self, trans), level = "debug")] + fn statement_effect( + &mut self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + location: Location, + ) { + let move_data = self.move_data(); + let init_path_map = &move_data.init_path_map; + let init_loc_map = &move_data.init_loc_map; + let rev_lookup = &move_data.rev_lookup; + + debug!("initializes move_indexes {:?}", &init_loc_map[location]); + trans.gen_all(init_loc_map[location].iter().copied()); + + if let mir::StatementKind::StorageDead(local) = stmt.kind { + // End inits for StorageDead, so that an immutable variable can + // be reinitialized on the next iteration of the loop. + let move_path_index = rev_lookup.find_local(local); + debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]); + trans.kill_all(init_path_map[move_path_index].iter().copied()); + } + } + + #[instrument(skip(self, trans, _terminator), level = "debug")] + fn terminator_effect( + &mut self, + trans: &mut impl GenKill, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + let (body, move_data) = (self.body, self.move_data()); + let term = body[location.block].terminator(); + let init_loc_map = &move_data.init_loc_map; + debug!(?term); + debug!("initializes move_indexes {:?}", init_loc_map[location]); + trans.gen_all( + init_loc_map[location] + .iter() + .filter(|init_index| { + move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly + }) + .copied(), + ); + } + + fn call_return_effect( + &mut self, + trans: &mut impl GenKill, + block: mir::BasicBlock, + _return_places: CallReturnPlaces<'_, 'tcx>, + ) { + let move_data = self.move_data(); + let init_loc_map = &move_data.init_loc_map; + + let call_loc = self.body.terminator_loc(block); + for init_index in &init_loc_map[call_loc] { + trans.gen(*init_index); + } + } +} + +/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is +/// an enum discriminant. +/// +/// We expect such blocks to have a call to `discriminant` as their last statement like so: +/// +/// ```text +/// ... +/// _42 = discriminant(_1) +/// SwitchInt(_42, ..) +/// ``` +/// +/// If the basic block matches this pattern, this function returns the place corresponding to the +/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. +fn switch_on_enum_discriminant<'mir, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + block: &'mir mir::BasicBlockData<'tcx>, + switch_on: mir::Place<'tcx>, +) -> Option<(mir::Place<'tcx>, ty::AdtDef<'tcx>)> { + for statement in block.statements.iter().rev() { + match &statement.kind { + mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))) + if *lhs == switch_on => + { + match discriminated.ty(body, tcx).ty.kind() { + ty::Adt(def, _) => return Some((*discriminated, *def)), + + // `Rvalue::Discriminant` is also used to get the active yield point for a + // generator, but we do not need edge-specific effects in that case. This may + // change in the future. + ty::Generator(..) => return None, + + t => bug!("`discriminant` called on unexpected type {:?}", t), + } + } + mir::StatementKind::Coverage(_) => continue, + _ => return None, + } + } + None +} diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index 52e236383f49..f8db18fc1f8d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -2,719 +2,18 @@ //! bitvectors attached to each basic block, represented via a //! zero-sized structure. -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; -use rustc_index::Idx; -use rustc_middle::mir::{self, Body, Location}; -use rustc_middle::ty::{self, TyCtxt}; - -use crate::drop_flag_effects_for_function_entry; -use crate::drop_flag_effects_for_location; -use crate::elaborate_drops::DropFlagState; -use crate::framework::{CallReturnPlaces, SwitchIntEdgeEffects}; -use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; -use crate::on_lookup_result_bits; -use crate::MoveDataParamEnv; -use crate::{drop_flag_effects, on_all_children_bits}; -use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis}; - mod borrowed_locals; +mod initialized; mod liveness; mod storage_liveness; pub use self::borrowed_locals::borrowed_locals; pub use self::borrowed_locals::MaybeBorrowedLocals; +pub use self::initialized::{ + DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces, + MaybeUninitializedPlaces, +}; pub use self::liveness::MaybeLiveLocals; pub use self::liveness::MaybeTransitiveLiveLocals; pub use self::liveness::TransferFunction as LivenessTransferFunction; pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageDead, MaybeStorageLive}; - -/// `MaybeInitializedPlaces` tracks all places that might be -/// initialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-init: -/// // {} -/// let a = S; let mut b = S; let c; let d; // {a, b} -/// -/// if pred { -/// drop(a); // { b} -/// b = S; // { b} -/// -/// } else { -/// drop(b); // {a} -/// d = S; // {a, d} -/// -/// } // {a, b, d} -/// -/// c = S; // {a, b, c, d} -/// } -/// ``` -/// -/// To determine whether a place *must* be initialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeUninitializedPlaces` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeUninitializedPlaces` yields the set of -/// places that would require a dynamic drop-flag at that statement. -pub struct MaybeInitializedPlaces<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, -} - -impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeInitializedPlaces { tcx, body, mdpe } - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -/// `MaybeUninitializedPlaces` tracks all places that might be -/// uninitialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-uninit: -/// // {a, b, c, d} -/// let a = S; let mut b = S; let c; let d; // { c, d} -/// -/// if pred { -/// drop(a); // {a, c, d} -/// b = S; // {a, c, d} -/// -/// } else { -/// drop(b); // { b, c, d} -/// d = S; // { b, c } -/// -/// } // {a, b, c, d} -/// -/// c = S; // {a, b, d} -/// } -/// ``` -/// -/// To determine whether a place *must* be uninitialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeInitializedPlaces` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeInitializedPlaces` yields the set of -/// places that would require a dynamic drop-flag at that statement. -pub struct MaybeUninitializedPlaces<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, - - mark_inactive_variants_as_uninit: bool, -} - -impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false } - } - - /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an - /// enum discriminant. - /// - /// This is correct in a vacuum but is not the default because it causes problems in the borrow - /// checker, where this information gets propagated along `FakeEdge`s. - pub fn mark_inactive_variants_as_uninit(mut self) -> Self { - self.mark_inactive_variants_as_uninit = true; - self - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -/// `DefinitelyInitializedPlaces` tracks all places that are definitely -/// initialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // definite-init: -/// // { } -/// let a = S; let mut b = S; let c; let d; // {a, b } -/// -/// if pred { -/// drop(a); // { b, } -/// b = S; // { b, } -/// -/// } else { -/// drop(b); // {a, } -/// d = S; // {a, d} -/// -/// } // { } -/// -/// c = S; // { c } -/// } -/// ``` -/// -/// To determine whether a place *may* be uninitialized at a -/// particular control-flow point, one can take the set-complement -/// of this data. -/// -/// Similarly, at a given `drop` statement, the set-difference between -/// this data and `MaybeInitializedPlaces` yields the set of places -/// that would require a dynamic drop-flag at that statement. -pub struct DefinitelyInitializedPlaces<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, -} - -impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - DefinitelyInitializedPlaces { tcx, body, mdpe } - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -/// `EverInitializedPlaces` tracks all places that might have ever been -/// initialized upon reaching a particular point in the control flow -/// for a function, without an intervening `StorageDead`. -/// -/// This dataflow is used to determine if an immutable local variable may -/// be assigned to. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // ever-init: -/// // { } -/// let a = S; let mut b = S; let c; let d; // {a, b } -/// -/// if pred { -/// drop(a); // {a, b, } -/// b = S; // {a, b, } -/// -/// } else { -/// drop(b); // {a, b, } -/// d = S; // {a, b, d } -/// -/// } // {a, b, d } -/// -/// c = S; // {a, b, c, d } -/// } -/// ``` -pub struct EverInitializedPlaces<'a, 'tcx> { - #[allow(dead_code)] - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - mdpe: &'a MoveDataParamEnv<'tcx>, -} - -impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - EverInitializedPlaces { tcx, body, mdpe } - } -} - -impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { - &self.mdpe.move_data - } -} - -impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { - fn update_bits( - trans: &mut impl GenKill, - path: MovePathIndex, - state: DropFlagState, - ) { - match state { - DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), - } - } -} - -impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { - fn update_bits( - trans: &mut impl GenKill, - path: MovePathIndex, - state: DropFlagState, - ) { - match state { - DropFlagState::Absent => trans.gen(path), - DropFlagState::Present => trans.kill(path), - } - } -} - -impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { - fn update_bits( - trans: &mut impl GenKill, - path: MovePathIndex, - state: DropFlagState, - ) { - match state { - DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen(path), - } - } -} - -impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Domain = ChunkedBitSet; - const NAME: &'static str = "maybe_init"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = uninitialized - ChunkedBitSet::new_empty(self.move_data().move_paths.len()) - } - - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { - drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { - assert!(s == DropFlagState::Present); - state.insert(path); - }); - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }); - - // Mark all places as "maybe init" if they are mutably borrowed. See #90752. - if self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration - && let Some((_, rvalue)) = statement.kind.as_assign() - && let mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place) - // FIXME: Does `&raw const foo` allow mutation? See #90413. - | mir::Rvalue::AddressOf(_, place) = rvalue - && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) - { - on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| { - trans.gen(child); - }) - } - } - - fn terminator_effect( - &mut self, - trans: &mut impl GenKill, - _: &mir::Terminator<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }); - } - - fn call_return_effect( - &mut self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - return_places.for_each(|place| { - // when a call returns successfully, that means we need to set - // the bits for that dest_place to 1 (initialized). - on_lookup_result_bits( - self.tcx, - self.body, - self.move_data(), - self.move_data().rev_lookup.find(place.as_ref()), - |mpi| { - trans.gen(mpi); - }, - ); - }); - } - - fn switch_int_edge_effects>( - &mut self, - block: mir::BasicBlock, - discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { - return; - } - - let enum_ = discr.place().and_then(|discr| { - switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) - }); - - let Some((enum_place, enum_def)) = enum_ else { - return; - }; - - let mut discriminants = enum_def.discriminants(self.tcx); - edge_effects.apply(|trans, edge| { - let Some(value) = edge.value else { - return; - }; - - // MIR building adds discriminants to the `values` array in the same order as they - // are yielded by `AdtDef::discriminants`. We rely on this to match each - // discriminant in `values` to its corresponding variant in linear time. - let (variant, _) = discriminants - .find(|&(_, discr)| discr.val == value) - .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); - - // Kill all move paths that correspond to variants we know to be inactive along this - // particular outgoing edge of a `SwitchInt`. - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.kill(mpi), - ); - }); - } -} - -impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { - type Domain = ChunkedBitSet; - - const NAME: &'static str = "maybe_uninit"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = initialized (start_block_effect counters this at outset) - ChunkedBitSet::new_empty(self.move_data().move_paths.len()) - } - - // sets on_entry bits for Arg places - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { - // set all bits to 1 (uninit) before gathering counter-evidence - state.insert_all(); - - drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { - assert!(s == DropFlagState::Present); - state.remove(path); - }); - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }); - - // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a - // mutable borrow occurs. Places cannot become uninitialized through a mutable reference. - } - - fn terminator_effect( - &mut self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }); - } - - fn call_return_effect( - &mut self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - return_places.for_each(|place| { - // when a call returns successfully, that means we need to set - // the bits for that dest_place to 0 (initialized). - on_lookup_result_bits( - self.tcx, - self.body, - self.move_data(), - self.move_data().rev_lookup.find(place.as_ref()), - |mpi| { - trans.kill(mpi); - }, - ); - }); - } - - fn switch_int_edge_effects>( - &mut self, - block: mir::BasicBlock, - discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { - return; - } - - if !self.mark_inactive_variants_as_uninit { - return; - } - - let enum_ = discr.place().and_then(|discr| { - switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr) - }); - - let Some((enum_place, enum_def)) = enum_ else { - return; - }; - - let mut discriminants = enum_def.discriminants(self.tcx); - edge_effects.apply(|trans, edge| { - let Some(value) = edge.value else { - return; - }; - - // MIR building adds discriminants to the `values` array in the same order as they - // are yielded by `AdtDef::discriminants`. We rely on this to match each - // discriminant in `values` to its corresponding variant in linear time. - let (variant, _) = discriminants - .find(|&(_, discr)| discr.val == value) - .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`"); - - // Mark all move paths that correspond to variants other than this one as maybe - // uninitialized (in reality, they are *definitely* uninitialized). - drop_flag_effects::on_all_inactive_variants( - self.tcx, - self.body, - self.move_data(), - enum_place, - variant, - |mpi| trans.gen(mpi), - ); - }); - } -} - -impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { - /// Use set intersection as the join operator. - type Domain = lattice::Dual>; - - const NAME: &'static str = "definite_init"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = initialized (start_block_effect counters this at outset) - lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len())) - } - - // sets on_entry bits for Arg places - fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { - state.0.clear(); - - drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { - assert!(s == DropFlagState::Present); - state.0.insert(path); - }); - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn terminator_effect( - &mut self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) - }) - } - - fn call_return_effect( - &mut self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - return_places.for_each(|place| { - // when a call returns successfully, that means we need to set - // the bits for that dest_place to 1 (initialized). - on_lookup_result_bits( - self.tcx, - self.body, - self.move_data(), - self.move_data().rev_lookup.find(place.as_ref()), - |mpi| { - trans.gen(mpi); - }, - ); - }); - } -} - -impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { - type Domain = ChunkedBitSet; - - const NAME: &'static str = "ever_init"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = no initialized variables by default - ChunkedBitSet::new_empty(self.move_data().inits.len()) - } - - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { - for arg_init in 0..body.arg_count { - state.insert(InitIndex::new(arg_init)); - } - } -} - -impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { - type Idx = InitIndex; - - #[instrument(skip(self, trans), level = "debug")] - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, - location: Location, - ) { - let move_data = self.move_data(); - let init_path_map = &move_data.init_path_map; - let init_loc_map = &move_data.init_loc_map; - let rev_lookup = &move_data.rev_lookup; - - debug!("initializes move_indexes {:?}", &init_loc_map[location]); - trans.gen_all(init_loc_map[location].iter().copied()); - - if let mir::StatementKind::StorageDead(local) = stmt.kind { - // End inits for StorageDead, so that an immutable variable can - // be reinitialized on the next iteration of the loop. - let move_path_index = rev_lookup.find_local(local); - debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]); - trans.kill_all(init_path_map[move_path_index].iter().copied()); - } - } - - #[instrument(skip(self, trans, _terminator), level = "debug")] - fn terminator_effect( - &mut self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - let (body, move_data) = (self.body, self.move_data()); - let term = body[location.block].terminator(); - let init_loc_map = &move_data.init_loc_map; - debug!(?term); - debug!("initializes move_indexes {:?}", init_loc_map[location]); - trans.gen_all( - init_loc_map[location] - .iter() - .filter(|init_index| { - move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly - }) - .copied(), - ); - } - - fn call_return_effect( - &mut self, - trans: &mut impl GenKill, - block: mir::BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - let move_data = self.move_data(); - let init_loc_map = &move_data.init_loc_map; - - let call_loc = self.body.terminator_loc(block); - for init_index in &init_loc_map[call_loc] { - trans.gen(*init_index); - } - } -} - -/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is -/// an enum discriminant. -/// -/// We expect such blocks to have a call to `discriminant` as their last statement like so: -/// -/// ```text -/// ... -/// _42 = discriminant(_1) -/// SwitchInt(_42, ..) -/// ``` -/// -/// If the basic block matches this pattern, this function returns the place corresponding to the -/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. -fn switch_on_enum_discriminant<'mir, 'tcx>( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - block: &'mir mir::BasicBlockData<'tcx>, - switch_on: mir::Place<'tcx>, -) -> Option<(mir::Place<'tcx>, ty::AdtDef<'tcx>)> { - for statement in block.statements.iter().rev() { - match &statement.kind { - mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))) - if *lhs == switch_on => - { - match discriminated.ty(body, tcx).ty.kind() { - ty::Adt(def, _) => return Some((*discriminated, *def)), - - // `Rvalue::Discriminant` is also used to get the active yield point for a - // generator, but we do not need edge-specific effects in that case. This may - // change in the future. - ty::Generator(..) => return None, - - t => bug!("`discriminant` called on unexpected type {:?}", t), - } - } - mir::StatementKind::Coverage(_) => continue, - _ => return None, - } - } - None -} diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 666c8d50a8a8..faafd6a2dbf7 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -1,10 +1,12 @@ -pub use super::*; - -use crate::{CallReturnPlaces, GenKill, ResultsClonedCursor}; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; + use std::borrow::Cow; +use super::MaybeBorrowedLocals; +use crate::{CallReturnPlaces, GenKill, ResultsClonedCursor}; + #[derive(Clone)] pub struct MaybeStorageLive<'a> { always_live_locals: Cow<'a, BitSet>, @@ -27,12 +29,12 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { const NAME: &'static str = "maybe_storage_live"; - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain { // bottom = dead BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { + fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); for local in self.always_live_locals.iter() { on_entry.insert(local); @@ -50,7 +52,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { fn statement_effect( &mut self, trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, + stmt: &Statement<'tcx>, _: Location, ) { match stmt.kind { @@ -63,7 +65,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { fn terminator_effect( &mut self, _trans: &mut impl GenKill, - _: &mir::Terminator<'tcx>, + _: &Terminator<'tcx>, _: Location, ) { // Terminators have no effect @@ -95,12 +97,12 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead { const NAME: &'static str = "maybe_storage_dead"; - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain { // bottom = live BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { + fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); // Do not iterate on return place and args, as they are trivially always live. for local in body.vars_and_temps_iter() { @@ -117,7 +119,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead { fn statement_effect( &mut self, trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, + stmt: &Statement<'tcx>, _: Location, ) { match stmt.kind { @@ -130,7 +132,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead { fn terminator_effect( &mut self, _trans: &mut impl GenKill, - _: &mir::Terminator<'tcx>, + _: &Terminator<'tcx>, _: Location, ) { // Terminators have no effect @@ -172,12 +174,12 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { const NAME: &'static str = "requires_storage"; - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain { // bottom = dead BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) { + fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { // The resume argument is live on function entry (we don't care about // the `self` argument) for arg in body.args_iter().skip(1) { @@ -192,7 +194,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { fn before_statement_effect( &mut self, trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, + stmt: &Statement<'tcx>, loc: Location, ) { // If a place is borrowed in a statement, it needs storage for that statement. @@ -225,7 +227,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { fn statement_effect( &mut self, trans: &mut impl GenKill, - _: &mir::Statement<'tcx>, + _: &Statement<'tcx>, loc: Location, ) { // If we move from a place then it only stops needing storage *after* @@ -236,7 +238,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { fn before_terminator_effect( &mut self, trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, + terminator: &Terminator<'tcx>, loc: Location, ) { // If a place is borrowed in a terminator, it needs storage for that terminator. @@ -289,7 +291,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { fn terminator_effect( &mut self, trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, + terminator: &Terminator<'tcx>, loc: Location, ) { match terminator.kind { @@ -338,7 +340,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { &mut self, trans: &mut impl GenKill, _resume_block: BasicBlock, - resume_place: mir::Place<'tcx>, + resume_place: Place<'tcx>, ) { trans.gen(resume_place.local); } From 934a99eb659761353e9b89538bd5de356b0f7dfe Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 May 2023 22:00:24 +0000 Subject: [PATCH 049/169] Move domain_size to GenKillAnalysis. --- compiler/rustc_borrowck/src/dataflow.rs | 4 ++++ .../rustc_mir_dataflow/src/framework/engine.rs | 2 +- .../rustc_mir_dataflow/src/framework/lattice.rs | 4 ---- compiler/rustc_mir_dataflow/src/framework/mod.rs | 11 ++--------- .../src/impls/borrowed_locals.rs | 4 ++++ .../rustc_mir_dataflow/src/impls/initialized.rs | 16 ++++++++++++++++ .../rustc_mir_dataflow/src/impls/liveness.rs | 4 ++++ .../src/impls/storage_liveness.rs | 12 ++++++++++++ 8 files changed, 43 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 1e89a9f51445..289a41921a79 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -334,6 +334,10 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { type Idx = BorrowIndex; + fn domain_size(&self, _: &mir::Body<'tcx>) -> usize { + self.borrow_set.len() + } + fn before_statement_effect( &mut self, trans: &mut impl GenKill, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 1333b7de3b09..f9cb6eb360df 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -165,7 +165,7 @@ where // Otherwise, compute and store the cumulative transfer function for each block. - let identity = GenKillSet::identity(analysis.bottom_value(body).domain_size()); + let identity = GenKillSet::identity(analysis.domain_size(body)); let mut trans_for_block = IndexVec::from_elem(identity, &body.basic_blocks); for (block, block_data) in body.basic_blocks.iter_enumerated() { diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index 3952f44ad489..2d6a719417fa 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -187,10 +187,6 @@ impl MeetSemiLattice for ChunkedBitSet { pub struct Dual(pub T); impl BitSetExt for Dual> { - fn domain_size(&self) -> usize { - self.0.domain_size() - } - fn contains(&self, elem: T) -> bool { self.0.contains(elem) } diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 58df9b9a768b..8ccd57802d71 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -54,17 +54,12 @@ pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; /// Analysis domains are all bitsets of various kinds. This trait holds /// operations needed by all of them. pub trait BitSetExt { - fn domain_size(&self) -> usize; fn contains(&self, elem: T) -> bool; fn union(&mut self, other: &HybridBitSet); fn subtract(&mut self, other: &HybridBitSet); } impl BitSetExt for BitSet { - fn domain_size(&self) -> usize { - self.domain_size() - } - fn contains(&self, elem: T) -> bool { self.contains(elem) } @@ -79,10 +74,6 @@ impl BitSetExt for BitSet { } impl BitSetExt for ChunkedBitSet { - fn domain_size(&self) -> usize { - self.domain_size() - } - fn contains(&self, elem: T) -> bool { self.contains(elem) } @@ -295,6 +286,8 @@ where pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { type Idx: Idx; + fn domain_size(&self, body: &mir::Body<'tcx>) -> usize; + /// See `Analysis::apply_statement_effect`. fn statement_effect( &mut self, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index d04d591fd90e..d59bbc38644d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -37,6 +37,10 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals { impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { type Idx = Local; + fn domain_size(&self, body: &Body<'tcx>) -> usize { + body.local_decls.len() + } + fn statement_effect( &mut self, trans: &mut impl GenKill, diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 73df9f77fde3..cd5b1b4856dd 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -290,6 +290,10 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; + fn domain_size(&self, _: &Body<'tcx>) -> usize { + self.move_data().move_paths.len() + } + fn statement_effect( &mut self, trans: &mut impl GenKill, @@ -416,6 +420,10 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; + fn domain_size(&self, _: &Body<'tcx>) -> usize { + self.move_data().move_paths.len() + } + fn statement_effect( &mut self, trans: &mut impl GenKill, @@ -536,6 +544,10 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; + fn domain_size(&self, _: &Body<'tcx>) -> usize { + self.move_data().move_paths.len() + } + fn statement_effect( &mut self, trans: &mut impl GenKill, @@ -600,6 +612,10 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { type Idx = InitIndex; + fn domain_size(&self, _: &Body<'tcx>) -> usize { + self.move_data().inits.len() + } + #[instrument(skip(self, trans), level = "debug")] fn statement_effect( &mut self, diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 34e0834a68b3..eddf40bdf2ee 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -43,6 +43,10 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { type Idx = Local; + fn domain_size(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls.len() + } + fn statement_effect( &mut self, trans: &mut impl GenKill, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index faafd6a2dbf7..d07dd034d2a9 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -49,6 +49,10 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { type Idx = Local; + fn domain_size(&self, body: &Body<'tcx>) -> usize { + body.local_decls.len() + } + fn statement_effect( &mut self, trans: &mut impl GenKill, @@ -116,6 +120,10 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead { impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead { type Idx = Local; + fn domain_size(&self, body: &Body<'tcx>) -> usize { + body.local_decls.len() + } + fn statement_effect( &mut self, trans: &mut impl GenKill, @@ -191,6 +199,10 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { type Idx = Local; + fn domain_size(&self, body: &Body<'tcx>) -> usize { + body.local_decls.len() + } + fn before_statement_effect( &mut self, trans: &mut impl GenKill, From 32711b2b4e1d0868b5576e568e27024186f8aa38 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 May 2023 22:01:22 +0000 Subject: [PATCH 050/169] Introduce MaybeUnreachable. --- .../rustc_mir_dataflow/src/framework/fmt.rs | 32 +++++++ .../src/framework/lattice.rs | 85 +++++++++++++++++++ .../rustc_mir_dataflow/src/framework/mod.rs | 18 +++- compiler/rustc_mir_dataflow/src/lib.rs | 4 +- 4 files changed, 136 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs index 6a256fae3ca7..ac0d2aba39da 100644 --- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs +++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs @@ -1,6 +1,7 @@ //! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow //! analysis. +use super::lattice::MaybeUnreachable; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_index::Idx; use std::fmt; @@ -124,6 +125,37 @@ where } } +impl DebugWithContext for MaybeUnreachable +where + S: DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MaybeUnreachable::Unreachable => { + write!(f, "unreachable") + } + MaybeUnreachable::Reachable(set) => set.fmt_with(ctxt, f), + } + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match (self, old) { + (MaybeUnreachable::Unreachable, MaybeUnreachable::Unreachable) => Ok(()), + (MaybeUnreachable::Unreachable, MaybeUnreachable::Reachable(set)) => { + write!(f, "\u{001f}+")?; + set.fmt_with(ctxt, f) + } + (MaybeUnreachable::Reachable(set), MaybeUnreachable::Unreachable) => { + write!(f, "\u{001f}-")?; + set.fmt_with(ctxt, f) + } + (MaybeUnreachable::Reachable(this), MaybeUnreachable::Reachable(old)) => { + this.fmt_diff_with(old, ctxt, f) + } + } + } +} + fn fmt_diff( inserted: &HybridBitSet, removed: &HybridBitSet, diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index 2d6a719417fa..72ebf5754be4 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -272,3 +272,88 @@ impl HasBottom for FlatSet { impl HasTop for FlatSet { const TOP: Self = Self::Top; } + +#[derive(PartialEq, Eq, Debug)] +pub enum MaybeUnreachable { + Unreachable, + Reachable(T), +} + +impl MaybeUnreachable { + pub fn is_reachable(&self) -> bool { + matches!(self, MaybeUnreachable::Reachable(_)) + } +} + +impl HasBottom for MaybeUnreachable { + const BOTTOM: Self = MaybeUnreachable::Unreachable; +} + +impl HasTop for MaybeUnreachable { + const TOP: Self = MaybeUnreachable::Reachable(T::TOP); +} + +impl MaybeUnreachable { + pub fn contains(&self, elem: T) -> bool + where + S: BitSetExt, + { + match self { + MaybeUnreachable::Unreachable => false, + MaybeUnreachable::Reachable(set) => set.contains(elem), + } + } +} + +impl> BitSetExt for MaybeUnreachable { + fn contains(&self, elem: T) -> bool { + self.contains(elem) + } + + fn union(&mut self, other: &HybridBitSet) { + match self { + MaybeUnreachable::Unreachable => {} + MaybeUnreachable::Reachable(set) => set.union(other), + } + } + + fn subtract(&mut self, other: &HybridBitSet) { + match self { + MaybeUnreachable::Unreachable => {} + MaybeUnreachable::Reachable(set) => set.subtract(other), + } + } +} + +impl Clone for MaybeUnreachable { + fn clone(&self) -> Self { + match self { + MaybeUnreachable::Reachable(x) => MaybeUnreachable::Reachable(x.clone()), + MaybeUnreachable::Unreachable => MaybeUnreachable::Unreachable, + } + } + + fn clone_from(&mut self, source: &Self) { + match (&mut *self, source) { + (MaybeUnreachable::Reachable(x), MaybeUnreachable::Reachable(y)) => { + x.clone_from(&y); + } + _ => *self = source.clone(), + } + } +} + +impl JoinSemiLattice for MaybeUnreachable { + fn join(&mut self, other: &Self) -> bool { + match (&mut *self, &other) { + (_, MaybeUnreachable::Unreachable) => false, + (MaybeUnreachable::Unreachable, _) => { + *self = other.clone(); + true + } + (MaybeUnreachable::Reachable(this), MaybeUnreachable::Reachable(other)) => { + this.join(other) + } + } + } +} diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 8ccd57802d71..b40cf9f46918 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -48,7 +48,7 @@ mod visitor; pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor}; pub use self::direction::{Backward, Direction, Forward}; pub use self::engine::{Engine, EntrySets, Results, ResultsCloned}; -pub use self::lattice::{JoinSemiLattice, MeetSemiLattice}; +pub use self::lattice::{JoinSemiLattice, MaybeUnreachable, MeetSemiLattice}; pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -524,6 +524,22 @@ impl GenKill for ChunkedBitSet { } } +impl> GenKill for MaybeUnreachable { + fn gen(&mut self, elem: T) { + match self { + MaybeUnreachable::Unreachable => {} + MaybeUnreachable::Reachable(set) => set.gen(elem), + } + } + + fn kill(&mut self, elem: T) { + match self { + MaybeUnreachable::Unreachable => {} + MaybeUnreachable::Reachable(set) => set.kill(elem), + } + } +} + impl GenKill for lattice::Dual> { fn gen(&mut self, elem: T) { self.0.insert(elem); diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 900d438f8d53..f627a4867ee6 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -29,8 +29,8 @@ pub use self::drop_flag_effects::{ pub use self::framework::{ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, AnalysisResults, Backward, CallReturnPlaces, CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, - JoinSemiLattice, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, - ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, + JoinSemiLattice, MaybeUnreachable, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, + ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, }; use self::move_paths::MoveData; From 5173d85043918d70aeef3a623c3a247487c28843 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 May 2023 10:20:43 +0000 Subject: [PATCH 051/169] Allow apply_terminator_effect to customize edges. --- compiler/rustc_borrowck/src/dataflow.rs | 15 +- .../src/transform/check_consts/resolver.rs | 13 +- compiler/rustc_middle/src/mir/terminator.rs | 106 +++++++++++ .../src/framework/direction.rs | 167 +++++++----------- .../src/framework/engine.rs | 17 +- .../src/framework/graphviz.rs | 6 +- .../rustc_mir_dataflow/src/framework/mod.rs | 80 ++------- .../rustc_mir_dataflow/src/framework/tests.rs | 7 +- .../src/impls/borrowed_locals.rs | 14 +- .../src/impls/initialized.rs | 46 ++--- .../rustc_mir_dataflow/src/impls/liveness.rs | 74 +++----- .../src/impls/storage_liveness.rs | 43 +++-- compiler/rustc_mir_dataflow/src/lib.rs | 6 +- .../rustc_mir_dataflow/src/value_analysis.rs | 12 +- 14 files changed, 300 insertions(+), 306 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 289a41921a79..796c8ab92914 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -2,12 +2,14 @@ #![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::fx::FxIndexMap; use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, BasicBlock, Body, Location, Place}; +use rustc_middle::mir::{ + self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdge, +}; use rustc_middle::ty::RegionVid; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; use rustc_mir_dataflow::ResultsVisitable; -use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill}; +use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill}; use rustc_mir_dataflow::{Analysis, Direction, Results}; use std::fmt; @@ -404,12 +406,12 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { self.kill_loans_out_of_scope_at_location(trans, location); } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, _location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind { for op in operands { if let mir::InlineAsmOperand::Out { place: Some(place), .. } @@ -419,6 +421,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } } } + terminator.edges() } fn call_return_effect( diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 3a869f7f5472..23cde5d75fd7 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -4,10 +4,12 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind}; +use rustc_middle::mir::{ + self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdge, +}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::JoinSemiLattice; -use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces}; +use rustc_mir_dataflow::{Analysis, AnalysisDomain}; use std::fmt; use std::marker::PhantomData; @@ -345,13 +347,14 @@ where self.transfer_function(state).visit_statement(statement, location); } - fn apply_terminator_effect( + fn apply_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, - terminator: &mir::Terminator<'tcx>, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { self.transfer_function(state).visit_terminator(terminator, location); + terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 6de843515950..24a13d7ed14a 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -10,6 +10,7 @@ use std::iter; use std::slice; pub use super::query::*; +use super::*; #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct SwitchTargets { @@ -430,3 +431,108 @@ impl<'tcx> TerminatorKind<'tcx> { } } } + +#[derive(Copy, Clone, Debug)] +pub enum TerminatorEdge<'mir, 'tcx> { + /// For terminators that have no successor, like `return`. + None, + /// For terminators that a single successor, like `goto`, and `assert` without cleanup block. + Single(BasicBlock), + /// For terminators that two successors, `assert` with cleanup block and `falseEdge`. + Double(BasicBlock, BasicBlock), + /// Special action for `Yield`, `Call` and `InlineAsm` terminators. + AssignOnReturn { + return_: Option, + unwind: UnwindAction, + place: CallReturnPlaces<'mir, 'tcx>, + }, + /// Special edge for `SwitchInt`. + SwitchInt { targets: &'mir SwitchTargets, discr: &'mir Operand<'tcx> }, +} + +/// List of places that are written to after a successful (non-unwind) return +/// from a `Call` or `InlineAsm`. +#[derive(Copy, Clone, Debug)] +pub enum CallReturnPlaces<'a, 'tcx> { + Call(Place<'tcx>), + Yield(Place<'tcx>), + InlineAsm(&'a [InlineAsmOperand<'tcx>]), +} + +impl<'tcx> CallReturnPlaces<'_, 'tcx> { + pub fn for_each(&self, mut f: impl FnMut(Place<'tcx>)) { + match *self { + Self::Call(place) | Self::Yield(place) => f(place), + Self::InlineAsm(operands) => { + for op in operands { + match *op { + InlineAsmOperand::Out { place: Some(place), .. } + | InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place), + _ => {} + } + } + } + } + } +} + +impl<'tcx> Terminator<'tcx> { + pub fn edges(&self) -> TerminatorEdge<'_, 'tcx> { + self.kind.edges() + } +} + +impl<'tcx> TerminatorKind<'tcx> { + pub fn edges(&self) -> TerminatorEdge<'_, 'tcx> { + use TerminatorKind::*; + match *self { + Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdge::None, + + Goto { target } => TerminatorEdge::Single(target), + + Assert { target, unwind, expected: _, msg: _, cond: _ } + | Drop { target, unwind, place: _, replace: _ } + | FalseUnwind { real_target: target, unwind } => match unwind { + UnwindAction::Cleanup(unwind) => TerminatorEdge::Double(target, unwind), + UnwindAction::Continue | UnwindAction::Terminate | UnwindAction::Unreachable => { + TerminatorEdge::Single(target) + } + }, + + FalseEdge { real_target, imaginary_target } => { + TerminatorEdge::Double(real_target, imaginary_target) + } + + Yield { resume: target, drop, resume_arg, value: _ } => { + TerminatorEdge::AssignOnReturn { + return_: Some(target), + unwind: drop.map_or(UnwindAction::Terminate, UnwindAction::Cleanup), + place: CallReturnPlaces::Yield(resume_arg), + } + } + + Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => { + TerminatorEdge::AssignOnReturn { + return_: target, + unwind, + place: CallReturnPlaces::Call(destination), + } + } + + InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination, + unwind, + } => TerminatorEdge::AssignOnReturn { + return_: destination, + unwind, + place: CallReturnPlaces::InlineAsm(operands), + }, + + SwitchInt { ref targets, ref discr } => TerminatorEdge::SwitchInt { targets, discr }, + } + } +} diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 804b44a6bf05..7a5570a4b163 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -1,11 +1,10 @@ -use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets, UnwindAction}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::mir::{ + self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdge, UnwindAction, +}; use std::ops::RangeInclusive; use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{ - Analysis, CallReturnPlaces, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget, -}; +use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; pub trait Direction { const IS_FORWARD: bool; @@ -24,12 +23,14 @@ pub trait Direction { ) where A: Analysis<'tcx>; - fn apply_effects_in_block<'tcx, A>( + fn apply_effects_in_block<'mir, 'tcx, A>( analysis: &mut A, state: &mut A::Domain, block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where + block_data: &'mir mir::BasicBlockData<'tcx>, + statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, + ) -> TerminatorEdge<'mir, 'tcx> + where A: Analysis<'tcx>; fn gen_kill_effects_in_block<'tcx, A>( @@ -51,10 +52,10 @@ pub trait Direction { fn join_state_into_successors_of<'tcx, A>( analysis: &mut A, - tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, exit_state: &mut A::Domain, - block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>), + block: BasicBlock, + edges: TerminatorEdge<'_, 'tcx>, propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>; @@ -66,24 +67,30 @@ pub struct Backward; impl Direction for Backward { const IS_FORWARD: bool = false; - fn apply_effects_in_block<'tcx, A>( + fn apply_effects_in_block<'mir, 'tcx, A>( analysis: &mut A, state: &mut A::Domain, block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where + block_data: &'mir mir::BasicBlockData<'tcx>, + statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, + ) -> TerminatorEdge<'mir, 'tcx> + where A: Analysis<'tcx>, { let terminator = block_data.terminator(); let location = Location { block, statement_index: block_data.statements.len() }; analysis.apply_before_terminator_effect(state, terminator, location); - analysis.apply_terminator_effect(state, terminator, location); - - for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { - let location = Location { block, statement_index }; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); + let edges = analysis.apply_terminator_effect(state, terminator, location); + if let Some(statement_effect) = statement_effect { + statement_effect(block, state) + } else { + for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { + let location = Location { block, statement_index }; + analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_statement_effect(state, statement, location); + } } + edges } fn gen_kill_effects_in_block<'tcx, A>( @@ -94,11 +101,6 @@ impl Direction for Backward { ) where A: GenKillAnalysis<'tcx>, { - let terminator = block_data.terminator(); - let location = Location { block, statement_index: block_data.statements.len() }; - analysis.before_terminator_effect(trans, terminator, location); - analysis.terminator_effect(trans, terminator, location); - for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { let location = Location { block, statement_index }; analysis.before_statement_effect(trans, statement, location); @@ -217,10 +219,10 @@ impl Direction for Backward { fn join_state_into_successors_of<'tcx, A>( analysis: &mut A, - _tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, exit_state: &mut A::Domain, - (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), + bb: BasicBlock, + _edges: TerminatorEdge<'_, 'tcx>, mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, @@ -254,7 +256,11 @@ impl Direction for Backward { mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => { let mut tmp = exit_state.clone(); - analysis.apply_yield_resume_effect(&mut tmp, resume, resume_arg); + analysis.apply_call_return_effect( + &mut tmp, + resume, + CallReturnPlaces::Yield(resume_arg), + ); propagate(pred, &tmp); } @@ -318,24 +324,30 @@ pub struct Forward; impl Direction for Forward { const IS_FORWARD: bool = true; - fn apply_effects_in_block<'tcx, A>( + fn apply_effects_in_block<'mir, 'tcx, A>( analysis: &mut A, state: &mut A::Domain, block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where + block_data: &'mir mir::BasicBlockData<'tcx>, + statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, + ) -> TerminatorEdge<'mir, 'tcx> + where A: Analysis<'tcx>, { - for (statement_index, statement) in block_data.statements.iter().enumerate() { - let location = Location { block, statement_index }; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); + if let Some(statement_effect) = statement_effect { + statement_effect(block, state) + } else { + for (statement_index, statement) in block_data.statements.iter().enumerate() { + let location = Location { block, statement_index }; + analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_statement_effect(state, statement, location); + } } let terminator = block_data.terminator(); let location = Location { block, statement_index: block_data.statements.len() }; analysis.apply_before_terminator_effect(state, terminator, location); - analysis.apply_terminator_effect(state, terminator, location); + analysis.apply_terminator_effect(state, terminator, location) } fn gen_kill_effects_in_block<'tcx, A>( @@ -351,11 +363,6 @@ impl Direction for Forward { analysis.before_statement_effect(trans, statement, location); analysis.statement_effect(trans, statement, location); } - - let terminator = block_data.terminator(); - let location = Location { block, statement_index: block_data.statements.len() }; - analysis.before_terminator_effect(trans, terminator, location); - analysis.terminator_effect(trans, terminator, location); } fn apply_effects_in_range<'tcx, A>( @@ -464,86 +471,32 @@ impl Direction for Forward { fn join_state_into_successors_of<'tcx, A>( analysis: &mut A, - _tcx: TyCtxt<'tcx>, _body: &mir::Body<'tcx>, exit_state: &mut A::Domain, - (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), + bb: BasicBlock, + edges: TerminatorEdge<'_, 'tcx>, mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, { - use mir::TerminatorKind::*; - match bb_data.terminator().kind { - Return | Resume | Terminate | GeneratorDrop | Unreachable => {} - - Goto { target } => propagate(target, exit_state), - - Assert { target, unwind, expected: _, msg: _, cond: _ } - | Drop { target, unwind, place: _, replace: _ } - | FalseUnwind { real_target: target, unwind } => { - if let UnwindAction::Cleanup(unwind) = unwind { - propagate(unwind, exit_state); - } - + match edges { + TerminatorEdge::None => {} + TerminatorEdge::Single(target) => propagate(target, exit_state), + TerminatorEdge::Double(target, unwind) => { propagate(target, exit_state); + propagate(unwind, exit_state); } - - FalseEdge { real_target, imaginary_target } => { - propagate(real_target, exit_state); - propagate(imaginary_target, exit_state); - } - - Yield { resume: target, drop, resume_arg, value: _ } => { - if let Some(drop) = drop { - propagate(drop, exit_state); - } - - analysis.apply_yield_resume_effect(exit_state, target, resume_arg); - propagate(target, exit_state); - } - - Call { unwind, destination, target, func: _, args: _, call_source: _, fn_span: _ } => { + TerminatorEdge::AssignOnReturn { return_, unwind, place } => { + // This must be done *first*, otherwise the unwind path will see the assignments. if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); } - - if let Some(target) = target { - // N.B.: This must be done *last*, otherwise the unwind path will see the call - // return effect. - analysis.apply_call_return_effect( - exit_state, - bb, - CallReturnPlaces::Call(destination), - ); - propagate(target, exit_state); + if let Some(return_) = return_ { + analysis.apply_call_return_effect(exit_state, bb, place); + propagate(return_, exit_state); } } - - InlineAsm { - template: _, - ref operands, - options: _, - line_spans: _, - destination, - unwind, - } => { - if let UnwindAction::Cleanup(unwind) = unwind { - propagate(unwind, exit_state); - } - - if let Some(target) = destination { - // N.B.: This must be done *last*, otherwise the unwind path will see the call - // return effect. - analysis.apply_call_return_effect( - exit_state, - bb, - CallReturnPlaces::InlineAsm(operands), - ); - propagate(target, exit_state); - } - } - - SwitchInt { ref targets, ref discr } => { + TerminatorEdge::SwitchInt { targets, discr } => { let mut applier = ForwardSwitchIntEdgeEffectsApplier { exit_state, targets, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index f9cb6eb360df..346e875f6374 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -264,19 +264,20 @@ where state.clone_from(&entry_sets[bb]); // Apply the block transfer function, using the cached one if it exists. - match &apply_trans_for_block { - Some(apply) => apply(bb, &mut state), - None => { - A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data) - } - } + let edges = A::Direction::apply_effects_in_block( + &mut analysis, + &mut state, + bb, + bb_data, + apply_trans_for_block.as_deref(), + ); A::Direction::join_state_into_successors_of( &mut analysis, - tcx, body, &mut state, - (bb, bb_data), + bb, + edges, |target: BasicBlock, state: &A::Domain| { let set_changed = entry_sets[target].join(state); if set_changed { diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index e331533c3710..1421d9b45cda 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -269,7 +269,11 @@ where self.write_row(w, "", "(on yield resume)", |this, w, fmt| { let state_on_generator_drop = this.results.get().clone(); this.results.apply_custom_effect(|analysis, state| { - analysis.apply_yield_resume_effect(state, resume, resume_arg); + analysis.apply_call_return_effect( + state, + resume, + CallReturnPlaces::Yield(resume_arg), + ); }); write!( diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index b40cf9f46918..4d915997791a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -34,7 +34,7 @@ use std::cmp::Ordering; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_index::Idx; -use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdge}; use rustc_middle::ty::TyCtxt; mod cursor; @@ -163,12 +163,12 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// in this function. That should go in `apply_call_return_effect`. For example, in the /// `InitializedPlaces` analyses, the return place for a function call is not marked as /// initialized here. - fn apply_terminator_effect( + fn apply_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, - terminator: &mir::Terminator<'tcx>, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ); + ) -> TerminatorEdge<'mir, 'tcx>; /// Updates the current dataflow state with an effect that occurs immediately *before* the /// given terminator. @@ -198,20 +198,6 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { return_places: CallReturnPlaces<'_, 'tcx>, ); - /// Updates the current dataflow state with the effect of resuming from a `Yield` terminator. - /// - /// This is similar to `apply_call_return_effect` in that it only takes place after the - /// generator is resumed, not when it is dropped. - /// - /// By default, no effects happen. - fn apply_yield_resume_effect( - &mut self, - _state: &mut Self::Domain, - _resume_block: BasicBlock, - _resume_place: mir::Place<'tcx>, - ) { - } - /// Updates the current dataflow state with the effect of taking a particular branch in a /// `SwitchInt` terminator. /// @@ -306,12 +292,12 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { } /// See `Analysis::apply_terminator_effect`. - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ); + ) -> TerminatorEdge<'mir, 'tcx>; /// See `Analysis::apply_before_terminator_effect`. fn before_terminator_effect( @@ -332,15 +318,6 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { return_places: CallReturnPlaces<'_, 'tcx>, ); - /// See `Analysis::apply_yield_resume_effect`. - fn yield_resume_effect( - &mut self, - _trans: &mut impl GenKill, - _resume_block: BasicBlock, - _resume_place: mir::Place<'tcx>, - ) { - } - /// See `Analysis::apply_switch_int_edge_effects`. fn switch_int_edge_effects>( &mut self, @@ -374,13 +351,13 @@ where self.before_statement_effect(state, statement, location); } - fn apply_terminator_effect( + fn apply_terminator_effect<'mir>( &mut self, state: &mut A::Domain, - terminator: &mir::Terminator<'tcx>, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { - self.terminator_effect(state, terminator, location); + ) -> TerminatorEdge<'mir, 'tcx> { + self.terminator_effect(state, terminator, location) } fn apply_before_terminator_effect( @@ -403,15 +380,6 @@ where self.call_return_effect(state, block, return_places); } - fn apply_yield_resume_effect( - &mut self, - state: &mut A::Domain, - resume_block: BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - self.yield_resume_effect(state, resume_block, resume_place); - } - fn apply_switch_int_edge_effects( &mut self, block: BasicBlock, @@ -621,29 +589,5 @@ pub trait SwitchIntEdgeEffects { fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)); } -/// List of places that are written to after a successful (non-unwind) return -/// from a `Call` or `InlineAsm`. -pub enum CallReturnPlaces<'a, 'tcx> { - Call(mir::Place<'tcx>), - InlineAsm(&'a [mir::InlineAsmOperand<'tcx>]), -} - -impl<'tcx> CallReturnPlaces<'_, 'tcx> { - pub fn for_each(&self, mut f: impl FnMut(mir::Place<'tcx>)) { - match *self { - Self::Call(place) => f(place), - Self::InlineAsm(operands) => { - for op in operands { - match *op { - mir::InlineAsmOperand::Out { place: Some(place), .. } - | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place), - _ => {} - } - } - } - } - } -} - #[cfg(test)] mod tests; diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index cb0ec144ef0b..793f97b6c881 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -198,14 +198,15 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { assert!(state.insert(idx)); } - fn apply_terminator_effect( + fn apply_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { let idx = self.effect(Effect::Primary.at_index(location.statement_index)); assert!(state.insert(idx)); + terminator.edges() } fn apply_before_terminator_effect( diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index d59bbc38644d..98c271a8aa98 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -2,7 +2,6 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use crate::framework::CallReturnPlaces; use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; /// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points @@ -15,7 +14,7 @@ use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; pub struct MaybeBorrowedLocals; impl MaybeBorrowedLocals { - fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> { + pub(super) fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> { TransferFunction { trans } } } @@ -50,13 +49,14 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { self.transfer_function(trans).visit_statement(statement, location); } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - terminator: &Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'mir Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { self.transfer_function(trans).visit_terminator(terminator, location); + terminator.edges() } fn call_return_effect( @@ -69,7 +69,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { } /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. -struct TransferFunction<'a, T> { +pub(super) struct TransferFunction<'a, T> { trans: &'a mut T, } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index cd5b1b4856dd..bec715defd38 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,12 +1,12 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_index::Idx; -use rustc_middle::mir::{self, Body, Location}; +use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdge}; use rustc_middle::ty::{self, TyCtxt}; use crate::drop_flag_effects_for_function_entry; use crate::drop_flag_effects_for_location; use crate::elaborate_drops::DropFlagState; -use crate::framework::{CallReturnPlaces, SwitchIntEdgeEffects}; +use crate::framework::SwitchIntEdgeEffects; use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; use crate::on_lookup_result_bits; use crate::MoveDataParamEnv; @@ -318,15 +318,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - _: &mir::Terminator<'tcx>, + state: &mut Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { - Self::update_bits(trans, path, s) + Self::update_bits(state, path, s) }); + terminator.edges() } fn call_return_effect( @@ -438,15 +439,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { // mutable borrow occurs. Places cannot become uninitialized through a mutable reference. } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }); + terminator.edges() } fn call_return_effect( @@ -559,15 +561,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { }) } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) - }) + }); + terminator.edges() } fn call_return_effect( @@ -640,13 +643,13 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } - #[instrument(skip(self, trans, _terminator), level = "debug")] - fn terminator_effect( + #[instrument(skip(self, trans, terminator), level = "debug")] + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - _terminator: &mir::Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { let (body, move_data) = (self.body, self.move_data()); let term = body[location.block].terminator(); let init_loc_map = &move_data.init_loc_map; @@ -660,6 +663,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { }) .copied(), ); + terminator.edges() } fn call_return_effect( diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index eddf40bdf2ee..e6f9193652ec 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -1,8 +1,10 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Local, Location, Place, StatementKind}; +use rustc_middle::mir::{ + self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdge, +}; -use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis}; +use crate::{Analysis, AnalysisDomain, Backward, GenKill, GenKillAnalysis}; /// A [live-variable dataflow analysis][liveness]. /// @@ -56,13 +58,14 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { TransferFunction(trans).visit_statement(statement, location); } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { TransferFunction(trans).visit_terminator(terminator, location); + terminator.edges() } fn call_return_effect( @@ -72,24 +75,13 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { return_places: CallReturnPlaces<'_, 'tcx>, ) { return_places.for_each(|place| { - if let Some(local) = place.as_local() { - trans.kill(local); - } + YieldResumeEffect(trans).visit_place( + &place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) }); } - - fn yield_resume_effect( - &mut self, - trans: &mut impl GenKill, - _resume_block: mir::BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - YieldResumeEffect(trans).visit_place( - &resume_place, - PlaceContext::MutatingUse(MutatingUseContext::Yield), - Location::START, - ) - } } pub struct TransferFunction<'a, T>(pub &'a mut T); @@ -99,16 +91,12 @@ where T: GenKill, { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - if let PlaceContext::MutatingUse(MutatingUseContext::Yield) = context { - // The resume place is evaluated and assigned to only after generator resumes, so its - // effect is handled separately in `yield_resume_effect`. - return; - } - match DefUse::for_place(*place, context) { Some(DefUse::Def) => { if let PlaceContext::MutatingUse( - MutatingUseContext::Call | MutatingUseContext::AsmOutput, + MutatingUseContext::Yield + | MutatingUseContext::Call + | MutatingUseContext::AsmOutput, ) = context { // For the associated terminators, this is only a `Def` when the terminator returns @@ -287,13 +275,14 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { TransferFunction(trans).visit_statement(statement, location); } - fn apply_terminator_effect( + fn apply_terminator_effect<'mir>( &mut self, trans: &mut Self::Domain, - terminator: &mir::Terminator<'tcx>, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { TransferFunction(trans).visit_terminator(terminator, location); + TerminatorEdge::None } fn apply_call_return_effect( @@ -303,22 +292,11 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { return_places: CallReturnPlaces<'_, 'tcx>, ) { return_places.for_each(|place| { - if let Some(local) = place.as_local() { - trans.remove(local); - } + YieldResumeEffect(trans).visit_place( + &place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), + Location::START, + ) }); } - - fn apply_yield_resume_effect( - &mut self, - trans: &mut Self::Domain, - _resume_block: mir::BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - YieldResumeEffect(trans).visit_place( - &resume_place, - PlaceContext::MutatingUse(MutatingUseContext::Yield), - Location::START, - ) - } } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index d07dd034d2a9..9370efdccf88 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::*; use std::borrow::Cow; use super::MaybeBorrowedLocals; -use crate::{CallReturnPlaces, GenKill, ResultsClonedCursor}; +use crate::{GenKill, ResultsClonedCursor}; #[derive(Clone)] pub struct MaybeStorageLive<'a> { @@ -66,13 +66,14 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { } } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - _trans: &mut impl GenKill, - _: &Terminator<'tcx>, + _trans: &mut Self::Domain, + terminator: &'mir Terminator<'tcx>, _: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { // Terminators have no effect + terminator.edges() } fn call_return_effect( @@ -137,13 +138,14 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead { } } - fn terminator_effect( + fn terminator_effect<'mir>( &mut self, - _trans: &mut impl GenKill, - _: &Terminator<'tcx>, + _: &mut Self::Domain, + terminator: &'mir Terminator<'tcx>, _: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { // Terminators have no effect + terminator.edges() } fn call_return_effect( @@ -254,7 +256,10 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { loc: Location, ) { // If a place is borrowed in a terminator, it needs storage for that terminator. - self.borrowed_locals.mut_analysis().terminator_effect(trans, terminator, loc); + self.borrowed_locals + .mut_analysis() + .transfer_function(trans) + .visit_terminator(terminator, loc); match &terminator.kind { TerminatorKind::Call { destination, .. } => { @@ -300,12 +305,12 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { } } - fn terminator_effect( + fn terminator_effect<'t>( &mut self, - trans: &mut impl GenKill, - terminator: &Terminator<'tcx>, + trans: &mut Self::Domain, + terminator: &'t Terminator<'tcx>, loc: Location, - ) { + ) -> TerminatorEdge<'t, 'tcx> { match terminator.kind { // For call terminators the destination requires storage for the call // and after the call returns successfully, but not after a panic. @@ -337,6 +342,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { } self.check_for_move(trans, loc); + terminator.edges() } fn call_return_effect( @@ -347,15 +353,6 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { ) { return_places.for_each(|place| trans.gen(place.local)); } - - fn yield_resume_effect( - &mut self, - trans: &mut impl GenKill, - _resume_block: BasicBlock, - resume_place: Place<'tcx>, - ) { - trans.gen(resume_place.local); - } } impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index f627a4867ee6..0ec84d2789d5 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -28,9 +28,9 @@ pub use self::drop_flag_effects::{ }; pub use self::framework::{ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, AnalysisResults, Backward, - CallReturnPlaces, CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, - JoinSemiLattice, MaybeUnreachable, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, - ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, + CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, + MaybeUnreachable, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, + ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 17bb8fc37ad1..bda5b3520413 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -47,8 +47,7 @@ use rustc_target::abi::{FieldIdx, VariantIdx}; use crate::lattice::{HasBottom, HasTop}; use crate::{ - fmt::DebugWithContext, Analysis, AnalysisDomain, CallReturnPlaces, JoinSemiLattice, - SwitchIntEdgeEffects, + fmt::DebugWithContext, Analysis, AnalysisDomain, JoinSemiLattice, SwitchIntEdgeEffects, }; pub trait ValueAnalysis<'tcx> { @@ -353,22 +352,23 @@ where } } - fn apply_terminator_effect( + fn apply_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, - terminator: &Terminator<'tcx>, + terminator: &'mir Terminator<'tcx>, _location: Location, - ) { + ) -> TerminatorEdge<'mir, 'tcx> { if state.is_reachable() { self.0.handle_terminator(terminator, state); } + terminator.edges() } fn apply_call_return_effect( &mut self, state: &mut Self::Domain, _block: BasicBlock, - return_places: crate::CallReturnPlaces<'_, 'tcx>, + return_places: CallReturnPlaces<'_, 'tcx>, ) { if state.is_reachable() { self.0.handle_call_return(return_places, state) From 3acfa092db190e0df010769f097a7c5a8619abda Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 May 2023 07:57:05 +0000 Subject: [PATCH 052/169] Only run MaybeInitializedPlaces once for drop elaboration. --- .../src/impls/initialized.rs | 72 +++++++++++++++--- .../src/elaborate_drops.rs | 74 ++++++------------- .../src/remove_uninit_drops.rs | 7 +- .../basic_assignment.main.ElaborateDrops.diff | 4 - ...41110.test.ElaborateDrops.panic-abort.diff | 10 +-- ...1110.test.ElaborateDrops.panic-unwind.diff | 10 +-- ...41888.main.ElaborateDrops.panic-abort.diff | 36 ++++----- ...1888.main.ElaborateDrops.panic-unwind.diff | 36 ++++----- 8 files changed, 129 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index bec715defd38..ebae25146de9 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -10,8 +10,8 @@ use crate::framework::SwitchIntEdgeEffects; use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; use crate::on_lookup_result_bits; use crate::MoveDataParamEnv; -use crate::{drop_flag_effects, on_all_children_bits}; -use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis}; +use crate::{drop_flag_effects, on_all_children_bits, on_all_drop_children_bits}; +use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis, MaybeUnreachable}; /// `MaybeInitializedPlaces` tracks all places that might be /// initialized upon reaching a particular point in the control flow @@ -52,11 +52,33 @@ pub struct MaybeInitializedPlaces<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>, + skip_unreachable_unwind: bool, } impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeInitializedPlaces { tcx, body, mdpe } + MaybeInitializedPlaces { tcx, body, mdpe, skip_unreachable_unwind: false } + } + + pub fn skipping_unreachable_unwind(mut self) -> Self { + self.skip_unreachable_unwind = true; + self + } + + pub fn is_unwind_dead( + &self, + place: mir::Place<'tcx>, + state: &MaybeUnreachable>, + ) -> bool { + if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) { + let mut maybe_live = false; + on_all_drop_children_bits(self.tcx, self.body, self.mdpe, path, |child| { + maybe_live |= state.contains(child); + }); + !maybe_live + } else { + false + } } } @@ -107,11 +129,18 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> { mdpe: &'a MoveDataParamEnv<'tcx>, mark_inactive_variants_as_uninit: bool, + skip_unreachable_unwind: BitSet, } impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false } + MaybeUninitializedPlaces { + tcx, + body, + mdpe, + mark_inactive_variants_as_uninit: false, + skip_unreachable_unwind: BitSet::new_empty(body.basic_blocks.len()), + } } /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an @@ -123,6 +152,14 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { self.mark_inactive_variants_as_uninit = true; self } + + pub fn skipping_unreachable_unwind( + mut self, + unreachable_unwind: BitSet, + ) -> Self { + self.skip_unreachable_unwind = unreachable_unwind; + self + } } impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { @@ -271,18 +308,21 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Domain = ChunkedBitSet; + type Domain = MaybeUnreachable>; const NAME: &'static str = "maybe_init"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = uninitialized - ChunkedBitSet::new_empty(self.move_data().move_paths.len()) + MaybeUnreachable::Unreachable } fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { + *state = MaybeUnreachable::Reachable(ChunkedBitSet::new_empty( + self.move_data().move_paths.len(), + )); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - state.insert(path); + state.gen(path); }); } } @@ -324,10 +364,18 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { terminator: &'mir mir::Terminator<'tcx>, location: Location, ) -> TerminatorEdge<'mir, 'tcx> { + let mut edges = terminator.edges(); + if self.skip_unreachable_unwind + && let mir::TerminatorKind::Drop { target, unwind, place, replace: _ } = terminator.kind + && matches!(unwind, mir::UnwindAction::Cleanup(_)) + && self.is_unwind_dead(place, state) + { + edges = TerminatorEdge::Single(target); + } drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(state, path, s) }); - terminator.edges() + edges } fn call_return_effect( @@ -448,7 +496,13 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }); - terminator.edges() + if self.skip_unreachable_unwind.contains(location.block) { + let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() }; + assert!(matches!(unwind, mir::UnwindAction::Cleanup(_))); + TerminatorEdge::Single(target) + } else { + terminator.edges() + } } fn call_return_effect( diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 43757a9ea353..4d509e349cdf 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -48,6 +48,7 @@ use std::fmt; pub struct ElaborateDrops; impl<'tcx> MirPass<'tcx> for ElaborateDrops { + #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); @@ -65,23 +66,29 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { }; let elaborate_patch = { let env = MoveDataParamEnv { move_data, param_env }; - remove_dead_unwinds(tcx, body, &env); - let inits = MaybeInitializedPlaces::new(tcx, body, &env) + let mut inits = MaybeInitializedPlaces::new(tcx, body, &env) + .skipping_unreachable_unwind() .into_engine(tcx, body) .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); + let dead_unwinds = compute_dead_unwinds(&body, &mut inits); + let mut reachable = BitSet::new_empty(body.basic_blocks.len()); + for bb in body.basic_blocks.indices() { + if inits.results().entry_set_for_block(bb).is_reachable() { + reachable.insert(bb); + } + } let uninits = MaybeUninitializedPlaces::new(tcx, body, &env) .mark_inactive_variants_as_uninit() + .skipping_unreachable_unwind(dead_unwinds) .into_engine(tcx, body) .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); - let reachable = traversal::reachable_as_bitset(body); - let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths); ElaborateDropsCtxt { tcx, @@ -101,63 +108,28 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { /// Removes unwind edges which are known to be unreachable, because they are in `drop` terminators /// that can't drop anything. -fn remove_dead_unwinds<'tcx>( - tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, - env: &MoveDataParamEnv<'tcx>, -) { - debug!("remove_dead_unwinds({:?})", body.span); +#[instrument(level = "trace", skip(body, flow_inits), ret)] +fn compute_dead_unwinds<'mir, 'tcx>( + body: &'mir Body<'tcx>, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, +) -> BitSet { // We only need to do this pass once, because unwind edges can only // reach cleanup blocks, which can't have unwind edges themselves. - let mut dead_unwinds = Vec::new(); - let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) - .into_engine(tcx, body) - .pass_name("remove_dead_unwinds") - .iterate_to_fixpoint() - .into_results_cursor(body); + let mut dead_unwinds = BitSet::new_empty(body.basic_blocks.len()); for (bb, bb_data) in body.basic_blocks.iter_enumerated() { - let place = match bb_data.terminator().kind { - TerminatorKind::Drop { place, unwind: UnwindAction::Cleanup(_), .. } => place, - _ => continue, - }; - - debug!("remove_dead_unwinds @ {:?}: {:?}", bb, bb_data); - - let LookupResult::Exact(path) = env.move_data.rev_lookup.find(place.as_ref()) else { - debug!("remove_dead_unwinds: has parent; skipping"); + let TerminatorKind::Drop { place, unwind: UnwindAction::Cleanup(_), .. } = + bb_data.terminator().kind + else { continue; }; flow_inits.seek_before_primary_effect(body.terminator_loc(bb)); - debug!( - "remove_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}", - bb, - place, - path, - flow_inits.get() - ); - - let mut maybe_live = false; - on_all_drop_children_bits(tcx, body, &env, path, |child| { - maybe_live |= flow_inits.contains(child); - }); - - debug!("remove_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); - if !maybe_live { - dead_unwinds.push(bb); + if flow_inits.analysis().is_unwind_dead(place, flow_inits.get()) { + dead_unwinds.insert(bb); } } - if dead_unwinds.is_empty() { - return; - } - - let basic_blocks = body.basic_blocks.as_mut(); - for &bb in dead_unwinds.iter() { - if let Some(unwind) = basic_blocks[bb].terminator_mut().unwind_mut() { - *unwind = UnwindAction::Unreachable; - } - } + dead_unwinds } struct InitializationData<'mir, 'tcx> { diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index 6f9edd07d736..e89f719d7c98 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -4,7 +4,9 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; -use rustc_mir_dataflow::{self, move_path_children_matching, Analysis, MoveDataParamEnv}; +use rustc_mir_dataflow::{ + self, move_path_children_matching, Analysis, MaybeUnreachable, MoveDataParamEnv, +}; use rustc_target::abi::FieldIdx; use crate::MirPass; @@ -41,6 +43,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops { let TerminatorKind::Drop { place, .. } = &terminator.kind else { continue }; maybe_inits.seek_before_primary_effect(body.terminator_loc(bb)); + let MaybeUnreachable::Reachable(maybe_inits) = maybe_inits.get() else { continue }; // If there's no move path for the dropped place, it's probably a `Deref`. Let it alone. let LookupResult::Exact(mpi) = mdpe.move_data.rev_lookup.find(place.as_ref()) else { @@ -50,7 +53,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops { let should_keep = is_needs_drop_and_init( tcx, param_env, - maybe_inits.get(), + maybe_inits, &mdpe.move_data, place.ty(body, tcx).ty, mpi, diff --git a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff index 9c7b3c5197b6..34a1b5f2ff3c 100644 --- a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff +++ b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff @@ -80,10 +80,6 @@ bb8 (cleanup): { resume; -+ } -+ -+ bb9 (cleanup): { -+ unreachable; } } diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff index eb03a347a19f..00e6ae5a21cd 100644 --- a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff +++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff @@ -80,7 +80,7 @@ bb9 (cleanup): { - drop(_1) -> [return: bb10, unwind terminate]; -+ goto -> bb13; ++ goto -> bb12; } bb10 (cleanup): { @@ -88,15 +88,11 @@ + } + + bb11 (cleanup): { -+ unreachable; -+ } -+ -+ bb12 (cleanup): { + drop(_1) -> [return: bb10, unwind terminate]; + } + -+ bb13 (cleanup): { -+ switchInt(_6) -> [0: bb10, otherwise: bb12]; ++ bb12 (cleanup): { ++ switchInt(_6) -> [0: bb10, otherwise: bb11]; } } diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff index 254658c810db..924207ffc3d8 100644 --- a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff +++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff @@ -80,7 +80,7 @@ bb9 (cleanup): { - drop(_1) -> [return: bb10, unwind terminate]; -+ goto -> bb13; ++ goto -> bb12; } bb10 (cleanup): { @@ -88,15 +88,11 @@ + } + + bb11 (cleanup): { -+ unreachable; -+ } -+ -+ bb12 (cleanup): { + drop(_1) -> [return: bb10, unwind terminate]; + } + -+ bb13 (cleanup): { -+ switchInt(_6) -> [0: bb10, otherwise: bb12]; ++ bb12 (cleanup): { ++ switchInt(_6) -> [0: bb10, otherwise: bb11]; } } diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff index 7c2503f9d3e9..02803285e8ec 100644 --- a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff +++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff @@ -86,7 +86,7 @@ bb9: { StorageDead(_2); - drop(_1) -> [return: bb10, unwind: bb12]; -+ goto -> bb19; ++ goto -> bb18; } bb10: { @@ -106,43 +106,39 @@ resume; + } + -+ bb13 (cleanup): { -+ unreachable; -+ } -+ -+ bb14: { ++ bb13: { + _7 = const false; + goto -> bb10; + } + -+ bb15 (cleanup): { ++ bb14 (cleanup): { + goto -> bb12; + } + -+ bb16: { -+ drop(_1) -> [return: bb14, unwind: bb12]; ++ bb15: { ++ drop(_1) -> [return: bb13, unwind: bb12]; + } + -+ bb17 (cleanup): { ++ bb16 (cleanup): { + drop(_1) -> [return: bb12, unwind terminate]; + } + -+ bb18: { ++ bb17: { + _10 = discriminant(_1); -+ switchInt(move _10) -> [0: bb14, otherwise: bb16]; ++ switchInt(move _10) -> [0: bb13, otherwise: bb15]; + } + -+ bb19: { -+ switchInt(_7) -> [0: bb14, otherwise: bb18]; ++ bb18: { ++ switchInt(_7) -> [0: bb13, otherwise: bb17]; ++ } ++ ++ bb19 (cleanup): { ++ _11 = discriminant(_1); ++ switchInt(move _11) -> [0: bb14, otherwise: bb16]; + } + + bb20 (cleanup): { -+ _11 = discriminant(_1); -+ switchInt(move _11) -> [0: bb15, otherwise: bb17]; -+ } -+ -+ bb21 (cleanup): { -+ switchInt(_7) -> [0: bb12, otherwise: bb20]; ++ switchInt(_7) -> [0: bb12, otherwise: bb19]; } } diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff index 4ef3650cdea3..9d6a3958769e 100644 --- a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff +++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff @@ -86,7 +86,7 @@ bb9: { StorageDead(_2); - drop(_1) -> [return: bb10, unwind continue]; -+ goto -> bb19; ++ goto -> bb18; } bb10: { @@ -106,43 +106,39 @@ resume; + } + -+ bb13 (cleanup): { -+ unreachable; -+ } -+ -+ bb14: { ++ bb13: { + _7 = const false; + goto -> bb10; + } + -+ bb15 (cleanup): { ++ bb14 (cleanup): { + goto -> bb12; + } + -+ bb16: { -+ drop(_1) -> [return: bb14, unwind: bb12]; ++ bb15: { ++ drop(_1) -> [return: bb13, unwind: bb12]; + } + -+ bb17 (cleanup): { ++ bb16 (cleanup): { + drop(_1) -> [return: bb12, unwind terminate]; + } + -+ bb18: { ++ bb17: { + _10 = discriminant(_1); -+ switchInt(move _10) -> [0: bb14, otherwise: bb16]; ++ switchInt(move _10) -> [0: bb13, otherwise: bb15]; + } + -+ bb19: { -+ switchInt(_7) -> [0: bb14, otherwise: bb18]; ++ bb18: { ++ switchInt(_7) -> [0: bb13, otherwise: bb17]; ++ } ++ ++ bb19 (cleanup): { ++ _11 = discriminant(_1); ++ switchInt(move _11) -> [0: bb14, otherwise: bb16]; + } + + bb20 (cleanup): { -+ _11 = discriminant(_1); -+ switchInt(move _11) -> [0: bb15, otherwise: bb17]; -+ } -+ -+ bb21 (cleanup): { -+ switchInt(_7) -> [0: bb12, otherwise: bb20]; ++ switchInt(_7) -> [0: bb12, otherwise: bb19]; } } From f19cd3f2e1fee3679f6596423a0f0c04f793f1b7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 May 2023 10:43:20 +0000 Subject: [PATCH 053/169] Use TerminatorEdge for dataflow-const-prop. --- .../rustc_mir_dataflow/src/value_analysis.rs | 49 +++++++++------ .../src/dataflow_const_prop.rs | 61 ++++++------------- 2 files changed, 48 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index bda5b3520413..f9ab95f61621 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -241,11 +241,19 @@ pub trait ValueAnalysis<'tcx> { /// The effect of a successful function call return should not be /// applied here, see [`Analysis::apply_terminator_effect`]. - fn handle_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State) { + fn handle_terminator<'mir>( + &self, + terminator: &'mir Terminator<'tcx>, + state: &mut State, + ) -> TerminatorEdge<'mir, 'tcx> { self.super_terminator(terminator, state) } - fn super_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State) { + fn super_terminator<'mir>( + &self, + terminator: &'mir Terminator<'tcx>, + state: &mut State, + ) -> TerminatorEdge<'mir, 'tcx> { match &terminator.kind { TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { // Effect is applied by `handle_call_return`. @@ -257,8 +265,10 @@ pub trait ValueAnalysis<'tcx> { // They would have an effect, but are not allowed in this phase. bug!("encountered disallowed terminator"); } + TerminatorKind::SwitchInt { discr, targets } => { + return self.handle_switch_int(discr, targets, state); + } TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } | TerminatorKind::Resume | TerminatorKind::Terminate | TerminatorKind::Return @@ -270,6 +280,7 @@ pub trait ValueAnalysis<'tcx> { // These terminators have no effect on the analysis. } } + terminator.edges() } fn handle_call_return( @@ -290,19 +301,22 @@ pub trait ValueAnalysis<'tcx> { }) } - fn handle_switch_int( + fn handle_switch_int<'mir>( &self, - discr: &Operand<'tcx>, - apply_edge_effects: &mut impl SwitchIntEdgeEffects>, - ) { - self.super_switch_int(discr, apply_edge_effects) + discr: &'mir Operand<'tcx>, + targets: &'mir SwitchTargets, + state: &mut State, + ) -> TerminatorEdge<'mir, 'tcx> { + self.super_switch_int(discr, targets, state) } - fn super_switch_int( + fn super_switch_int<'mir>( &self, - _discr: &Operand<'tcx>, - _apply_edge_effects: &mut impl SwitchIntEdgeEffects>, - ) { + discr: &'mir Operand<'tcx>, + targets: &'mir SwitchTargets, + _state: &mut State, + ) -> TerminatorEdge<'mir, 'tcx> { + TerminatorEdge::SwitchInt { discr, targets } } fn wrap(self) -> ValueAnalysisWrapper @@ -359,9 +373,10 @@ where _location: Location, ) -> TerminatorEdge<'mir, 'tcx> { if state.is_reachable() { - self.0.handle_terminator(terminator, state); + self.0.handle_terminator(terminator, state) + } else { + TerminatorEdge::None } - terminator.edges() } fn apply_call_return_effect( @@ -378,11 +393,9 @@ where fn apply_switch_int_edge_effects( &mut self, _block: BasicBlock, - discr: &Operand<'tcx>, - apply_edge_effects: &mut impl SwitchIntEdgeEffects, + _discr: &Operand<'tcx>, + _apply_edge_effects: &mut impl SwitchIntEdgeEffects, ) { - // FIXME: Dataflow framework provides no access to current state here. - self.0.handle_switch_int(discr, apply_edge_effects) } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 7d7588fcaecd..08a4619591ad 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -13,9 +13,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, }; -use rustc_mir_dataflow::{ - lattice::FlatSet, Analysis, Results, ResultsVisitor, SwitchIntEdgeEffects, -}; +use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor}; use rustc_span::DUMMY_SP; use rustc_target::abi::{Align, FieldIdx, VariantIdx}; @@ -249,49 +247,24 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { .unwrap_or(FlatSet::Top) } - fn handle_switch_int( + fn handle_switch_int<'mir>( &self, - discr: &Operand<'tcx>, - apply_edge_effects: &mut impl SwitchIntEdgeEffects>, - ) { - // FIXME: The dataflow framework only provides the state if we call `apply()`, which makes - // this more inefficient than it has to be. - let mut discr_value = None; - let mut handled = false; - apply_edge_effects.apply(|state, target| { - let discr_value = match discr_value { - Some(value) => value, - None => { - let value = match self.handle_operand(discr, state) { - ValueOrPlace::Value(value) => value, - ValueOrPlace::Place(place) => state.get_idx(place, self.map()), - }; - let result = match value { - FlatSet::Top => FlatSet::Top, - FlatSet::Elem(ScalarTy(scalar, _)) => { - let int = scalar.assert_int(); - FlatSet::Elem(int.assert_bits(int.size())) - } - FlatSet::Bottom => FlatSet::Bottom, - }; - discr_value = Some(result); - result - } - }; + discr: &'mir Operand<'tcx>, + targets: &'mir SwitchTargets, + state: &mut State, + ) -> TerminatorEdge<'mir, 'tcx> { + let value = match self.handle_operand(discr, state) { + ValueOrPlace::Value(value) => value, + ValueOrPlace::Place(place) => state.get_idx(place, self.map()), + }; + let FlatSet::Elem(ScalarTy(scalar, _)) = value else { + // Do nothing if we don't know which branch will be taken. + return TerminatorEdge::SwitchInt { discr, targets }; + }; - let FlatSet::Elem(choice) = discr_value else { - // Do nothing if we don't know which branch will be taken. - return; - }; - - if target.value.map(|n| n == choice).unwrap_or(!handled) { - // Branch is taken. Has no effect on state. - handled = true; - } else { - // Branch is not taken. - state.mark_unreachable(); - } - }) + let int = scalar.assert_int(); + let choice = int.assert_bits(int.size()); + TerminatorEdge::Single(targets.target_for_value(choice)) } } From 6cf15d4cb5bf00bb17b3b8c23a76cc755d082026 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 19 May 2023 17:41:04 +0000 Subject: [PATCH 054/169] Rename MaybeUnreachable. --- .../rustc_mir_dataflow/src/framework/fmt.rs | 16 +++--- .../src/framework/lattice.rs | 55 ++++++++++--------- .../rustc_mir_dataflow/src/framework/mod.rs | 14 +++-- .../src/impls/initialized.rs | 13 ++--- compiler/rustc_mir_dataflow/src/lib.rs | 2 +- .../src/remove_uninit_drops.rs | 4 +- 6 files changed, 55 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs index ac0d2aba39da..e3a66bd952c5 100644 --- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs +++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs @@ -1,7 +1,7 @@ //! Custom formatting traits used when outputting Graphviz diagrams with the results of a dataflow //! analysis. -use super::lattice::MaybeUnreachable; +use super::lattice::MaybeReachable; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_index::Idx; use std::fmt; @@ -125,31 +125,31 @@ where } } -impl DebugWithContext for MaybeUnreachable +impl DebugWithContext for MaybeReachable where S: DebugWithContext, { fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MaybeUnreachable::Unreachable => { + MaybeReachable::Unreachable => { write!(f, "unreachable") } - MaybeUnreachable::Reachable(set) => set.fmt_with(ctxt, f), + MaybeReachable::Reachable(set) => set.fmt_with(ctxt, f), } } fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { match (self, old) { - (MaybeUnreachable::Unreachable, MaybeUnreachable::Unreachable) => Ok(()), - (MaybeUnreachable::Unreachable, MaybeUnreachable::Reachable(set)) => { + (MaybeReachable::Unreachable, MaybeReachable::Unreachable) => Ok(()), + (MaybeReachable::Unreachable, MaybeReachable::Reachable(set)) => { write!(f, "\u{001f}+")?; set.fmt_with(ctxt, f) } - (MaybeUnreachable::Reachable(set), MaybeUnreachable::Unreachable) => { + (MaybeReachable::Reachable(set), MaybeReachable::Unreachable) => { write!(f, "\u{001f}-")?; set.fmt_with(ctxt, f) } - (MaybeUnreachable::Reachable(this), MaybeUnreachable::Reachable(old)) => { + (MaybeReachable::Reachable(this), MaybeReachable::Reachable(old)) => { this.fmt_diff_with(old, ctxt, f) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index 72ebf5754be4..3b89598d2899 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -273,69 +273,75 @@ impl HasTop for FlatSet { const TOP: Self = Self::Top; } +/// Extend a lattice with a bottom value to represent an unreachable execution. +/// +/// The only useful action on an unreachable state is joining it with a reachable one to make it +/// reachable. All other actions, gen/kill for instance, are no-ops. #[derive(PartialEq, Eq, Debug)] -pub enum MaybeUnreachable { +pub enum MaybeReachable { Unreachable, Reachable(T), } -impl MaybeUnreachable { +impl MaybeReachable { pub fn is_reachable(&self) -> bool { - matches!(self, MaybeUnreachable::Reachable(_)) + matches!(self, MaybeReachable::Reachable(_)) } } -impl HasBottom for MaybeUnreachable { - const BOTTOM: Self = MaybeUnreachable::Unreachable; +impl HasBottom for MaybeReachable { + const BOTTOM: Self = MaybeReachable::Unreachable; } -impl HasTop for MaybeUnreachable { - const TOP: Self = MaybeUnreachable::Reachable(T::TOP); +impl HasTop for MaybeReachable { + const TOP: Self = MaybeReachable::Reachable(T::TOP); } -impl MaybeUnreachable { +impl MaybeReachable { + /// Return whether the current state contains the given element. If the state is unreachable, + /// it does no contain anything. pub fn contains(&self, elem: T) -> bool where S: BitSetExt, { match self { - MaybeUnreachable::Unreachable => false, - MaybeUnreachable::Reachable(set) => set.contains(elem), + MaybeReachable::Unreachable => false, + MaybeReachable::Reachable(set) => set.contains(elem), } } } -impl> BitSetExt for MaybeUnreachable { +impl> BitSetExt for MaybeReachable { fn contains(&self, elem: T) -> bool { self.contains(elem) } fn union(&mut self, other: &HybridBitSet) { match self { - MaybeUnreachable::Unreachable => {} - MaybeUnreachable::Reachable(set) => set.union(other), + MaybeReachable::Unreachable => {} + MaybeReachable::Reachable(set) => set.union(other), } } fn subtract(&mut self, other: &HybridBitSet) { match self { - MaybeUnreachable::Unreachable => {} - MaybeUnreachable::Reachable(set) => set.subtract(other), + MaybeReachable::Unreachable => {} + MaybeReachable::Reachable(set) => set.subtract(other), } } } -impl Clone for MaybeUnreachable { +impl Clone for MaybeReachable { fn clone(&self) -> Self { match self { - MaybeUnreachable::Reachable(x) => MaybeUnreachable::Reachable(x.clone()), - MaybeUnreachable::Unreachable => MaybeUnreachable::Unreachable, + MaybeReachable::Reachable(x) => MaybeReachable::Reachable(x.clone()), + MaybeReachable::Unreachable => MaybeReachable::Unreachable, } } fn clone_from(&mut self, source: &Self) { match (&mut *self, source) { - (MaybeUnreachable::Reachable(x), MaybeUnreachable::Reachable(y)) => { + (MaybeReachable::Reachable(x), MaybeReachable::Reachable(y)) => { x.clone_from(&y); } _ => *self = source.clone(), @@ -343,17 +349,16 @@ impl Clone for MaybeUnreachable { } } -impl JoinSemiLattice for MaybeUnreachable { +impl JoinSemiLattice for MaybeReachable { fn join(&mut self, other: &Self) -> bool { + // Unreachable acts as a bottom. match (&mut *self, &other) { - (_, MaybeUnreachable::Unreachable) => false, - (MaybeUnreachable::Unreachable, _) => { + (_, MaybeReachable::Unreachable) => false, + (MaybeReachable::Unreachable, _) => { *self = other.clone(); true } - (MaybeUnreachable::Reachable(this), MaybeUnreachable::Reachable(other)) => { - this.join(other) - } + (MaybeReachable::Reachable(this), MaybeReachable::Reachable(other)) => this.join(other), } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 4d915997791a..9fe8b509c56d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -48,7 +48,7 @@ mod visitor; pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor}; pub use self::direction::{Backward, Direction, Forward}; pub use self::engine::{Engine, EntrySets, Results, ResultsCloned}; -pub use self::lattice::{JoinSemiLattice, MaybeUnreachable, MeetSemiLattice}; +pub use self::lattice::{JoinSemiLattice, MaybeReachable, MeetSemiLattice}; pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -492,18 +492,20 @@ impl GenKill for ChunkedBitSet { } } -impl> GenKill for MaybeUnreachable { +impl> GenKill for MaybeReachable { fn gen(&mut self, elem: T) { match self { - MaybeUnreachable::Unreachable => {} - MaybeUnreachable::Reachable(set) => set.gen(elem), + // If the state is not reachable, adding an element does nothing. + MaybeReachable::Unreachable => {} + MaybeReachable::Reachable(set) => set.gen(elem), } } fn kill(&mut self, elem: T) { match self { - MaybeUnreachable::Unreachable => {} - MaybeUnreachable::Reachable(set) => set.kill(elem), + // If the state is not reachable, killing an element does nothing. + MaybeReachable::Unreachable => {} + MaybeReachable::Reachable(set) => set.kill(elem), } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index ebae25146de9..20d4ba7b51c5 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -11,7 +11,7 @@ use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData use crate::on_lookup_result_bits; use crate::MoveDataParamEnv; use crate::{drop_flag_effects, on_all_children_bits, on_all_drop_children_bits}; -use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis, MaybeUnreachable}; +use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis, MaybeReachable}; /// `MaybeInitializedPlaces` tracks all places that might be /// initialized upon reaching a particular point in the control flow @@ -68,7 +68,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { pub fn is_unwind_dead( &self, place: mir::Place<'tcx>, - state: &MaybeUnreachable>, + state: &MaybeReachable>, ) -> bool { if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) { let mut maybe_live = false; @@ -308,18 +308,17 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Domain = MaybeUnreachable>; + type Domain = MaybeReachable>; const NAME: &'static str = "maybe_init"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = uninitialized - MaybeUnreachable::Unreachable + MaybeReachable::Unreachable } fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { - *state = MaybeUnreachable::Reachable(ChunkedBitSet::new_empty( - self.move_data().move_paths.len(), - )); + *state = + MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len())); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); state.gen(path); diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 0ec84d2789d5..0cdbee19d2c8 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -29,7 +29,7 @@ pub use self::drop_flag_effects::{ pub use self::framework::{ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, AnalysisResults, Backward, CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, - MaybeUnreachable, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, + MaybeReachable, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, }; diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index e89f719d7c98..263849747981 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use rustc_mir_dataflow::{ - self, move_path_children_matching, Analysis, MaybeUnreachable, MoveDataParamEnv, + self, move_path_children_matching, Analysis, MaybeReachable, MoveDataParamEnv, }; use rustc_target::abi::FieldIdx; @@ -43,7 +43,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops { let TerminatorKind::Drop { place, .. } = &terminator.kind else { continue }; maybe_inits.seek_before_primary_effect(body.terminator_loc(bb)); - let MaybeUnreachable::Reachable(maybe_inits) = maybe_inits.get() else { continue }; + let MaybeReachable::Reachable(maybe_inits) = maybe_inits.get() else { continue }; // If there's no move path for the dropped place, it's probably a `Deref`. Let it alone. let LookupResult::Exact(mpi) = mdpe.move_data.rev_lookup.find(place.as_ref()) else { From 388f6a64130ea39c01d6be74c7cbf907c49b310a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 27 May 2023 16:27:04 +0000 Subject: [PATCH 055/169] Make TerminatorEdge plural. --- compiler/rustc_borrowck/src/dataflow.rs | 4 +-- .../src/transform/check_consts/resolver.rs | 4 +-- compiler/rustc_middle/src/mir/terminator.rs | 26 +++++++++---------- .../src/framework/direction.rs | 24 ++++++++--------- .../rustc_mir_dataflow/src/framework/mod.rs | 8 +++--- .../rustc_mir_dataflow/src/framework/tests.rs | 2 +- .../src/impls/borrowed_locals.rs | 2 +- .../src/impls/initialized.rs | 14 +++++----- .../rustc_mir_dataflow/src/impls/liveness.rs | 8 +++--- .../src/impls/storage_liveness.rs | 6 ++--- .../rustc_mir_dataflow/src/value_analysis.rs | 14 +++++----- .../src/dataflow_const_prop.rs | 6 ++--- 12 files changed, 59 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 796c8ab92914..4ac633c263fa 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{ - self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdge, + self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, }; use rustc_middle::ty::RegionVid; use rustc_middle::ty::TyCtxt; @@ -411,7 +411,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, _location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind { for op in operands { if let mir::InlineAsmOperand::Out { place: Some(place), .. } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 23cde5d75fd7..a137f84b7382 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -5,7 +5,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{ - self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdge, + self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges, }; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::JoinSemiLattice; @@ -352,7 +352,7 @@ where state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { self.transfer_function(state).visit_terminator(terminator, location); terminator.edges() } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 24a13d7ed14a..1f878d23b443 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -433,7 +433,7 @@ impl<'tcx> TerminatorKind<'tcx> { } #[derive(Copy, Clone, Debug)] -pub enum TerminatorEdge<'mir, 'tcx> { +pub enum TerminatorEdges<'mir, 'tcx> { /// For terminators that have no successor, like `return`. None, /// For terminators that a single successor, like `goto`, and `assert` without cleanup block. @@ -451,7 +451,7 @@ pub enum TerminatorEdge<'mir, 'tcx> { } /// List of places that are written to after a successful (non-unwind) return -/// from a `Call` or `InlineAsm`. +/// from a `Call`, `Yield` or `InlineAsm`. #[derive(Copy, Clone, Debug)] pub enum CallReturnPlaces<'a, 'tcx> { Call(Place<'tcx>), @@ -477,34 +477,34 @@ impl<'tcx> CallReturnPlaces<'_, 'tcx> { } impl<'tcx> Terminator<'tcx> { - pub fn edges(&self) -> TerminatorEdge<'_, 'tcx> { + pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> { self.kind.edges() } } impl<'tcx> TerminatorKind<'tcx> { - pub fn edges(&self) -> TerminatorEdge<'_, 'tcx> { + pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> { use TerminatorKind::*; match *self { - Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdge::None, + Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdges::None, - Goto { target } => TerminatorEdge::Single(target), + Goto { target } => TerminatorEdges::Single(target), Assert { target, unwind, expected: _, msg: _, cond: _ } | Drop { target, unwind, place: _, replace: _ } | FalseUnwind { real_target: target, unwind } => match unwind { - UnwindAction::Cleanup(unwind) => TerminatorEdge::Double(target, unwind), + UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind), UnwindAction::Continue | UnwindAction::Terminate | UnwindAction::Unreachable => { - TerminatorEdge::Single(target) + TerminatorEdges::Single(target) } }, FalseEdge { real_target, imaginary_target } => { - TerminatorEdge::Double(real_target, imaginary_target) + TerminatorEdges::Double(real_target, imaginary_target) } Yield { resume: target, drop, resume_arg, value: _ } => { - TerminatorEdge::AssignOnReturn { + TerminatorEdges::AssignOnReturn { return_: Some(target), unwind: drop.map_or(UnwindAction::Terminate, UnwindAction::Cleanup), place: CallReturnPlaces::Yield(resume_arg), @@ -512,7 +512,7 @@ impl<'tcx> TerminatorKind<'tcx> { } Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => { - TerminatorEdge::AssignOnReturn { + TerminatorEdges::AssignOnReturn { return_: target, unwind, place: CallReturnPlaces::Call(destination), @@ -526,13 +526,13 @@ impl<'tcx> TerminatorKind<'tcx> { line_spans: _, destination, unwind, - } => TerminatorEdge::AssignOnReturn { + } => TerminatorEdges::AssignOnReturn { return_: destination, unwind, place: CallReturnPlaces::InlineAsm(operands), }, - SwitchInt { ref targets, ref discr } => TerminatorEdge::SwitchInt { targets, discr }, + SwitchInt { ref targets, ref discr } => TerminatorEdges::SwitchInt { targets, discr }, } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 7a5570a4b163..c75a2c6d4f75 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -1,5 +1,5 @@ use rustc_middle::mir::{ - self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdge, UnwindAction, + self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges, UnwindAction, }; use std::ops::RangeInclusive; @@ -29,7 +29,7 @@ pub trait Direction { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, - ) -> TerminatorEdge<'mir, 'tcx> + ) -> TerminatorEdges<'mir, 'tcx> where A: Analysis<'tcx>; @@ -55,7 +55,7 @@ pub trait Direction { body: &mir::Body<'tcx>, exit_state: &mut A::Domain, block: BasicBlock, - edges: TerminatorEdge<'_, 'tcx>, + edges: TerminatorEdges<'_, 'tcx>, propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>; @@ -73,7 +73,7 @@ impl Direction for Backward { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, - ) -> TerminatorEdge<'mir, 'tcx> + ) -> TerminatorEdges<'mir, 'tcx> where A: Analysis<'tcx>, { @@ -222,7 +222,7 @@ impl Direction for Backward { body: &mir::Body<'tcx>, exit_state: &mut A::Domain, bb: BasicBlock, - _edges: TerminatorEdge<'_, 'tcx>, + _edges: TerminatorEdges<'_, 'tcx>, mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, @@ -330,7 +330,7 @@ impl Direction for Forward { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, - ) -> TerminatorEdge<'mir, 'tcx> + ) -> TerminatorEdges<'mir, 'tcx> where A: Analysis<'tcx>, { @@ -474,19 +474,19 @@ impl Direction for Forward { _body: &mir::Body<'tcx>, exit_state: &mut A::Domain, bb: BasicBlock, - edges: TerminatorEdge<'_, 'tcx>, + edges: TerminatorEdges<'_, 'tcx>, mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, { match edges { - TerminatorEdge::None => {} - TerminatorEdge::Single(target) => propagate(target, exit_state), - TerminatorEdge::Double(target, unwind) => { + TerminatorEdges::None => {} + TerminatorEdges::Single(target) => propagate(target, exit_state), + TerminatorEdges::Double(target, unwind) => { propagate(target, exit_state); propagate(unwind, exit_state); } - TerminatorEdge::AssignOnReturn { return_, unwind, place } => { + TerminatorEdges::AssignOnReturn { return_, unwind, place } => { // This must be done *first*, otherwise the unwind path will see the assignments. if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); @@ -496,7 +496,7 @@ impl Direction for Forward { propagate(return_, exit_state); } } - TerminatorEdge::SwitchInt { targets, discr } => { + TerminatorEdges::SwitchInt { targets, discr } => { let mut applier = ForwardSwitchIntEdgeEffectsApplier { exit_state, targets, diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 9fe8b509c56d..ce30c642fcc9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -34,7 +34,7 @@ use std::cmp::Ordering; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_index::Idx; -use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdge}; +use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::TyCtxt; mod cursor; @@ -168,7 +168,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx>; + ) -> TerminatorEdges<'mir, 'tcx>; /// Updates the current dataflow state with an effect that occurs immediately *before* the /// given terminator. @@ -297,7 +297,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx>; + ) -> TerminatorEdges<'mir, 'tcx>; /// See `Analysis::apply_before_terminator_effect`. fn before_terminator_effect( @@ -356,7 +356,7 @@ where state: &mut A::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { self.terminator_effect(state, terminator, location) } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 793f97b6c881..9cce5b26cd30 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -203,7 +203,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { let idx = self.effect(Effect::Primary.at_index(location.statement_index)); assert!(state.insert(idx)); terminator.edges() diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 98c271a8aa98..8d7b50796bbf 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -54,7 +54,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { trans: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { self.transfer_function(trans).visit_terminator(terminator, location); terminator.edges() } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 20d4ba7b51c5..e6d383d626ad 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,6 +1,6 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_index::Idx; -use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdge}; +use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::{self, TyCtxt}; use crate::drop_flag_effects_for_function_entry; @@ -362,14 +362,14 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { let mut edges = terminator.edges(); if self.skip_unreachable_unwind && let mir::TerminatorKind::Drop { target, unwind, place, replace: _ } = terminator.kind && matches!(unwind, mir::UnwindAction::Cleanup(_)) && self.is_unwind_dead(place, state) { - edges = TerminatorEdge::Single(target); + edges = TerminatorEdges::Single(target); } drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(state, path, s) @@ -491,14 +491,14 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }); if self.skip_unreachable_unwind.contains(location.block) { let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() }; assert!(matches!(unwind, mir::UnwindAction::Cleanup(_))); - TerminatorEdge::Single(target) + TerminatorEdges::Single(target) } else { terminator.edges() } @@ -619,7 +619,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }); @@ -702,7 +702,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { let (body, move_data) = (self.body, self.move_data()); let term = body[location.block].terminator(); let init_loc_map = &move_data.init_loc_map; diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index e6f9193652ec..fbe1209092c4 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -1,7 +1,7 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ - self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdge, + self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdges, }; use crate::{Analysis, AnalysisDomain, Backward, GenKill, GenKillAnalysis}; @@ -63,7 +63,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { TransferFunction(trans).visit_terminator(terminator, location); terminator.edges() } @@ -280,9 +280,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { TransferFunction(trans).visit_terminator(terminator, location); - TerminatorEdge::None + TerminatorEdges::None } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 9370efdccf88..bea23b7f7ae1 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -71,7 +71,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { _trans: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, _: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { // Terminators have no effect terminator.edges() } @@ -143,7 +143,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead { _: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, _: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { // Terminators have no effect terminator.edges() } @@ -310,7 +310,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { trans: &mut Self::Domain, terminator: &'t Terminator<'tcx>, loc: Location, - ) -> TerminatorEdge<'t, 'tcx> { + ) -> TerminatorEdges<'t, 'tcx> { match terminator.kind { // For call terminators the destination requires storage for the call // and after the call returns successfully, but not after a panic. diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index f9ab95f61621..766e0257efdc 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -245,7 +245,7 @@ pub trait ValueAnalysis<'tcx> { &self, terminator: &'mir Terminator<'tcx>, state: &mut State, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { self.super_terminator(terminator, state) } @@ -253,7 +253,7 @@ pub trait ValueAnalysis<'tcx> { &self, terminator: &'mir Terminator<'tcx>, state: &mut State, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { match &terminator.kind { TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { // Effect is applied by `handle_call_return`. @@ -306,7 +306,7 @@ pub trait ValueAnalysis<'tcx> { discr: &'mir Operand<'tcx>, targets: &'mir SwitchTargets, state: &mut State, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { self.super_switch_int(discr, targets, state) } @@ -315,8 +315,8 @@ pub trait ValueAnalysis<'tcx> { discr: &'mir Operand<'tcx>, targets: &'mir SwitchTargets, _state: &mut State, - ) -> TerminatorEdge<'mir, 'tcx> { - TerminatorEdge::SwitchInt { discr, targets } + ) -> TerminatorEdges<'mir, 'tcx> { + TerminatorEdges::SwitchInt { discr, targets } } fn wrap(self) -> ValueAnalysisWrapper @@ -371,11 +371,11 @@ where state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, _location: Location, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { if state.is_reachable() { self.0.handle_terminator(terminator, state) } else { - TerminatorEdge::None + TerminatorEdges::None } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 08a4619591ad..605011651765 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -252,19 +252,19 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { discr: &'mir Operand<'tcx>, targets: &'mir SwitchTargets, state: &mut State, - ) -> TerminatorEdge<'mir, 'tcx> { + ) -> TerminatorEdges<'mir, 'tcx> { let value = match self.handle_operand(discr, state) { ValueOrPlace::Value(value) => value, ValueOrPlace::Place(place) => state.get_idx(place, self.map()), }; let FlatSet::Elem(ScalarTy(scalar, _)) = value else { // Do nothing if we don't know which branch will be taken. - return TerminatorEdge::SwitchInt { discr, targets }; + return TerminatorEdges::SwitchInt { discr, targets }; }; let int = scalar.assert_int(); let choice = int.assert_bits(int.size()); - TerminatorEdge::Single(targets.target_for_value(choice)) + TerminatorEdges::Single(targets.target_for_value(choice)) } } From aa697f599e8060ca05ee8f56dc1bd19c73911503 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 27 May 2023 17:08:56 +0000 Subject: [PATCH 056/169] Rename YieldResumeEffect. --- compiler/rustc_mir_dataflow/src/impls/liveness.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index fbe1209092c4..a1f60c84b12e 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -75,9 +75,9 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { return_places: CallReturnPlaces<'_, 'tcx>, ) { return_places.for_each(|place| { - YieldResumeEffect(trans).visit_place( + CallReturnEffect(trans).visit_place( &place, - PlaceContext::MutatingUse(MutatingUseContext::Yield), + PlaceContext::MutatingUse(MutatingUseContext::Store), Location::START, ) }); @@ -119,9 +119,9 @@ where } } -struct YieldResumeEffect<'a, T>(&'a mut T); +struct CallReturnEffect<'a, T>(&'a mut T); -impl<'tcx, T> Visitor<'tcx> for YieldResumeEffect<'_, T> +impl<'tcx, T> Visitor<'tcx> for CallReturnEffect<'_, T> where T: GenKill, { @@ -292,9 +292,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { return_places: CallReturnPlaces<'_, 'tcx>, ) { return_places.for_each(|place| { - YieldResumeEffect(trans).visit_place( + CallReturnEffect(trans).visit_place( &place, - PlaceContext::MutatingUse(MutatingUseContext::Yield), + PlaceContext::MutatingUse(MutatingUseContext::Store), Location::START, ) }); From 7ded3409b83710b9de105a35e1c32a5fa88b1b20 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 27 May 2023 17:11:59 +0000 Subject: [PATCH 057/169] Specify that method only applies statement effects. --- .../src/framework/direction.rs | 6 +++--- .../rustc_mir_dataflow/src/framework/engine.rs | 17 +++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index c75a2c6d4f75..8a9e37c5a4fd 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -33,7 +33,7 @@ pub trait Direction { where A: Analysis<'tcx>; - fn gen_kill_effects_in_block<'tcx, A>( + fn gen_kill_statement_effects_in_block<'tcx, A>( analysis: &mut A, trans: &mut GenKillSet, block: BasicBlock, @@ -93,7 +93,7 @@ impl Direction for Backward { edges } - fn gen_kill_effects_in_block<'tcx, A>( + fn gen_kill_statement_effects_in_block<'tcx, A>( analysis: &mut A, trans: &mut GenKillSet, block: BasicBlock, @@ -350,7 +350,7 @@ impl Direction for Forward { analysis.apply_terminator_effect(state, terminator, location) } - fn gen_kill_effects_in_block<'tcx, A>( + fn gen_kill_statement_effects_in_block<'tcx, A>( analysis: &mut A, trans: &mut GenKillSet, block: BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 346e875f6374..a29962d7717a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -144,7 +144,7 @@ where // gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade // performance in practice. I've tried a few ways to avoid this, but they have downsides. See // the message for the commit that added this FIXME for more information. - apply_trans_for_block: Option>, + apply_statement_trans_for_block: Option>, } impl<'a, 'tcx, A, D, T> Engine<'a, 'tcx, A> @@ -170,7 +170,12 @@ where for (block, block_data) in body.basic_blocks.iter_enumerated() { let trans = &mut trans_for_block[block]; - A::Direction::gen_kill_effects_in_block(&mut analysis, trans, block, block_data); + A::Direction::gen_kill_statement_effects_in_block( + &mut analysis, + trans, + block, + block_data, + ); } let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| { @@ -199,7 +204,7 @@ where tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A, - apply_trans_for_block: Option>, + apply_statement_trans_for_block: Option>, ) -> Self { let mut entry_sets = IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len()); @@ -210,7 +215,7 @@ where bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } - Engine { analysis, tcx, body, pass_name: None, entry_sets, apply_trans_for_block } + Engine { analysis, tcx, body, pass_name: None, entry_sets, apply_statement_trans_for_block } } /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. @@ -232,7 +237,7 @@ where body, mut entry_sets, tcx, - apply_trans_for_block, + apply_statement_trans_for_block, pass_name, .. } = self; @@ -269,7 +274,7 @@ where &mut state, bb, bb_data, - apply_trans_for_block.as_deref(), + apply_statement_trans_for_block.as_deref(), ); A::Direction::join_state_into_successors_of( From e9990ce89ca62e9c9b62bcde89eb11314ec1dc22 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 27 May 2023 17:20:48 +0000 Subject: [PATCH 058/169] Only evaluate yield place after resume in liveness. --- .../rustc_mir_dataflow/src/impls/liveness.rs | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index a1f60c84b12e..063a480e4b5f 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -74,13 +74,19 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { - return_places.for_each(|place| { - CallReturnEffect(trans).visit_place( - &place, - PlaceContext::MutatingUse(MutatingUseContext::Store), + if let CallReturnPlaces::Yield(resume_place) = return_places { + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), Location::START, ) - }); + } else { + return_places.for_each(|place| { + if let Some(local) = place.as_local() { + trans.kill(local); + } + }); + } } } @@ -91,12 +97,16 @@ where T: GenKill, { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { + if let PlaceContext::MutatingUse(MutatingUseContext::Yield) = context { + // The resume place is evaluated and assigned to only after generator resumes, so its + // effect is handled separately in `call_resume_effect`. + return; + } + match DefUse::for_place(*place, context) { Some(DefUse::Def) => { if let PlaceContext::MutatingUse( - MutatingUseContext::Yield - | MutatingUseContext::Call - | MutatingUseContext::AsmOutput, + MutatingUseContext::Call | MutatingUseContext::AsmOutput, ) = context { // For the associated terminators, this is only a `Def` when the terminator returns @@ -119,9 +129,9 @@ where } } -struct CallReturnEffect<'a, T>(&'a mut T); +struct YieldResumeEffect<'a, T>(&'a mut T); -impl<'tcx, T> Visitor<'tcx> for CallReturnEffect<'_, T> +impl<'tcx, T> Visitor<'tcx> for YieldResumeEffect<'_, T> where T: GenKill, { @@ -291,12 +301,18 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { - return_places.for_each(|place| { - CallReturnEffect(trans).visit_place( - &place, - PlaceContext::MutatingUse(MutatingUseContext::Store), + if let CallReturnPlaces::Yield(resume_place) = return_places { + YieldResumeEffect(trans).visit_place( + &resume_place, + PlaceContext::MutatingUse(MutatingUseContext::Yield), Location::START, ) - }); + } else { + return_places.for_each(|place| { + if let Some(local) = place.as_local() { + trans.remove(local); + } + }); + } } } From b8fed2f21c505ed73e238c4c47fdad6d47283475 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 29 May 2023 10:29:54 +0000 Subject: [PATCH 059/169] Make dataflow const-prop handle_switch_int monotonic. --- .../src/dataflow_const_prop.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 605011651765..8f4dc9f69e9a 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -257,14 +257,17 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { ValueOrPlace::Value(value) => value, ValueOrPlace::Place(place) => state.get_idx(place, self.map()), }; - let FlatSet::Elem(ScalarTy(scalar, _)) = value else { - // Do nothing if we don't know which branch will be taken. - return TerminatorEdges::SwitchInt { discr, targets }; - }; - - let int = scalar.assert_int(); - let choice = int.assert_bits(int.size()); - TerminatorEdges::Single(targets.target_for_value(choice)) + match value { + // We are branching on uninitialized data, this is UB, treat it as unreachable. + // This allows the set of visited edges to grow monotonically with the lattice. + FlatSet::Bottom => TerminatorEdges::None, + FlatSet::Elem(ScalarTy(scalar, _)) => { + let int = scalar.assert_int(); + let choice = int.assert_bits(int.size()); + TerminatorEdges::Single(targets.target_for_value(choice)) + } + FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets }, + } } } From 94c5ea350f3fe5fcb8db3e670468bcf92b750046 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 16 Aug 2023 18:15:49 +0000 Subject: [PATCH 060/169] Update doc comment. --- compiler/rustc_mir_transform/src/elaborate_drops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 4d509e349cdf..78c0c6b6b866 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -106,7 +106,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { } } -/// Removes unwind edges which are known to be unreachable, because they are in `drop` terminators +/// Records unwind edges which are known to be unreachable, because they are in `drop` terminators /// that can't drop anything. #[instrument(level = "trace", skip(body, flow_inits), ret)] fn compute_dead_unwinds<'mir, 'tcx>( From f5e4eb91b7626e3a3d34c116c18a85e1bdceef65 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 16 Aug 2023 18:21:06 +0000 Subject: [PATCH 061/169] Use Terminator::edges for backward analysis too. --- compiler/rustc_mir_dataflow/src/impls/liveness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 063a480e4b5f..5aa73c7a9069 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { location: Location, ) -> TerminatorEdges<'mir, 'tcx> { TransferFunction(trans).visit_terminator(terminator, location); - TerminatorEdges::None + terminator.edges() } fn apply_call_return_effect( From 5b2524eb03d0fc88d045ffee3043b66abbbbf6d2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 16 Aug 2023 18:19:48 +0000 Subject: [PATCH 062/169] Do not pre-compute reachable blocks. --- .../src/elaborate_drops.rs | 20 ------------------- .../basic_assignment.main.ElaborateDrops.diff | 6 ++++-- ...41110.test.ElaborateDrops.panic-abort.diff | 3 ++- ...1110.test.ElaborateDrops.panic-unwind.diff | 3 ++- ...41888.main.ElaborateDrops.panic-abort.diff | 6 +++++- ...1888.main.ElaborateDrops.panic-unwind.diff | 6 +++++- 6 files changed, 18 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 78c0c6b6b866..b6b1ae6d3c37 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -74,12 +74,6 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { .iterate_to_fixpoint() .into_results_cursor(body); let dead_unwinds = compute_dead_unwinds(&body, &mut inits); - let mut reachable = BitSet::new_empty(body.basic_blocks.len()); - for bb in body.basic_blocks.indices() { - if inits.results().entry_set_for_block(bb).is_reachable() { - reachable.insert(bb); - } - } let uninits = MaybeUninitializedPlaces::new(tcx, body, &env) .mark_inactive_variants_as_uninit() @@ -97,7 +91,6 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { init_data: InitializationData { inits, uninits }, drop_flags, patch: MirPatch::new(body), - reachable, } .elaborate() }; @@ -262,7 +255,6 @@ struct ElaborateDropsCtxt<'a, 'tcx> { init_data: InitializationData<'a, 'tcx>, drop_flags: IndexVec>, patch: MirPatch<'tcx>, - reachable: BitSet, } impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { @@ -302,9 +294,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn collect_drop_flags(&mut self) { for (bb, data) in self.body.basic_blocks.iter_enumerated() { - if !self.reachable.contains(bb) { - continue; - } let terminator = data.terminator(); let place = match terminator.kind { TerminatorKind::Drop { ref place, .. } => place, @@ -356,9 +345,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn elaborate_drops(&mut self) { for (bb, data) in self.body.basic_blocks.iter_enumerated() { - if !self.reachable.contains(bb) { - continue; - } let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); @@ -437,9 +423,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn drop_flags_for_fn_rets(&mut self) { for (bb, data) in self.body.basic_blocks.iter_enumerated() { - if !self.reachable.contains(bb) { - continue; - } if let TerminatorKind::Call { destination, target: Some(tgt), @@ -478,9 +461,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // clobbered before they are read. for (bb, data) in self.body.basic_blocks.iter_enumerated() { - if !self.reachable.contains(bb) { - continue; - } debug!("drop_flags_for_locs({:?})", data); for i in 0..(data.statements.len() + 1) { debug!("drop_flag_for_locs: stmt {}", i); diff --git a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff index 34a1b5f2ff3c..15269fb8f6c6 100644 --- a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff +++ b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff @@ -47,7 +47,8 @@ bb2 (cleanup): { _5 = move _6; - drop(_6) -> [return: bb6, unwind terminate]; +- drop(_6) -> [return: bb6, unwind terminate]; ++ goto -> bb6; } bb3: { @@ -70,7 +71,8 @@ } bb6 (cleanup): { - drop(_5) -> [return: bb7, unwind terminate]; +- drop(_5) -> [return: bb7, unwind terminate]; ++ goto -> bb7; } bb7 (cleanup): { diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff index 00e6ae5a21cd..65f4806aaf77 100644 --- a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff +++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-abort.diff @@ -47,7 +47,8 @@ bb3 (cleanup): { _2 = move _5; - drop(_5) -> [return: bb8, unwind terminate]; +- drop(_5) -> [return: bb8, unwind terminate]; ++ goto -> bb8; } bb4: { diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff index 924207ffc3d8..4845fc732aab 100644 --- a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff +++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff @@ -47,7 +47,8 @@ bb3 (cleanup): { _2 = move _5; - drop(_5) -> [return: bb8, unwind terminate]; +- drop(_5) -> [return: bb8, unwind terminate]; ++ goto -> bb8; } bb4: { diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff index 02803285e8ec..aca7fe95c183 100644 --- a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff +++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff @@ -54,8 +54,12 @@ } bb4 (cleanup): { ++ _7 = const true; ++ _8 = const true; ++ _9 = const true; _1 = move _3; - drop(_3) -> [return: bb11, unwind terminate]; +- drop(_3) -> [return: bb11, unwind terminate]; ++ goto -> bb11; } bb5: { diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff index 9d6a3958769e..60ce9cd8ad9d 100644 --- a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff +++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff @@ -54,8 +54,12 @@ } bb4 (cleanup): { ++ _7 = const true; ++ _8 = const true; ++ _9 = const true; _1 = move _3; - drop(_3) -> [return: bb11, unwind terminate]; +- drop(_3) -> [return: bb11, unwind terminate]; ++ goto -> bb11; } bb5: { From 072d8c8bbc57358ffd6fa66f6a12365464de185f Mon Sep 17 00:00:00 2001 From: beetrees Date: Wed, 17 May 2023 02:54:13 +0100 Subject: [PATCH 063/169] Fix suggestion for attempting to define a string with single quotes --- .../src/lexer/unescape_error_reporting.rs | 22 +++++++------------ tests/ui/inference/str-as-char.fixed | 1 + tests/ui/inference/str-as-char.rs | 1 + tests/ui/inference/str-as-char.stderr | 13 ++++++++++- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 446472d12945..b659c40b2336 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -80,20 +80,14 @@ pub(crate) fn emit_unescape_error( let sugg = sugg.unwrap_or_else(|| { let prefix = mode.prefix_noraw(); let mut escaped = String::with_capacity(lit.len()); - let mut chrs = lit.chars().peekable(); - while let Some(first) = chrs.next() { - match (first, chrs.peek()) { - ('\\', Some('"')) => { - escaped.push('\\'); - escaped.push('"'); - chrs.next(); - } - ('"', _) => { - escaped.push('\\'); - escaped.push('"') - } - (c, _) => escaped.push(c), - }; + let mut in_escape = false; + for c in lit.chars() { + match c { + '\\' => in_escape = !in_escape, + '"' if !in_escape => escaped.push('\\'), + _ => in_escape = false, + } + escaped.push(c); } let sugg = format!("{prefix}\"{escaped}\""); MoreThanOneCharSugg::Quotes { diff --git a/tests/ui/inference/str-as-char.fixed b/tests/ui/inference/str-as-char.fixed index 6aea809cbdb2..911b067c4d19 100644 --- a/tests/ui/inference/str-as-char.fixed +++ b/tests/ui/inference/str-as-char.fixed @@ -7,4 +7,5 @@ fn main() { let _: &str = "a"; //~ ERROR mismatched types let _: &str = "\"\"\""; //~ ERROR character literal may only contain one codepoint let _: &str = "\"\"\""; //~ ERROR character literal may only contain one codepoint + let _: &str = "\"\"\\\"\\\"\\\\\""; //~ ERROR character literal may only contain one codepoint } diff --git a/tests/ui/inference/str-as-char.rs b/tests/ui/inference/str-as-char.rs index eaa8d788c346..832bc871a9e3 100644 --- a/tests/ui/inference/str-as-char.rs +++ b/tests/ui/inference/str-as-char.rs @@ -7,4 +7,5 @@ fn main() { let _: &str = 'a'; //~ ERROR mismatched types let _: &str = '"""'; //~ ERROR character literal may only contain one codepoint let _: &str = '\"\"\"'; //~ ERROR character literal may only contain one codepoint + let _: &str = '"\"\\"\\\"\\\\"'; //~ ERROR character literal may only contain one codepoint } diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr index 2c84dac8e0c1..216f4cda6988 100644 --- a/tests/ui/inference/str-as-char.stderr +++ b/tests/ui/inference/str-as-char.stderr @@ -20,6 +20,17 @@ help: if you meant to write a `str` literal, use double quotes LL | let _: &str = "\"\"\""; | ~~~~~~~~ +error: character literal may only contain one codepoint + --> $DIR/str-as-char.rs:10:19 + | +LL | let _: &str = '"\"\"\\"\\"'; + | ^^^^^^^^^^^^^^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | let _: &str = "\"\"\\"\\"\\\""; + | ~~~~~~~~~~~~~~~~~~~~ + error[E0308]: mismatched types --> $DIR/str-as-char.rs:7:19 | @@ -33,6 +44,6 @@ help: if you meant to write a `str` literal, use double quotes LL | let _: &str = "a"; | ~~~ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. From 2cc71ba8813e3a651048c18d14411467517c7ddb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 16 Aug 2023 14:28:00 -0700 Subject: [PATCH 064/169] Normalize return type of deduce_future_output_from_obligations --- compiler/rustc_hir_typeck/src/closure.rs | 13 ++++++------- ...normalize-output-in-signature-deduction.rs | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 tests/ui/async-await/normalize-output-in-signature-deduction.rs diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 3e67afb1c3d9..b19fb6da6def 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -711,6 +711,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + let span = self.tcx.def_span(expr_def_id); + let output_ty = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => { self.obligations_for_self_ty(ret_vid).find_map(|obligation| { @@ -724,20 +726,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return None, _ => span_bug!( - self.tcx.def_span(expr_def_id), + span, "async fn generator return type not an inference variable: {ret_ty}" ), }; + let output_ty = self.normalize(span, output_ty); + // async fn that have opaque types in their return type need to redo the conversion to inference variables // as they fetch the still opaque version from the signature. let InferOk { value: output_ty, obligations } = self - .replace_opaque_types_with_inference_vars( - output_ty, - body_def_id, - self.tcx.def_span(expr_def_id), - self.param_env, - ); + .replace_opaque_types_with_inference_vars(output_ty, body_def_id, span, self.param_env); self.register_predicates(obligations); Some(output_ty) diff --git a/tests/ui/async-await/normalize-output-in-signature-deduction.rs b/tests/ui/async-await/normalize-output-in-signature-deduction.rs new file mode 100644 index 000000000000..960065a83a45 --- /dev/null +++ b/tests/ui/async-await/normalize-output-in-signature-deduction.rs @@ -0,0 +1,19 @@ +// edition:2021 +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next +// check-pass + +#![feature(type_alias_impl_trait)] + +struct Foo; + +impl Trait for Foo {} +pub trait Trait {} + +pub type TAIT = impl Trait; + +async fn foo() -> TAIT { + Foo +} + +fn main() {} From 9de696b39fbe661d827ab8d8335df9f1efd86c3b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Aug 2023 09:14:20 +1000 Subject: [PATCH 065/169] Remove some unnecessary (and badly named) local variables. --- compiler/rustc_expand/src/mbe/transcribe.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index a5f83b88f7e4..15e7ab3fe3ee 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -220,16 +220,15 @@ pub(super) fn transcribe<'a>( MatchedTokenTree(tt) => { // `tt`s are emitted into the output stream directly as "raw tokens", // without wrapping them into groups. - let token = tt.clone(); - result.push(token); + result.push(tt.clone()); } MatchedNonterminal(nt) => { // Other variables are emitted into the output stream as groups with // `Delimiter::Invisible` to maintain parsing priorities. // `Interpolated` is currently used for such groups in rustc parser. marker.visit_span(&mut sp); - let token = TokenTree::token_alone(token::Interpolated(nt.clone()), sp); - result.push(token); + result + .push(TokenTree::token_alone(token::Interpolated(nt.clone()), sp)); } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. From 434bfc316293a1b2c959e4f8c8facb1634abf729 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Aug 2023 11:02:35 +1000 Subject: [PATCH 066/169] Remove outdated comment. All nonterminals collect and store tokens now. (Unless they are very simple, e.g. single-token, and can precisely recover them without collecting.) --- compiler/rustc_parse/src/parser/nonterminal.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index f5681532b3af..7e1a2b6a3069 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -101,8 +101,6 @@ impl<'a> Parser<'a> { /// site. #[inline] pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt> { - // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`) - // needs to have them force-captured here. // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, // which requires having captured tokens available. Since we cannot determine // in advance whether or not a proc-macro will be (transitively) invoked, From 3bb85b73b5af587e4934ee006f8d5d81976c7a43 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Aug 2023 11:40:45 +1000 Subject: [PATCH 067/169] Add helpful comments to `tt_prepend_space`. --- compiler/rustc_ast_pretty/src/pprust/state.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 068b255e9f28..58ce73047bce 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -150,6 +150,8 @@ pub fn print_crate<'a>( /// and also addresses some specific regressions described in #63896 and #73345. fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { if let TokenTree::Token(token, _) = prev { + // No space after these tokens, e.g. `x.y`, `$e` + // (The carets point to `prev`.) ^ ^ if matches!(token.kind, token::Dot | token::Dollar) { return false; } @@ -158,10 +160,19 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { } } match tt { + // No space before these tokens, e.g. `foo,`, `println!`, `x.y` + // (The carets point to `token`.) ^ ^ ^ + // + // FIXME: having `Not` here works well for macro invocations like + // `println!()`, but is bad when `!` means "logical not" or "the never + // type", where the lack of space causes ugliness like this: + // `Fn() ->!`, `x =! y`, `if! x { f(); }`. TokenTree::Token(token, _) => !matches!(token.kind, token::Comma | token::Not | token::Dot), + // No space before parentheses if preceded by these tokens, e.g. `foo(...)` TokenTree::Delimited(_, Delimiter::Parenthesis, _) => { !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }, _)) } + // No space before brackets if preceded by these tokens, e.g. `#[...]` TokenTree::Delimited(_, Delimiter::Bracket, _) => { !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }, _)) } From 04cf6b4ac56ee72b6621b82a01074607da70f04b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Aug 2023 12:57:05 +1000 Subject: [PATCH 068/169] Rename `parse_no_question_mark_recover`. Adding a `ty_` makes its purpose much clearer, and consistent with other `parse_ty_*` functions. --- compiler/rustc_parse/src/parser/nonterminal.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 7e1a2b6a3069..7fb517ffdb86 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { } NonterminalKind::Ty => token::NtTy( - self.collect_tokens_no_attrs(|this| this.parse_no_question_mark_recover())?, + self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, ), // this could be handled like a token, since it is one diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 3bb50b05aa34..88e640f1696e 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -180,7 +180,7 @@ impl<'a> Parser<'a> { ) } - pub(super) fn parse_no_question_mark_recover(&mut self) -> PResult<'a, P> { + pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::No, From e8f733370f45dca86356a7358642702c7438fca8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Aug 2023 15:02:30 +1000 Subject: [PATCH 069/169] Add some useful comments to `Parser::look_ahead`. --- compiler/rustc_parse/src/parser/mod.rs | 31 +++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ce4d4a605510..3c3872f2706f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1052,33 +1052,48 @@ impl<'a> Parser<'a> { } /// Look-ahead `dist` tokens of `self.token` and get access to that token there. - /// When `dist == 0` then the current token is looked at. + /// When `dist == 0` then the current token is looked at. `Eof` will be + /// returned if the look-ahead is any distance past the end of the tokens. pub fn look_ahead(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R { if dist == 0 { return looker(&self.token); } - let tree_cursor = &self.token_cursor.tree_cursor; if let Some(&(_, delim, span)) = self.token_cursor.stack.last() && delim != Delimiter::Invisible { + // We are not in the outermost token stream, and the token stream + // we are in has non-skipped delimiters. Look for skipped + // delimiters in the lookahead range. + let tree_cursor = &self.token_cursor.tree_cursor; let all_normal = (0..dist).all(|i| { let token = tree_cursor.look_ahead(i); !matches!(token, Some(TokenTree::Delimited(_, Delimiter::Invisible, _))) }); if all_normal { + // There were no skipped delimiters. Do lookahead by plain indexing. return match tree_cursor.look_ahead(dist - 1) { - Some(tree) => match tree { - TokenTree::Token(token, _) => looker(token), - TokenTree::Delimited(dspan, delim, _) => { - looker(&Token::new(token::OpenDelim(*delim), dspan.open)) + Some(tree) => { + // Indexing stayed within the current token stream. + match tree { + TokenTree::Token(token, _) => looker(token), + TokenTree::Delimited(dspan, delim, _) => { + looker(&Token::new(token::OpenDelim(*delim), dspan.open)) + } } - }, - None => looker(&Token::new(token::CloseDelim(delim), span.close)), + } + None => { + // Indexing went past the end of the current token + // stream. Use the close delimiter, no matter how far + // ahead `dist` went. + looker(&Token::new(token::CloseDelim(delim), span.close)) + } }; } } + // We are in a more complex case. Just clone the token cursor and use + // `next`, skipping delimiters as necessary. Slow but simple. let mut cursor = self.token_cursor.clone(); let mut i = 0; let mut token = Token::dummy(); From 4ab3e9d5b9b1f4163cc5d3208c0c3f7f99f3b2f6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Aug 2023 15:24:06 +1000 Subject: [PATCH 070/169] Add a failing case to `tests/ui/macros/macro-interpolation`. This test currently tests the successful paths for the `Interpolated`/`NtTy`/`Path` case in `parse_path_inner`, but it doesn't test the failure path. --- tests/ui/macros/macro-interpolation.rs | 4 ++-- tests/ui/macros/macro-interpolation.stderr | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/ui/macros/macro-interpolation.stderr diff --git a/tests/ui/macros/macro-interpolation.rs b/tests/ui/macros/macro-interpolation.rs index 35003a79ad70..48c1f19e777f 100644 --- a/tests/ui/macros/macro-interpolation.rs +++ b/tests/ui/macros/macro-interpolation.rs @@ -1,5 +1,3 @@ -// run-pass - macro_rules! overly_complicated { ($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path) => ({ @@ -21,12 +19,14 @@ macro_rules! qpath { (ty, <$type:ty as $trait:ty>::$name:ident) => { <$type as $trait>::$name + //~^ ERROR expected identifier, found `!` }; } pub fn main() { let _: qpath!(path, ::Owned); let _: qpath!(ty, ::Owned); + let _: qpath!(ty, ::Owned); assert!(overly_complicated!(f, x, Option, { return Some(x); }, Some(8), Some(y), y) == 8) diff --git a/tests/ui/macros/macro-interpolation.stderr b/tests/ui/macros/macro-interpolation.stderr new file mode 100644 index 000000000000..7ef1fcbbce3e --- /dev/null +++ b/tests/ui/macros/macro-interpolation.stderr @@ -0,0 +1,16 @@ +error: expected identifier, found `!` + --> $DIR/macro-interpolation.rs:21:19 + | +LL | <$type as $trait>::$name + | ^^^^^^ expected identifier +... +LL | let _: qpath!(ty, ::Owned); + | ----------------------------- + | | + | this macro call doesn't expand to a type + | in this macro invocation + | + = note: this error originates in the macro `qpath` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + From acd3a5e35f48d7afa19ce2f56a473c2b7888908d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Aug 2023 20:11:22 +1000 Subject: [PATCH 071/169] Remove unnecessary braces on `PatWithOr` patterns. --- compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- compiler/rustc_parse/src/parser/nonterminal.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index ce8b46217209..a5959d68fbc8 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -1328,7 +1328,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - NonterminalKind::PatWithOr { .. } => { + NonterminalKind::PatWithOr => { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 7fb517ffdb86..2bf670c24eae 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -64,7 +64,7 @@ impl<'a> Parser<'a> { }, _ => false, }, - NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { + NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { match &token.kind { token::Ident(..) | // box, ref, mut, and other identifiers (can stricten) token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern @@ -79,7 +79,7 @@ impl<'a> Parser<'a> { token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) // leading vert `|` or-pattern - token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr {..}), + token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr), token::Interpolated(nt) => may_be_ident(nt), _ => false, } @@ -127,10 +127,10 @@ impl<'a> Parser<'a> { .into_diagnostic(&self.sess.span_diagnostic)); } }, - NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { + NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { token::NtPat(self.collect_tokens_no_attrs(|this| match kind { NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None), - NonterminalKind::PatWithOr { .. } => this.parse_pat_allow_top_alt( + NonterminalKind::PatWithOr => this.parse_pat_allow_top_alt( None, RecoverComma::No, RecoverColon::No, From f8a21a5df03f393f2c666c3033632b0024fa86ee Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Aug 2023 08:39:20 +1000 Subject: [PATCH 072/169] Use `Nonterminal::*` in `nonterminal.rs`. It makes the code more readable. --- .../rustc_parse/src/parser/nonterminal.rs | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 2bf670c24eae..fc21c0a8fd68 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,5 +1,5 @@ use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, NonterminalKind, Token}; +use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token}; use rustc_ast::HasTokens; use rustc_ast_pretty::pprust; use rustc_errors::IntoDiagnostic; @@ -20,10 +20,7 @@ impl<'a> Parser<'a> { pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { - !matches!( - *nt, - token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) - ) + !matches!(*nt, NtItem(_) | NtBlock(_) | NtVis(_) | NtLifetime(_)) } match kind { @@ -46,20 +43,14 @@ impl<'a> Parser<'a> { token::OpenDelim(Delimiter::Brace) => true, token::Interpolated(nt) => !matches!( **nt, - token::NtItem(_) - | token::NtPat(_) - | token::NtTy(_) - | token::NtIdent(..) - | token::NtMeta(_) - | token::NtPath(_) - | token::NtVis(_) + NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_) | NtVis(_) ), _ => false, }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { token::ModSep | token::Ident(..) => true, token::Interpolated(nt) => match **nt { - token::NtPath(_) | token::NtMeta(_) => true, + NtPath(_) | NtMeta(_) => true, _ => may_be_ident(&nt), }, _ => false, @@ -87,7 +78,7 @@ impl<'a> Parser<'a> { NonterminalKind::Lifetime => match &token.kind { token::Lifetime(_) => true, token::Interpolated(nt) => { - matches!(**nt, token::NtLifetime(_)) + matches!(**nt, NtLifetime(_)) } _ => false, }, @@ -109,7 +100,7 @@ impl<'a> Parser<'a> { // Note that TT is treated differently to all the others. NonterminalKind::TT => return Ok(NtOrTt::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { - Some(item) => token::NtItem(item), + Some(item) => NtItem(item), None => { return Err(UnexpectedNonterminal::Item(self.token.span) .into_diagnostic(&self.sess.span_diagnostic)); @@ -118,17 +109,17 @@ impl<'a> Parser<'a> { NonterminalKind::Block => { // While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`), // the ':block' matcher does not support them - token::NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) + NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(s) => token::NtStmt(P(s)), + Some(s) => NtStmt(P(s)), None => { return Err(UnexpectedNonterminal::Statement(self.token.span) .into_diagnostic(&self.sess.span_diagnostic)); } }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { - token::NtPat(self.collect_tokens_no_attrs(|this| match kind { + NtPat(self.collect_tokens_no_attrs(|this| match kind { NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None), NonterminalKind::PatWithOr => this.parse_pat_allow_top_alt( None, @@ -140,15 +131,15 @@ impl<'a> Parser<'a> { })?) } - NonterminalKind::Expr => token::NtExpr(self.parse_expr_force_collect()?), + NonterminalKind::Expr => NtExpr(self.parse_expr_force_collect()?), NonterminalKind::Literal => { // The `:literal` matcher does not support attributes - token::NtLiteral( + NtLiteral( self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, ) } - NonterminalKind::Ty => token::NtTy( + NonterminalKind::Ty => NtTy( self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, ), @@ -157,7 +148,7 @@ impl<'a> Parser<'a> { if let Some((ident, is_raw)) = get_macro_ident(&self.token) => { self.bump(); - token::NtIdent(ident, is_raw) + NtIdent(ident, is_raw) } NonterminalKind::Ident => { return Err(UnexpectedNonterminal::Ident { @@ -165,16 +156,16 @@ impl<'a> Parser<'a> { token: self.token.clone(), }.into_diagnostic(&self.sess.span_diagnostic)); } - NonterminalKind::Path => token::NtPath( + NonterminalKind::Path => NtPath( P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?), ), - NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item(true)?)), - NonterminalKind::Vis => token::NtVis( + NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(true)?)), + NonterminalKind::Vis => NtVis( P(self.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?), ), NonterminalKind::Lifetime => { if self.check_lifetime() { - token::NtLifetime(self.expect_lifetime().ident) + NtLifetime(self.expect_lifetime().ident) } else { return Err(UnexpectedNonterminal::Lifetime { span: self.token.span, From 9a3c907bdbab9c9e444db4c32997bf621936b891 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Aug 2023 09:25:16 +1000 Subject: [PATCH 073/169] Make some `match`es exhaustive in `nonterminal.rs`. For ones matching more than one or two variants, this is easier to think about. --- .../rustc_parse/src/parser/nonterminal.rs | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index fc21c0a8fd68..3862b7640b6e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -20,7 +20,21 @@ impl<'a> Parser<'a> { pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { /// Checks whether the non-terminal may contain a single (non-keyword) identifier. fn may_be_ident(nt: &token::Nonterminal) -> bool { - !matches!(*nt, NtItem(_) | NtBlock(_) | NtVis(_) | NtLifetime(_)) + match nt { + NtStmt(_) + | NtPat(_) + | NtExpr(_) + | NtTy(_) + | NtIdent(..) + | NtLiteral(_) // `true`, `false` + | NtMeta(_) + | NtPath(_) => true, + + NtItem(_) + | NtBlock(_) + | NtVis(_) + | NtLifetime(_) => false, + } } match kind { @@ -41,10 +55,11 @@ impl<'a> Parser<'a> { }, NonterminalKind::Block => match &token.kind { token::OpenDelim(Delimiter::Brace) => true, - token::Interpolated(nt) => !matches!( - **nt, - NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_) | NtVis(_) - ), + token::Interpolated(nt) => match **nt { + NtBlock(_) | NtLifetime(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, + NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_) + | NtVis(_) => false, + }, _ => false, }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { From e46caaf84bcdfcbd7582b6ee63989f28116c3177 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 11 Aug 2023 09:36:51 +1000 Subject: [PATCH 074/169] Simplify a `match`. `may_be_ident` is true for `NtPath` and `NtMeta`, so we don't need to check for them separately. --- compiler/rustc_parse/src/parser/nonterminal.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 3862b7640b6e..882ecc2a7ea8 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -64,10 +64,7 @@ impl<'a> Parser<'a> { }, NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { token::ModSep | token::Ident(..) => true, - token::Interpolated(nt) => match **nt { - NtPath(_) | NtMeta(_) => true, - _ => may_be_ident(&nt), - }, + token::Interpolated(nt) => may_be_ident(nt), _ => false, }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { From bfb16545a3bbb602756710000acac3ac8acd5186 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 16 Aug 2023 12:42:33 +1000 Subject: [PATCH 075/169] coverage: Anonymize line numbers in `run-coverage` test snapshots This makes the test snapshots less sensitive to lines being added/removed. --- src/tools/compiletest/src/runtest.rs | 17 + tests/run-coverage-rustdoc/doctest.coverage | 216 ++++----- tests/run-coverage/abort.coverage | 132 +++--- tests/run-coverage/assert.coverage | 64 +-- tests/run-coverage/async.coverage | 256 +++++------ tests/run-coverage/async2.coverage | 210 ++++----- tests/run-coverage/closure.coverage | 430 +++++++++--------- tests/run-coverage/closure_macro.coverage | 80 ++-- .../run-coverage/closure_macro_async.coverage | 162 +++---- tests/run-coverage/conditions.coverage | 174 +++---- tests/run-coverage/continue.coverage | 138 +++--- tests/run-coverage/dead_code.coverage | 74 +-- tests/run-coverage/drop_trait.coverage | 66 +-- tests/run-coverage/generator.coverage | 60 +-- tests/run-coverage/generics.coverage | 120 ++--- tests/run-coverage/if.coverage | 56 +-- tests/run-coverage/if_else.coverage | 80 ++-- tests/run-coverage/inline-dead.coverage | 54 +-- tests/run-coverage/inline.coverage | 102 ++--- tests/run-coverage/inner_items.coverage | 114 ++--- tests/run-coverage/issue-83601.coverage | 28 +- tests/run-coverage/issue-84561.coverage | 364 +++++++-------- tests/run-coverage/issue-85461.coverage | 64 +-- tests/run-coverage/issue-93054.coverage | 56 +-- tests/run-coverage/lazy_boolean.coverage | 122 ++--- tests/run-coverage/loop_break_value.coverage | 26 +- tests/run-coverage/loops_branches.coverage | 122 ++--- tests/run-coverage/match_or_pattern.coverage | 90 ++-- tests/run-coverage/nested_loops.coverage | 50 +- tests/run-coverage/no_cov_crate.coverage | 172 +++---- tests/run-coverage/overflow.coverage | 126 ++--- tests/run-coverage/panic_unwind.coverage | 62 +-- tests/run-coverage/partial_eq.coverage | 92 ++-- tests/run-coverage/simple_loop.coverage | 70 +-- tests/run-coverage/simple_match.coverage | 86 ++-- tests/run-coverage/sort_groups.coverage | 76 ++-- tests/run-coverage/test_harness.coverage | 20 +- tests/run-coverage/tight_inf_loop.coverage | 10 +- tests/run-coverage/try_error_result.coverage | 236 +++++----- tests/run-coverage/unused.coverage | 106 ++--- tests/run-coverage/unused_mod.coverage | 18 +- tests/run-coverage/uses_crate.coverage | 286 ++++++------ tests/run-coverage/uses_inline_crate.coverage | 272 +++++------ tests/run-coverage/while.coverage | 10 +- tests/run-coverage/while_early_ret.coverage | 84 ++-- tests/run-coverage/yield.coverage | 74 +-- 46 files changed, 2672 insertions(+), 2655 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 3d237eb25cc9..4ef79af3124a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -18,6 +18,7 @@ use crate::ColorConfig; use regex::{Captures, Regex}; use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; +use std::borrow::Cow; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; use std::env; @@ -664,6 +665,7 @@ impl<'test> TestCx<'test> { fn normalize_coverage_output(&self, coverage: &str) -> Result { let normalized = self.normalize_output(coverage, &[]); + let normalized = Self::anonymize_coverage_line_numbers(&normalized); let mut lines = normalized.lines().collect::>(); @@ -674,6 +676,21 @@ impl<'test> TestCx<'test> { Ok(joined_lines) } + /// Replace line numbers in coverage reports with the placeholder `LL`, + /// so that the tests are less sensitive to lines being added/removed. + fn anonymize_coverage_line_numbers(coverage: &str) -> Cow<'_, str> { + // The coverage reporter prints line numbers at the start of a line. + // They are truncated or left-padded to occupy exactly 5 columns. + // (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.) + // A pipe character `|` appears immediately after the final digit. + // + // Line numbers that appear inside expansion/instantiation subviews + // have an additional prefix of ` |` for each nesting level. + static LINE_NUMBER_RE: Lazy = + Lazy::new(|| Regex::new(r"(?m:^)(?(?: \|)*) *[0-9]+\|").unwrap()); + LINE_NUMBER_RE.replace_all(coverage, "$prefix LL|") + } + /// Coverage reports can describe multiple source files, separated by /// blank lines. The order of these files is unpredictable (since it /// depends on implementation details), so we need to sort the file diff --git a/tests/run-coverage-rustdoc/doctest.coverage b/tests/run-coverage-rustdoc/doctest.coverage index 0fce73a6048b..07f1e6b3ee5d 100644 --- a/tests/run-coverage-rustdoc/doctest.coverage +++ b/tests/run-coverage-rustdoc/doctest.coverage @@ -1,115 +1,115 @@ $DIR/auxiliary/doctest_crate.rs: - 1| |/// A function run only from within doctests - 2| 3|pub fn fn_run_in_doctests(conditional: usize) { - 3| 3| match conditional { - 4| 1| 1 => assert_eq!(1, 1), // this is run, - 5| 1| 2 => assert_eq!(1, 1), // this, - 6| 1| 3 => assert_eq!(1, 1), // and this too - 7| 0| _ => assert_eq!(1, 2), // however this is not - 8| | } - 9| 3|} + LL| |/// A function run only from within doctests + LL| 3|pub fn fn_run_in_doctests(conditional: usize) { + LL| 3| match conditional { + LL| 1| 1 => assert_eq!(1, 1), // this is run, + LL| 1| 2 => assert_eq!(1, 1), // this, + LL| 1| 3 => assert_eq!(1, 1), // and this too + LL| 0| _ => assert_eq!(1, 2), // however this is not + LL| | } + LL| 3|} $DIR/doctest.rs: - 1| |//! This test ensures that code from doctests is properly re-mapped. - 2| |//! See for more info. - 3| |//! - 4| |//! Just some random code: - 5| 1|//! ``` - 6| 1|//! if true { - 7| |//! // this is executed! - 8| 1|//! assert_eq!(1, 1); - 9| |//! } else { - 10| |//! // this is not! - 11| 0|//! assert_eq!(1, 2); - 12| |//! } - 13| 1|//! ``` - 14| |//! - 15| |//! doctest testing external code: - 16| |//! ``` - 17| 1|//! extern crate doctest_crate; - 18| 1|//! doctest_crate::fn_run_in_doctests(1); - 19| 1|//! ``` - 20| |//! - 21| |//! doctest returning a result: - 22| 1|//! ``` - 23| 2|//! #[derive(Debug, PartialEq)] + LL| |//! This test ensures that code from doctests is properly re-mapped. + LL| |//! See for more info. + LL| |//! + LL| |//! Just some random code: + LL| 1|//! ``` + LL| 1|//! if true { + LL| |//! // this is executed! + LL| 1|//! assert_eq!(1, 1); + LL| |//! } else { + LL| |//! // this is not! + LL| 0|//! assert_eq!(1, 2); + LL| |//! } + LL| 1|//! ``` + LL| |//! + LL| |//! doctest testing external code: + LL| |//! ``` + LL| 1|//! extern crate doctest_crate; + LL| 1|//! doctest_crate::fn_run_in_doctests(1); + LL| 1|//! ``` + LL| |//! + LL| |//! doctest returning a result: + LL| 1|//! ``` + LL| 2|//! #[derive(Debug, PartialEq)] ^1 - 24| 1|//! struct SomeError { - 25| 1|//! msg: String, - 26| 1|//! } - 27| 1|//! let mut res = Err(SomeError { msg: String::from("a message") }); - 28| 1|//! if res.is_ok() { - 29| 0|//! res?; - 30| |//! } else { - 31| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { - 32| 1|//! println!("{:?}", res); - 33| 1|//! } + LL| 1|//! struct SomeError { + LL| 1|//! msg: String, + LL| 1|//! } + LL| 1|//! let mut res = Err(SomeError { msg: String::from("a message") }); + LL| 1|//! if res.is_ok() { + LL| 0|//! res?; + LL| |//! } else { + LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { + LL| 1|//! println!("{:?}", res); + LL| 1|//! } ^0 - 34| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { - 35| 1|//! res = Ok(1); - 36| 1|//! } + LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { + LL| 1|//! res = Ok(1); + LL| 1|//! } ^0 - 37| 1|//! res = Ok(0); - 38| |//! } - 39| |//! // need to be explicit because rustdoc cant infer the return type - 40| 1|//! Ok::<(), SomeError>(()) - 41| 1|//! ``` - 42| |//! - 43| |//! doctest with custom main: - 44| |//! ``` - 45| 1|//! fn some_func() { - 46| 1|//! println!("called some_func()"); - 47| 1|//! } - 48| |//! - 49| 0|//! #[derive(Debug)] - 50| |//! struct SomeError; - 51| |//! - 52| |//! extern crate doctest_crate; - 53| |//! - 54| 1|//! fn doctest_main() -> Result<(), SomeError> { - 55| 1|//! some_func(); - 56| 1|//! doctest_crate::fn_run_in_doctests(2); - 57| 1|//! Ok(()) - 58| 1|//! } - 59| |//! - 60| |//! // this `main` is not shown as covered, as it clashes with all the other - 61| |//! // `main` functions that were automatically generated for doctests - 62| |//! fn main() -> Result<(), SomeError> { - 63| |//! doctest_main() - 64| |//! } - 65| |//! ``` - 66| |// aux-build:doctest_crate.rs - 67| |/// doctest attached to fn testing external code: - 68| |/// ``` - 69| 1|/// extern crate doctest_crate; - 70| 1|/// doctest_crate::fn_run_in_doctests(3); - 71| 1|/// ``` - 72| |/// - 73| 1|fn main() { - 74| 1| if true { - 75| 1| assert_eq!(1, 1); - 76| | } else { - 77| 0| assert_eq!(1, 2); - 78| | } - 79| 1|} - 80| | - 81| |// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the - 82| |// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc - 83| |// comment characters). This test produces `llvm-cov show` results demonstrating the problem. - 84| |// - 85| |// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show` - 86| |// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong - 87| |// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or - 88| |// one character past, the `if` block's closing brace. In both cases, these are most likely off - 89| |// by the number of characters stripped from the beginning of each doc comment line: indent - 90| |// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character - 91| |// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are - 92| |// more pronounced, and show up in more places, with background color used to show some distinct - 93| |// code regions with different coverage counts. - 94| |// - 95| |// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each - 96| |// character stripped from the beginning of doc comment lines with a space. This will give coverage - 97| |// results the correct column offsets, and I think it should compile correctly, but I don't know - 98| |// what affect it might have on diagnostic messages from the compiler, and whether anyone would care - 99| |// if the indentation changed. I don't know if there is a more viable solution. + LL| 1|//! res = Ok(0); + LL| |//! } + LL| |//! // need to be explicit because rustdoc cant infer the return type + LL| 1|//! Ok::<(), SomeError>(()) + LL| 1|//! ``` + LL| |//! + LL| |//! doctest with custom main: + LL| |//! ``` + LL| 1|//! fn some_func() { + LL| 1|//! println!("called some_func()"); + LL| 1|//! } + LL| |//! + LL| 0|//! #[derive(Debug)] + LL| |//! struct SomeError; + LL| |//! + LL| |//! extern crate doctest_crate; + LL| |//! + LL| 1|//! fn doctest_main() -> Result<(), SomeError> { + LL| 1|//! some_func(); + LL| 1|//! doctest_crate::fn_run_in_doctests(2); + LL| 1|//! Ok(()) + LL| 1|//! } + LL| |//! + LL| |//! // this `main` is not shown as covered, as it clashes with all the other + LL| |//! // `main` functions that were automatically generated for doctests + LL| |//! fn main() -> Result<(), SomeError> { + LL| |//! doctest_main() + LL| |//! } + LL| |//! ``` + LL| |// aux-build:doctest_crate.rs + LL| |/// doctest attached to fn testing external code: + LL| |/// ``` + LL| 1|/// extern crate doctest_crate; + LL| 1|/// doctest_crate::fn_run_in_doctests(3); + LL| 1|/// ``` + LL| |/// + LL| 1|fn main() { + LL| 1| if true { + LL| 1| assert_eq!(1, 1); + LL| | } else { + LL| 0| assert_eq!(1, 2); + LL| | } + LL| 1|} + LL| | + LL| |// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the + LL| |// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc + LL| |// comment characters). This test produces `llvm-cov show` results demonstrating the problem. + LL| |// + LL| |// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show` + LL| |// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong + LL| |// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or + LL| |// one character past, the `if` block's closing brace. In both cases, these are most likely off + LL| |// by the number of characters stripped from the beginning of each doc comment line: indent + LL| |// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character + LL| |// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are + LL| |// more pronounced, and show up in more places, with background color used to show some distinct + LL| |// code regions with different coverage counts. + LL| |// + LL| |// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each + LL| |// character stripped from the beginning of doc comment lines with a space. This will give coverage + LL| |// results the correct column offsets, and I think it should compile correctly, but I don't know + LL| |// what affect it might have on diagnostic messages from the compiler, and whether anyone would care + LL| |// if the indentation changed. I don't know if there is a more viable solution. diff --git a/tests/run-coverage/abort.coverage b/tests/run-coverage/abort.coverage index a71c58d618da..ceef63867807 100644 --- a/tests/run-coverage/abort.coverage +++ b/tests/run-coverage/abort.coverage @@ -1,69 +1,69 @@ - 1| |#![feature(c_unwind)] - 2| |#![allow(unused_assignments)] - 3| | - 4| 12|extern "C" fn might_abort(should_abort: bool) { - 5| 12| if should_abort { - 6| 0| println!("aborting..."); - 7| 0| panic!("panics and aborts"); - 8| 12| } else { - 9| 12| println!("Don't Panic"); - 10| 12| } - 11| 12|} - 12| | - 13| 1|fn main() -> Result<(), u8> { - 14| 1| let mut countdown = 10; - 15| 11| while countdown > 0 { - 16| 10| if countdown < 5 { - 17| 4| might_abort(false); - 18| 6| } - 19| | // See discussion (below the `Notes` section) on coverage results for the closing brace. - 20| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line. + LL| |#![feature(c_unwind)] + LL| |#![allow(unused_assignments)] + LL| | + LL| 12|extern "C" fn might_abort(should_abort: bool) { + LL| 12| if should_abort { + LL| 0| println!("aborting..."); + LL| 0| panic!("panics and aborts"); + LL| 12| } else { + LL| 12| println!("Don't Panic"); + LL| 12| } + LL| 12|} + LL| | + LL| 1|fn main() -> Result<(), u8> { + LL| 1| let mut countdown = 10; + LL| 11| while countdown > 0 { + LL| 10| if countdown < 5 { + LL| 4| might_abort(false); + LL| 6| } + LL| | // See discussion (below the `Notes` section) on coverage results for the closing brace. + LL| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line. ^4 ^6 - 21| | // For the following example, the closing brace is the last character on the line. - 22| | // This shows the character after the closing brace is highlighted, even if that next - 23| | // character is a newline. - 24| 10| if countdown < 5 { might_abort(false); } + LL| | // For the following example, the closing brace is the last character on the line. + LL| | // This shows the character after the closing brace is highlighted, even if that next + LL| | // character is a newline. + LL| 10| if countdown < 5 { might_abort(false); } ^4 ^6 - 25| 10| countdown -= 1; - 26| | } - 27| 1| Ok(()) - 28| 1|} - 29| | - 30| |// Notes: - 31| |// 1. Compare this program and its coverage results to those of the similar tests - 32| |// `panic_unwind.rs` and `try_error_result.rs`. - 33| |// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`. - 34| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage - 35| |// results show where the program did and did not execute. - 36| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as - 37| |// intended"). Coverage results would show no executed coverage regions. - 38| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status - 39| |// (on Linux at least). - 40| | - 41| |/* - 42| | - 43| |Expect the following coverage results: - 44| | - 45| |```text - 46| | 16| 11| while countdown > 0 { - 47| | 17| 10| if countdown < 5 { - 48| | 18| 4| might_abort(false); - 49| | 19| 6| } - 50| |``` - 51| | - 52| |This is actually correct. - 53| | - 54| |The condition `countdown < 5` executed 10 times (10 loop iterations). - 55| | - 56| |It evaluated to `true` 4 times, and executed the `might_abort()` call. - 57| | - 58| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit - 59| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s - 60| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the - 61| |non-true condition. - 62| | - 63| |As another example of why this is important, say the condition was `countdown < 50`, which is always - 64| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. - 65| |The closing brace would have a count of `0`, highlighting the missed coverage. - 66| |*/ + LL| 10| countdown -= 1; + LL| | } + LL| 1| Ok(()) + LL| 1|} + LL| | + LL| |// Notes: + LL| |// 1. Compare this program and its coverage results to those of the similar tests + LL| |// `panic_unwind.rs` and `try_error_result.rs`. + LL| |// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`. + LL| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage + LL| |// results show where the program did and did not execute. + LL| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as + LL| |// intended"). Coverage results would show no executed coverage regions. + LL| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status + LL| |// (on Linux at least). + LL| | + LL| |/* + LL| | + LL| |Expect the following coverage results: + LL| | + LL| |```text + LL| | 16| 11| while countdown > 0 { + LL| | 17| 10| if countdown < 5 { + LL| | 18| 4| might_abort(false); + LL| | 19| 6| } + LL| |``` + LL| | + LL| |This is actually correct. + LL| | + LL| |The condition `countdown < 5` executed 10 times (10 loop iterations). + LL| | + LL| |It evaluated to `true` 4 times, and executed the `might_abort()` call. + LL| | + LL| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit + LL| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s + LL| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the + LL| |non-true condition. + LL| | + LL| |As another example of why this is important, say the condition was `countdown < 50`, which is always + LL| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. + LL| |The closing brace would have a count of `0`, highlighting the missed coverage. + LL| |*/ diff --git a/tests/run-coverage/assert.coverage b/tests/run-coverage/assert.coverage index a7134a149e2f..3c6108e436a1 100644 --- a/tests/run-coverage/assert.coverage +++ b/tests/run-coverage/assert.coverage @@ -1,34 +1,34 @@ - 1| |#![allow(unused_assignments)] - 2| |// failure-status: 101 - 3| | - 4| 4|fn might_fail_assert(one_plus_one: u32) { - 5| 4| println!("does 1 + 1 = {}?", one_plus_one); - 6| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); + LL| |#![allow(unused_assignments)] + LL| |// failure-status: 101 + LL| | + LL| 4|fn might_fail_assert(one_plus_one: u32) { + LL| 4| println!("does 1 + 1 = {}?", one_plus_one); + LL| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); ^1 - 7| 3|} - 8| | - 9| 1|fn main() -> Result<(),u8> { - 10| 1| let mut countdown = 10; - 11| 11| while countdown > 0 { - 12| 11| if countdown == 1 { - 13| 1| might_fail_assert(3); - 14| 10| } else if countdown < 5 { - 15| 3| might_fail_assert(2); - 16| 6| } - 17| 10| countdown -= 1; - 18| | } - 19| 0| Ok(()) - 20| 0|} - 21| | - 22| |// Notes: - 23| |// 1. Compare this program and its coverage results to those of the very similar test - 24| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. - 25| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or - 26| |// related `assert_*!()` macro. - 27| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce - 28| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to - 29| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). - 30| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test - 31| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the - 32| |// Rust compiler to check for runtime failures, such as numeric overflows. + LL| 3|} + LL| | + LL| 1|fn main() -> Result<(),u8> { + LL| 1| let mut countdown = 10; + LL| 11| while countdown > 0 { + LL| 11| if countdown == 1 { + LL| 1| might_fail_assert(3); + LL| 10| } else if countdown < 5 { + LL| 3| might_fail_assert(2); + LL| 6| } + LL| 10| countdown -= 1; + LL| | } + LL| 0| Ok(()) + LL| 0|} + LL| | + LL| |// Notes: + LL| |// 1. Compare this program and its coverage results to those of the very similar test + LL| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. + LL| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or + LL| |// related `assert_*!()` macro. + LL| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce + LL| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to + LL| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). + LL| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test + LL| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the + LL| |// Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/tests/run-coverage/async.coverage b/tests/run-coverage/async.coverage index 93c1535b06b5..07bc16c2d926 100644 --- a/tests/run-coverage/async.coverage +++ b/tests/run-coverage/async.coverage @@ -1,139 +1,139 @@ - 1| |#![allow(unused_assignments, dead_code)] - 2| | - 3| |// compile-flags: --edition=2018 -C opt-level=1 - 4| | - 5| 1|async fn c(x: u8) -> u8 { - 6| 1| if x == 8 { - 7| 1| 1 - 8| | } else { - 9| 0| 0 - 10| | } - 11| 1|} - 12| | - 13| 0|async fn d() -> u8 { 1 } - 14| | - 15| 0|async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` - 16| | - 17| 1|async fn f() -> u8 { 1 } - 18| | - 19| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` - 20| | - 21| 1|pub async fn g(x: u8) { - 22| 0| match x { - 23| 0| y if e().await == y => (), - 24| 0| y if f().await == y => (), - 25| 0| _ => (), - 26| | } - 27| 0|} - 28| | - 29| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not - 30| 0| // executed (not awaited) so the open brace has a `0` count (at least when - 31| 0| // displayed with `llvm-cov show` in color-mode). - 32| 0| match x { - 33| 0| y if foo().await[y] => (), - 34| 0| _ => (), - 35| | } - 36| 0|} - 37| | - 38| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions: - 39| 1| // (a) the function signature, counted when the function is called; and - 40| 1| // (b) the open brace for the function body, counted once when the body is - 41| 1| // executed asynchronously. - 42| 1| match x { - 43| 1| y if c(x).await == y + 1 => { d().await; } + LL| |#![allow(unused_assignments, dead_code)] + LL| | + LL| |// compile-flags: --edition=2018 -C opt-level=1 + LL| | + LL| 1|async fn c(x: u8) -> u8 { + LL| 1| if x == 8 { + LL| 1| 1 + LL| | } else { + LL| 0| 0 + LL| | } + LL| 1|} + LL| | + LL| 0|async fn d() -> u8 { 1 } + LL| | + LL| 0|async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` + LL| | + LL| 1|async fn f() -> u8 { 1 } + LL| | + LL| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` + LL| | + LL| 1|pub async fn g(x: u8) { + LL| 0| match x { + LL| 0| y if e().await == y => (), + LL| 0| y if f().await == y => (), + LL| 0| _ => (), + LL| | } + LL| 0|} + LL| | + LL| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not + LL| 0| // executed (not awaited) so the open brace has a `0` count (at least when + LL| 0| // displayed with `llvm-cov show` in color-mode). + LL| 0| match x { + LL| 0| y if foo().await[y] => (), + LL| 0| _ => (), + LL| | } + LL| 0|} + LL| | + LL| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions: + LL| 1| // (a) the function signature, counted when the function is called; and + LL| 1| // (b) the open brace for the function body, counted once when the body is + LL| 1| // executed asynchronously. + LL| 1| match x { + LL| 1| y if c(x).await == y + 1 => { d().await; } ^0 ^0 ^0 ^0 - 44| 1| y if f().await == y + 1 => (), + LL| 1| y if f().await == y + 1 => (), ^0 ^0 ^0 - 45| 1| _ => (), - 46| | } - 47| 1|} - 48| | - 49| 1|fn j(x: u8) { - 50| 1| // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. - 51| 1| fn c(x: u8) -> u8 { - 52| 1| if x == 8 { - 53| 1| 1 // This line appears covered, but the 1-character expression span covering the `1` + LL| 1| _ => (), + LL| | } + LL| 1|} + LL| | + LL| 1|fn j(x: u8) { + LL| 1| // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + LL| 1| fn c(x: u8) -> u8 { + LL| 1| if x == 8 { + LL| 1| 1 // This line appears covered, but the 1-character expression span covering the `1` ^0 - 54| 1| // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because - 55| 1| // `fn j()` executes the open brace for the function body, followed by the function's - 56| 1| // first executable statement, `match x`. Inner function declarations are not - 57| 1| // "visible" to the MIR for `j()`, so the code region counts all lines between the - 58| 1| // open brace and the first statement as executed, which is, in a sense, true. - 59| 1| // `llvm-cov show` overcomes this kind of situation by showing the actual counts - 60| 1| // of the enclosed coverages, (that is, the `1` expression was not executed, and - 61| 1| // accurately displays a `0`). - 62| 1| } else { - 63| 1| 0 - 64| 1| } - 65| 1| } - 66| 1| fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed + LL| 1| // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + LL| 1| // `fn j()` executes the open brace for the function body, followed by the function's + LL| 1| // first executable statement, `match x`. Inner function declarations are not + LL| 1| // "visible" to the MIR for `j()`, so the code region counts all lines between the + LL| 1| // open brace and the first statement as executed, which is, in a sense, true. + LL| 1| // `llvm-cov show` overcomes this kind of situation by showing the actual counts + LL| 1| // of the enclosed coverages, (that is, the `1` expression was not executed, and + LL| 1| // accurately displays a `0`). + LL| 1| } else { + LL| 1| 0 + LL| 1| } + LL| 1| } + LL| 1| fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed ^0 - 67| 1| fn f() -> u8 { 1 } - 68| 1| match x { - 69| 1| y if c(x) == y + 1 => { d(); } + LL| 1| fn f() -> u8 { 1 } + LL| 1| match x { + LL| 1| y if c(x) == y + 1 => { d(); } ^0 ^0 - 70| 1| y if f() == y + 1 => (), + LL| 1| y if f() == y + 1 => (), ^0 ^0 - 71| 1| _ => (), - 72| | } - 73| 1|} - 74| | - 75| 0|fn k(x: u8) { // unused function - 76| 0| match x { - 77| 0| 1 => (), - 78| 0| 2 => (), - 79| 0| _ => (), - 80| | } - 81| 0|} - 82| | - 83| 1|fn l(x: u8) { - 84| 1| match x { - 85| 0| 1 => (), - 86| 0| 2 => (), - 87| 1| _ => (), - 88| | } - 89| 1|} - 90| | - 91| 1|async fn m(x: u8) -> u8 { x - 1 } + LL| 1| _ => (), + LL| | } + LL| 1|} + LL| | + LL| 0|fn k(x: u8) { // unused function + LL| 0| match x { + LL| 0| 1 => (), + LL| 0| 2 => (), + LL| 0| _ => (), + LL| | } + LL| 0|} + LL| | + LL| 1|fn l(x: u8) { + LL| 1| match x { + LL| 0| 1 => (), + LL| 0| 2 => (), + LL| 1| _ => (), + LL| | } + LL| 1|} + LL| | + LL| 1|async fn m(x: u8) -> u8 { x - 1 } ^0 - 92| | - 93| 1|fn main() { - 94| 1| let _ = g(10); - 95| 1| let _ = h(9); - 96| 1| let mut future = Box::pin(i(8)); - 97| 1| j(7); - 98| 1| l(6); - 99| 1| let _ = m(5); - 100| 1| executor::block_on(future.as_mut()); - 101| 1|} - 102| | - 103| |mod executor { - 104| | use core::{ - 105| | future::Future, - 106| | pin::Pin, - 107| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 108| | }; - 109| | - 110| 1| pub fn block_on(mut future: F) -> F::Output { - 111| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 112| 1| use std::hint::unreachable_unchecked; - 113| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - 114| 1| |_| unsafe { unreachable_unchecked() }, // clone + LL| | + LL| 1|fn main() { + LL| 1| let _ = g(10); + LL| 1| let _ = h(9); + LL| 1| let mut future = Box::pin(i(8)); + LL| 1| j(7); + LL| 1| l(6); + LL| 1| let _ = m(5); + LL| 1| executor::block_on(future.as_mut()); + LL| 1|} + LL| | + LL| |mod executor { + LL| | use core::{ + LL| | future::Future, + LL| | pin::Pin, + LL| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + LL| | }; + LL| | + LL| 1| pub fn block_on(mut future: F) -> F::Output { + LL| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + LL| 1| use std::hint::unreachable_unchecked; + LL| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + LL| 1| |_| unsafe { unreachable_unchecked() }, // clone ^0 - 115| 1| |_| unsafe { unreachable_unchecked() }, // wake + LL| 1| |_| unsafe { unreachable_unchecked() }, // wake ^0 - 116| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + LL| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref ^0 - 117| 1| |_| (), - 118| 1| ); - 119| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 120| 1| let mut context = Context::from_waker(&waker); - 121| | - 122| | loop { - 123| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 124| 1| break val; - 125| 0| } - 126| | } - 127| 1| } - 128| |} + LL| 1| |_| (), + LL| 1| ); + LL| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + LL| 1| let mut context = Context::from_waker(&waker); + LL| | + LL| | loop { + LL| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + LL| 1| break val; + LL| 0| } + LL| | } + LL| 1| } + LL| |} diff --git a/tests/run-coverage/async2.coverage b/tests/run-coverage/async2.coverage index 500dde1f2698..7e0139ae0362 100644 --- a/tests/run-coverage/async2.coverage +++ b/tests/run-coverage/async2.coverage @@ -1,116 +1,116 @@ - 1| |// compile-flags: --edition=2018 - 2| | - 3| |use core::{ - 4| | future::Future, - 5| | marker::Send, - 6| | pin::Pin, - 7| |}; - 8| | - 9| 1|fn non_async_func() { - 10| 1| println!("non_async_func was covered"); - 11| 1| let b = true; - 12| 1| if b { - 13| 1| println!("non_async_func println in block"); - 14| 1| } + LL| |// compile-flags: --edition=2018 + LL| | + LL| |use core::{ + LL| | future::Future, + LL| | marker::Send, + LL| | pin::Pin, + LL| |}; + LL| | + LL| 1|fn non_async_func() { + LL| 1| println!("non_async_func was covered"); + LL| 1| let b = true; + LL| 1| if b { + LL| 1| println!("non_async_func println in block"); + LL| 1| } ^0 - 15| 1|} - 16| | - 17| | - 18| | - 19| | - 20| 1|async fn async_func() { - 21| 1| println!("async_func was covered"); - 22| 1| let b = true; - 23| 1| if b { - 24| 1| println!("async_func println in block"); - 25| 1| } + LL| 1|} + LL| | + LL| | + LL| | + LL| | + LL| 1|async fn async_func() { + LL| 1| println!("async_func was covered"); + LL| 1| let b = true; + LL| 1| if b { + LL| 1| println!("async_func println in block"); + LL| 1| } ^0 - 26| 1|} - 27| | - 28| | - 29| | - 30| | - 31| 1|async fn async_func_just_println() { - 32| 1| println!("async_func_just_println was covered"); - 33| 1|} - 34| | - 35| 1|fn main() { - 36| 1| println!("codecovsample::main"); - 37| 1| - 38| 1| non_async_func(); - 39| 1| - 40| 1| executor::block_on(async_func()); - 41| 1| executor::block_on(async_func_just_println()); - 42| 1|} - 43| | - 44| |mod executor { - 45| | use core::{ - 46| | future::Future, - 47| | pin::Pin, - 48| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 49| | }; - 50| | - 51| 2| pub fn block_on(mut future: F) -> F::Output { - 52| 2| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 53| 2| use std::hint::unreachable_unchecked; - 54| 2| static VTABLE: RawWakerVTable = RawWakerVTable::new( - 55| 2| |_| unsafe { unreachable_unchecked() }, // clone + LL| 1|} + LL| | + LL| | + LL| | + LL| | + LL| 1|async fn async_func_just_println() { + LL| 1| println!("async_func_just_println was covered"); + LL| 1|} + LL| | + LL| 1|fn main() { + LL| 1| println!("codecovsample::main"); + LL| 1| + LL| 1| non_async_func(); + LL| 1| + LL| 1| executor::block_on(async_func()); + LL| 1| executor::block_on(async_func_just_println()); + LL| 1|} + LL| | + LL| |mod executor { + LL| | use core::{ + LL| | future::Future, + LL| | pin::Pin, + LL| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + LL| | }; + LL| | + LL| 2| pub fn block_on(mut future: F) -> F::Output { + LL| 2| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + LL| 2| use std::hint::unreachable_unchecked; + LL| 2| static VTABLE: RawWakerVTable = RawWakerVTable::new( + LL| 2| |_| unsafe { unreachable_unchecked() }, // clone ^0 - 56| 2| |_| unsafe { unreachable_unchecked() }, // wake + LL| 2| |_| unsafe { unreachable_unchecked() }, // wake ^0 - 57| 2| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + LL| 2| |_| unsafe { unreachable_unchecked() }, // wake_by_ref ^0 - 58| 2| |_| (), - 59| 2| ); - 60| 2| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 61| 2| let mut context = Context::from_waker(&waker); - 62| | - 63| | loop { - 64| 2| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 65| 2| break val; - 66| 0| } - 67| | } - 68| 2| } + LL| 2| |_| (), + LL| 2| ); + LL| 2| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + LL| 2| let mut context = Context::from_waker(&waker); + LL| | + LL| | loop { + LL| 2| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + LL| 2| break val; + LL| 0| } + LL| | } + LL| 2| } ------------------ | async2::executor::block_on::: - | 51| 1| pub fn block_on(mut future: F) -> F::Output { - | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - | 53| 1| use std::hint::unreachable_unchecked; - | 54| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - | 55| 1| |_| unsafe { unreachable_unchecked() }, // clone - | 56| 1| |_| unsafe { unreachable_unchecked() }, // wake - | 57| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref - | 58| 1| |_| (), - | 59| 1| ); - | 60| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - | 61| 1| let mut context = Context::from_waker(&waker); - | 62| | - | 63| | loop { - | 64| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - | 65| 1| break val; - | 66| 0| } - | 67| | } - | 68| 1| } + | LL| 1| pub fn block_on(mut future: F) -> F::Output { + | LL| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + | LL| 1| use std::hint::unreachable_unchecked; + | LL| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + | LL| 1| |_| unsafe { unreachable_unchecked() }, // clone + | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake + | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + | LL| 1| |_| (), + | LL| 1| ); + | LL| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + | LL| 1| let mut context = Context::from_waker(&waker); + | LL| | + | LL| | loop { + | LL| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + | LL| 1| break val; + | LL| 0| } + | LL| | } + | LL| 1| } ------------------ | async2::executor::block_on::: - | 51| 1| pub fn block_on(mut future: F) -> F::Output { - | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - | 53| 1| use std::hint::unreachable_unchecked; - | 54| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - | 55| 1| |_| unsafe { unreachable_unchecked() }, // clone - | 56| 1| |_| unsafe { unreachable_unchecked() }, // wake - | 57| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref - | 58| 1| |_| (), - | 59| 1| ); - | 60| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - | 61| 1| let mut context = Context::from_waker(&waker); - | 62| | - | 63| | loop { - | 64| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - | 65| 1| break val; - | 66| 0| } - | 67| | } - | 68| 1| } + | LL| 1| pub fn block_on(mut future: F) -> F::Output { + | LL| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + | LL| 1| use std::hint::unreachable_unchecked; + | LL| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + | LL| 1| |_| unsafe { unreachable_unchecked() }, // clone + | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake + | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + | LL| 1| |_| (), + | LL| 1| ); + | LL| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + | LL| 1| let mut context = Context::from_waker(&waker); + | LL| | + | LL| | loop { + | LL| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + | LL| 1| break val; + | LL| 0| } + | LL| | } + | LL| 1| } ------------------ - 69| |} + LL| |} diff --git a/tests/run-coverage/closure.coverage b/tests/run-coverage/closure.coverage index 45d36b72e3a2..809cf1f48211 100644 --- a/tests/run-coverage/closure.coverage +++ b/tests/run-coverage/closure.coverage @@ -1,222 +1,222 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| |// compile-flags: -C opt-level=2 - 3| 1|fn main() { // ^^ fix described in rustc_middle/mir/mono.rs - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| let is_false = ! is_true; - 9| 1| - 10| 1| let mut some_string = Some(String::from("the string content")); - 11| 1| println!( - 12| 1| "The string or alt: {}" - 13| 1| , - 14| 1| some_string - 15| 1| . - 16| 1| unwrap_or_else - 17| 1| ( - 18| 1| || - 19| 0| { - 20| 0| let mut countdown = 0; - 21| 0| if is_false { - 22| 0| countdown = 10; - 23| 0| } - 24| 0| "alt string 1".to_owned() - 25| 1| } - 26| 1| ) - 27| 1| ); - 28| 1| - 29| 1| some_string = Some(String::from("the string content")); - 30| 1| let - 31| 1| a - 32| | = - 33| | || - 34| 0| { - 35| 0| let mut countdown = 0; - 36| 0| if is_false { - 37| 0| countdown = 10; - 38| 0| } - 39| 0| "alt string 2".to_owned() - 40| 0| }; - 41| 1| println!( - 42| 1| "The string or alt: {}" - 43| 1| , - 44| 1| some_string - 45| 1| . - 46| 1| unwrap_or_else - 47| 1| ( - 48| 1| a - 49| 1| ) - 50| 1| ); - 51| 1| - 52| 1| some_string = None; - 53| 1| println!( - 54| 1| "The string or alt: {}" - 55| 1| , - 56| 1| some_string - 57| 1| . - 58| 1| unwrap_or_else - 59| 1| ( - 60| 1| || - 61| 1| { - 62| 1| let mut countdown = 0; - 63| 1| if is_false { - 64| 0| countdown = 10; - 65| 1| } - 66| 1| "alt string 3".to_owned() - 67| 1| } - 68| 1| ) - 69| 1| ); - 70| 1| - 71| 1| some_string = None; - 72| 1| let - 73| 1| a - 74| 1| = - 75| 1| || - 76| 1| { - 77| 1| let mut countdown = 0; - 78| 1| if is_false { - 79| 0| countdown = 10; - 80| 1| } - 81| 1| "alt string 4".to_owned() - 82| 1| }; - 83| 1| println!( - 84| 1| "The string or alt: {}" - 85| 1| , - 86| 1| some_string - 87| 1| . - 88| 1| unwrap_or_else - 89| 1| ( - 90| 1| a - 91| 1| ) - 92| 1| ); - 93| 1| - 94| 1| let - 95| 1| quote_closure - 96| 1| = - 97| 1| |val| - 98| 5| { - 99| 5| let mut countdown = 0; - 100| 5| if is_false { - 101| 0| countdown = 10; - 102| 5| } - 103| 5| format!("'{}'", val) - 104| 5| }; - 105| 1| println!( - 106| 1| "Repeated, quoted string: {:?}" - 107| 1| , - 108| 1| std::iter::repeat("repeat me") - 109| 1| .take(5) - 110| 1| .map - 111| 1| ( - 112| 1| quote_closure - 113| 1| ) - 114| 1| .collect::>() - 115| 1| ); - 116| 1| - 117| 1| let - 118| 1| _unused_closure - 119| | = - 120| | | - 121| | mut countdown - 122| | | - 123| 0| { - 124| 0| if is_false { - 125| 0| countdown = 10; - 126| 0| } - 127| 0| "closure should be unused".to_owned() - 128| 0| }; - 129| | - 130| 1| let mut countdown = 10; - 131| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; + LL| |#![allow(unused_assignments, unused_variables)] + LL| |// compile-flags: -C opt-level=2 + LL| 1|fn main() { // ^^ fix described in rustc_middle/mir/mono.rs + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| let is_false = ! is_true; + LL| 1| + LL| 1| let mut some_string = Some(String::from("the string content")); + LL| 1| println!( + LL| 1| "The string or alt: {}" + LL| 1| , + LL| 1| some_string + LL| 1| . + LL| 1| unwrap_or_else + LL| 1| ( + LL| 1| || + LL| 0| { + LL| 0| let mut countdown = 0; + LL| 0| if is_false { + LL| 0| countdown = 10; + LL| 0| } + LL| 0| "alt string 1".to_owned() + LL| 1| } + LL| 1| ) + LL| 1| ); + LL| 1| + LL| 1| some_string = Some(String::from("the string content")); + LL| 1| let + LL| 1| a + LL| | = + LL| | || + LL| 0| { + LL| 0| let mut countdown = 0; + LL| 0| if is_false { + LL| 0| countdown = 10; + LL| 0| } + LL| 0| "alt string 2".to_owned() + LL| 0| }; + LL| 1| println!( + LL| 1| "The string or alt: {}" + LL| 1| , + LL| 1| some_string + LL| 1| . + LL| 1| unwrap_or_else + LL| 1| ( + LL| 1| a + LL| 1| ) + LL| 1| ); + LL| 1| + LL| 1| some_string = None; + LL| 1| println!( + LL| 1| "The string or alt: {}" + LL| 1| , + LL| 1| some_string + LL| 1| . + LL| 1| unwrap_or_else + LL| 1| ( + LL| 1| || + LL| 1| { + LL| 1| let mut countdown = 0; + LL| 1| if is_false { + LL| 0| countdown = 10; + LL| 1| } + LL| 1| "alt string 3".to_owned() + LL| 1| } + LL| 1| ) + LL| 1| ); + LL| 1| + LL| 1| some_string = None; + LL| 1| let + LL| 1| a + LL| 1| = + LL| 1| || + LL| 1| { + LL| 1| let mut countdown = 0; + LL| 1| if is_false { + LL| 0| countdown = 10; + LL| 1| } + LL| 1| "alt string 4".to_owned() + LL| 1| }; + LL| 1| println!( + LL| 1| "The string or alt: {}" + LL| 1| , + LL| 1| some_string + LL| 1| . + LL| 1| unwrap_or_else + LL| 1| ( + LL| 1| a + LL| 1| ) + LL| 1| ); + LL| 1| + LL| 1| let + LL| 1| quote_closure + LL| 1| = + LL| 1| |val| + LL| 5| { + LL| 5| let mut countdown = 0; + LL| 5| if is_false { + LL| 0| countdown = 10; + LL| 5| } + LL| 5| format!("'{}'", val) + LL| 5| }; + LL| 1| println!( + LL| 1| "Repeated, quoted string: {:?}" + LL| 1| , + LL| 1| std::iter::repeat("repeat me") + LL| 1| .take(5) + LL| 1| .map + LL| 1| ( + LL| 1| quote_closure + LL| 1| ) + LL| 1| .collect::>() + LL| 1| ); + LL| 1| + LL| 1| let + LL| 1| _unused_closure + LL| | = + LL| | | + LL| | mut countdown + LL| | | + LL| 0| { + LL| 0| if is_false { + LL| 0| countdown = 10; + LL| 0| } + LL| 0| "closure should be unused".to_owned() + LL| 0| }; + LL| | + LL| 1| let mut countdown = 10; + LL| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; ^0 - 132| | - 133| | - 134| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); - 135| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); + LL| | + LL| | + LL| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); + LL| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); ^0 - 136| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); + LL| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); ^0 - 137| | - 138| | - 139| | - 140| | - 141| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; + LL| | + LL| | + LL| | + LL| | + LL| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; ^0 - 142| | - 143| 1| let _shortish_unused_closure = | _unused_arg: u8 | { - 144| 0| println!("not called") - 145| 0| }; - 146| | - 147| 1| let _as_short_unused_closure = | - 148| | _unused_arg: u8 - 149| 0| | { println!("not called") }; - 150| | - 151| 1| let _almost_as_short_unused_closure = | - 152| | _unused_arg: u8 - 153| 0| | { println!("not called") } - 154| | ; - 155| | - 156| | - 157| | - 158| | - 159| | - 160| 1| let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | - 161| 0|println!("not called") - 162| | ; - 163| | - 164| 1| let _short_unused_closure_line_break_no_block2 = - 165| | | _unused_arg: u8 | - 166| 0| println!( - 167| 0| "not called" - 168| 0| ) - 169| | ; - 170| | - 171| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch = - 172| | | _unused_arg: u8 | - 173| 0| println!( - 174| 0| "not called: {}", - 175| 0| if is_true { "check" } else { "me" } - 176| 0| ) - 177| | ; - 178| | - 179| 1| let short_used_not_covered_closure_line_break_block_embedded_branch = - 180| 1| | _unused_arg: u8 | - 181| 0| { - 182| 0| println!( - 183| 0| "not called: {}", - 184| 0| if is_true { "check" } else { "me" } - 185| | ) - 186| 0| } - 187| | ; - 188| | - 189| 1| let short_used_covered_closure_line_break_no_block_embedded_branch = - 190| 1| | _unused_arg: u8 | - 191| 1| println!( - 192| 1| "not called: {}", - 193| 1| if is_true { "check" } else { "me" } + LL| | + LL| 1| let _shortish_unused_closure = | _unused_arg: u8 | { + LL| 0| println!("not called") + LL| 0| }; + LL| | + LL| 1| let _as_short_unused_closure = | + LL| | _unused_arg: u8 + LL| 0| | { println!("not called") }; + LL| | + LL| 1| let _almost_as_short_unused_closure = | + LL| | _unused_arg: u8 + LL| 0| | { println!("not called") } + LL| | ; + LL| | + LL| | + LL| | + LL| | + LL| | + LL| 1| let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | + LL| 0|println!("not called") + LL| | ; + LL| | + LL| 1| let _short_unused_closure_line_break_no_block2 = + LL| | | _unused_arg: u8 | + LL| 0| println!( + LL| 0| "not called" + LL| 0| ) + LL| | ; + LL| | + LL| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch = + LL| | | _unused_arg: u8 | + LL| 0| println!( + LL| 0| "not called: {}", + LL| 0| if is_true { "check" } else { "me" } + LL| 0| ) + LL| | ; + LL| | + LL| 1| let short_used_not_covered_closure_line_break_block_embedded_branch = + LL| 1| | _unused_arg: u8 | + LL| 0| { + LL| 0| println!( + LL| 0| "not called: {}", + LL| 0| if is_true { "check" } else { "me" } + LL| | ) + LL| 0| } + LL| | ; + LL| | + LL| 1| let short_used_covered_closure_line_break_no_block_embedded_branch = + LL| 1| | _unused_arg: u8 | + LL| 1| println!( + LL| 1| "not called: {}", + LL| 1| if is_true { "check" } else { "me" } ^0 - 194| 1| ) - 195| | ; - 196| | - 197| 1| let short_used_covered_closure_line_break_block_embedded_branch = - 198| 1| | _unused_arg: u8 | - 199| 1| { - 200| 1| println!( - 201| 1| "not called: {}", - 202| 1| if is_true { "check" } else { "me" } + LL| 1| ) + LL| | ; + LL| | + LL| 1| let short_used_covered_closure_line_break_block_embedded_branch = + LL| 1| | _unused_arg: u8 | + LL| 1| { + LL| 1| println!( + LL| 1| "not called: {}", + LL| 1| if is_true { "check" } else { "me" } ^0 - 203| | ) - 204| 1| } - 205| | ; - 206| | - 207| 1| if is_false { - 208| 0| short_used_not_covered_closure_macro(0); - 209| 0| short_used_not_covered_closure_line_break_no_block_embedded_branch(0); - 210| 0| short_used_not_covered_closure_line_break_block_embedded_branch(0); - 211| 1| } - 212| 1| short_used_covered_closure_macro(0); - 213| 1| short_used_covered_closure_line_break_no_block_embedded_branch(0); - 214| 1| short_used_covered_closure_line_break_block_embedded_branch(0); - 215| 1|} + LL| | ) + LL| 1| } + LL| | ; + LL| | + LL| 1| if is_false { + LL| 0| short_used_not_covered_closure_macro(0); + LL| 0| short_used_not_covered_closure_line_break_no_block_embedded_branch(0); + LL| 0| short_used_not_covered_closure_line_break_block_embedded_branch(0); + LL| 1| } + LL| 1| short_used_covered_closure_macro(0); + LL| 1| short_used_covered_closure_line_break_no_block_embedded_branch(0); + LL| 1| short_used_covered_closure_line_break_block_embedded_branch(0); + LL| 1|} diff --git a/tests/run-coverage/closure_macro.coverage b/tests/run-coverage/closure_macro.coverage index 87f7014760ed..1bfd2013da84 100644 --- a/tests/run-coverage/closure_macro.coverage +++ b/tests/run-coverage/closure_macro.coverage @@ -1,42 +1,42 @@ - 1| |// compile-flags: --edition=2018 - 2| |#![feature(no_coverage)] - 3| | - 4| |macro_rules! bail { - 5| | ($msg:literal $(,)?) => { - 6| | if $msg.len() > 0 { - 7| | println!("no msg"); - 8| | } else { - 9| | println!($msg); - 10| | } - 11| | return Err(String::from($msg)); - 12| | }; - 13| |} - 14| | - 15| |macro_rules! on_error { - 16| | ($value:expr, $error_message:expr) => { - 17| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - 18| | let message = format!($error_message, e); - 19| | if message.len() > 0 { - 20| | println!("{}", message); - 21| | Ok(String::from("ok")) - 22| | } else { - 23| | bail!("error"); - 24| | } - 25| | }) - 26| | }; - 27| |} - 28| | - 29| 1|fn load_configuration_files() -> Result { - 30| 1| Ok(String::from("config")) - 31| 1|} - 32| | - 33| 1|pub fn main() -> Result<(), String> { - 34| 1| println!("Starting service"); - 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + LL| |// compile-flags: --edition=2018 + LL| |#![feature(no_coverage)] + LL| | + LL| |macro_rules! bail { + LL| | ($msg:literal $(,)?) => { + LL| | if $msg.len() > 0 { + LL| | println!("no msg"); + LL| | } else { + LL| | println!($msg); + LL| | } + LL| | return Err(String::from($msg)); + LL| | }; + LL| |} + LL| | + LL| |macro_rules! on_error { + LL| | ($value:expr, $error_message:expr) => { + LL| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + LL| | let message = format!($error_message, e); + LL| | if message.len() > 0 { + LL| | println!("{}", message); + LL| | Ok(String::from("ok")) + LL| | } else { + LL| | bail!("error"); + LL| | } + LL| | }) + LL| | }; + LL| |} + LL| | + LL| 1|fn load_configuration_files() -> Result { + LL| 1| Ok(String::from("config")) + LL| 1|} + LL| | + LL| 1|pub fn main() -> Result<(), String> { + LL| 1| println!("Starting service"); + LL| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; ^0 - 36| | - 37| 1| let startup_delay_duration = String::from("arg"); - 38| 1| let _ = (config, startup_delay_duration); - 39| 1| Ok(()) - 40| 1|} + LL| | + LL| 1| let startup_delay_duration = String::from("arg"); + LL| 1| let _ = (config, startup_delay_duration); + LL| 1| Ok(()) + LL| 1|} diff --git a/tests/run-coverage/closure_macro_async.coverage b/tests/run-coverage/closure_macro_async.coverage index 2b5418132c30..0e4365fc797d 100644 --- a/tests/run-coverage/closure_macro_async.coverage +++ b/tests/run-coverage/closure_macro_async.coverage @@ -1,83 +1,83 @@ - 1| |// compile-flags: --edition=2018 - 2| |#![feature(no_coverage)] - 3| | - 4| |macro_rules! bail { - 5| | ($msg:literal $(,)?) => { - 6| | if $msg.len() > 0 { - 7| | println!("no msg"); - 8| | } else { - 9| | println!($msg); - 10| | } - 11| | return Err(String::from($msg)); - 12| | }; - 13| |} - 14| | - 15| |macro_rules! on_error { - 16| | ($value:expr, $error_message:expr) => { - 17| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - 18| | let message = format!($error_message, e); - 19| | if message.len() > 0 { - 20| | println!("{}", message); - 21| | Ok(String::from("ok")) - 22| | } else { - 23| | bail!("error"); - 24| | } - 25| | }) - 26| | }; - 27| |} - 28| | - 29| 1|fn load_configuration_files() -> Result { - 30| 1| Ok(String::from("config")) - 31| 1|} - 32| | - 33| 1|pub async fn test() -> Result<(), String> { - 34| 1| println!("Starting service"); - 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + LL| |// compile-flags: --edition=2018 + LL| |#![feature(no_coverage)] + LL| | + LL| |macro_rules! bail { + LL| | ($msg:literal $(,)?) => { + LL| | if $msg.len() > 0 { + LL| | println!("no msg"); + LL| | } else { + LL| | println!($msg); + LL| | } + LL| | return Err(String::from($msg)); + LL| | }; + LL| |} + LL| | + LL| |macro_rules! on_error { + LL| | ($value:expr, $error_message:expr) => { + LL| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + LL| | let message = format!($error_message, e); + LL| | if message.len() > 0 { + LL| | println!("{}", message); + LL| | Ok(String::from("ok")) + LL| | } else { + LL| | bail!("error"); + LL| | } + LL| | }) + LL| | }; + LL| |} + LL| | + LL| 1|fn load_configuration_files() -> Result { + LL| 1| Ok(String::from("config")) + LL| 1|} + LL| | + LL| 1|pub async fn test() -> Result<(), String> { + LL| 1| println!("Starting service"); + LL| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; ^0 - 36| | - 37| 1| let startup_delay_duration = String::from("arg"); - 38| 1| let _ = (config, startup_delay_duration); - 39| 1| Ok(()) - 40| 1|} - 41| | - 42| |#[no_coverage] - 43| |fn main() { - 44| | executor::block_on(test()); - 45| |} - 46| | - 47| |mod executor { - 48| | use core::{ - 49| | future::Future, - 50| | pin::Pin, - 51| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 52| | }; - 53| | - 54| | #[no_coverage] - 55| | pub fn block_on(mut future: F) -> F::Output { - 56| | let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 57| | use std::hint::unreachable_unchecked; - 58| | static VTABLE: RawWakerVTable = RawWakerVTable::new( - 59| | - 60| | #[no_coverage] - 61| | |_| unsafe { unreachable_unchecked() }, // clone - 62| | - 63| | #[no_coverage] - 64| | |_| unsafe { unreachable_unchecked() }, // wake - 65| | - 66| | #[no_coverage] - 67| | |_| unsafe { unreachable_unchecked() }, // wake_by_ref - 68| | - 69| | #[no_coverage] - 70| | |_| (), - 71| | ); - 72| | let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 73| | let mut context = Context::from_waker(&waker); - 74| | - 75| | loop { - 76| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 77| | break val; - 78| | } - 79| | } - 80| | } - 81| |} + LL| | + LL| 1| let startup_delay_duration = String::from("arg"); + LL| 1| let _ = (config, startup_delay_duration); + LL| 1| Ok(()) + LL| 1|} + LL| | + LL| |#[no_coverage] + LL| |fn main() { + LL| | executor::block_on(test()); + LL| |} + LL| | + LL| |mod executor { + LL| | use core::{ + LL| | future::Future, + LL| | pin::Pin, + LL| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + LL| | }; + LL| | + LL| | #[no_coverage] + LL| | pub fn block_on(mut future: F) -> F::Output { + LL| | let mut future = unsafe { Pin::new_unchecked(&mut future) }; + LL| | use std::hint::unreachable_unchecked; + LL| | static VTABLE: RawWakerVTable = RawWakerVTable::new( + LL| | + LL| | #[no_coverage] + LL| | |_| unsafe { unreachable_unchecked() }, // clone + LL| | + LL| | #[no_coverage] + LL| | |_| unsafe { unreachable_unchecked() }, // wake + LL| | + LL| | #[no_coverage] + LL| | |_| unsafe { unreachable_unchecked() }, // wake_by_ref + LL| | + LL| | #[no_coverage] + LL| | |_| (), + LL| | ); + LL| | let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + LL| | let mut context = Context::from_waker(&waker); + LL| | + LL| | loop { + LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + LL| | break val; + LL| | } + LL| | } + LL| | } + LL| |} diff --git a/tests/run-coverage/conditions.coverage b/tests/run-coverage/conditions.coverage index 2d8a98a5d0c9..4749c353a64f 100644 --- a/tests/run-coverage/conditions.coverage +++ b/tests/run-coverage/conditions.coverage @@ -1,94 +1,94 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| let mut countdown = 0; - 5| 1| if true { - 6| 1| countdown = 10; - 7| 1| } + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 1|fn main() { + LL| 1| let mut countdown = 0; + LL| 1| if true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 8| | - 9| | const B: u32 = 100; - 10| 1| let x = if countdown > 7 { - 11| 1| countdown -= 4; - 12| 1| B - 13| 0| } else if countdown > 2 { - 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 15| 0| countdown = 0; - 16| 0| } - 17| 0| countdown -= 5; - 18| 0| countdown - 19| | } else { - 20| 0| return; - 21| | }; - 22| | - 23| 1| let mut countdown = 0; - 24| 1| if true { - 25| 1| countdown = 10; - 26| 1| } + LL| | + LL| | const B: u32 = 100; + LL| 1| let x = if countdown > 7 { + LL| 1| countdown -= 4; + LL| 1| B + LL| 0| } else if countdown > 2 { + LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + LL| 0| countdown = 0; + LL| 0| } + LL| 0| countdown -= 5; + LL| 0| countdown + LL| | } else { + LL| 0| return; + LL| | }; + LL| | + LL| 1| let mut countdown = 0; + LL| 1| if true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 27| | - 28| 1| if countdown > 7 { - 29| 1| countdown -= 4; - 30| 1| } else if countdown > 2 { + LL| | + LL| 1| if countdown > 7 { + LL| 1| countdown -= 4; + LL| 1| } else if countdown > 2 { ^0 - 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 32| 0| countdown = 0; - 33| 0| } - 34| 0| countdown -= 5; - 35| | } else { - 36| 0| return; - 37| | } - 38| | - 39| 1| if true { - 40| 1| let mut countdown = 0; - 41| 1| if true { - 42| 1| countdown = 10; - 43| 1| } + LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + LL| 0| countdown = 0; + LL| 0| } + LL| 0| countdown -= 5; + LL| | } else { + LL| 0| return; + LL| | } + LL| | + LL| 1| if true { + LL| 1| let mut countdown = 0; + LL| 1| if true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 44| | - 45| 1| if countdown > 7 { - 46| 1| countdown -= 4; - 47| 1| } - 48| 0| else if countdown > 2 { - 49| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 50| 0| countdown = 0; - 51| 0| } - 52| 0| countdown -= 5; - 53| | } else { - 54| 0| return; - 55| | } - 56| 0| } - 57| | - 58| | - 59| 1| let mut countdown = 0; - 60| 1| if true { - 61| 1| countdown = 1; - 62| 1| } + LL| | + LL| 1| if countdown > 7 { + LL| 1| countdown -= 4; + LL| 1| } + LL| 0| else if countdown > 2 { + LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + LL| 0| countdown = 0; + LL| 0| } + LL| 0| countdown -= 5; + LL| | } else { + LL| 0| return; + LL| | } + LL| 0| } + LL| | + LL| | + LL| 1| let mut countdown = 0; + LL| 1| if true { + LL| 1| countdown = 1; + LL| 1| } ^0 - 63| | - 64| 1| let z = if countdown > 7 { + LL| | + LL| 1| let z = if countdown > 7 { ^0 - 65| 0| countdown -= 4; - 66| 1| } else if countdown > 2 { - 67| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 68| 0| countdown = 0; - 69| 0| } - 70| 0| countdown -= 5; - 71| | } else { - 72| 1| let should_be_reachable = countdown; - 73| 1| println!("reached"); - 74| 1| return; - 75| | }; - 76| | - 77| 0| let w = if countdown > 7 { - 78| 0| countdown -= 4; - 79| 0| } else if countdown > 2 { - 80| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 81| 0| countdown = 0; - 82| 0| } - 83| 0| countdown -= 5; - 84| | } else { - 85| 0| return; - 86| | }; - 87| 1|} + LL| 0| countdown -= 4; + LL| 1| } else if countdown > 2 { + LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + LL| 0| countdown = 0; + LL| 0| } + LL| 0| countdown -= 5; + LL| | } else { + LL| 1| let should_be_reachable = countdown; + LL| 1| println!("reached"); + LL| 1| return; + LL| | }; + LL| | + LL| 0| let w = if countdown > 7 { + LL| 0| countdown -= 4; + LL| 0| } else if countdown > 2 { + LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + LL| 0| countdown = 0; + LL| 0| } + LL| 0| countdown -= 5; + LL| | } else { + LL| 0| return; + LL| | }; + LL| 1|} diff --git a/tests/run-coverage/continue.coverage b/tests/run-coverage/continue.coverage index bf42924b1911..4916cac0038e 100644 --- a/tests/run-coverage/continue.coverage +++ b/tests/run-coverage/continue.coverage @@ -1,70 +1,70 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| let is_true = std::env::args().len() == 1; - 5| 1| - 6| 1| let mut x = 0; - 7| 11| for _ in 0..10 { - 8| 10| match is_true { - 9| | true => { - 10| 10| continue; - 11| | } - 12| 0| _ => { - 13| 0| x = 1; - 14| 0| } - 15| 0| } - 16| 0| x = 3; - 17| | } - 18| 11| for _ in 0..10 { - 19| 10| match is_true { - 20| 0| false => { - 21| 0| x = 1; - 22| 0| } - 23| | _ => { - 24| 10| continue; - 25| | } - 26| | } - 27| 0| x = 3; - 28| | } - 29| 11| for _ in 0..10 { - 30| 10| match is_true { - 31| 10| true => { - 32| 10| x = 1; - 33| 10| } - 34| | _ => { - 35| 0| continue; - 36| | } - 37| | } - 38| 10| x = 3; - 39| | } - 40| 11| for _ in 0..10 { - 41| 10| if is_true { - 42| 10| continue; - 43| 0| } - 44| 0| x = 3; - 45| | } - 46| 11| for _ in 0..10 { - 47| 10| match is_true { - 48| 0| false => { - 49| 0| x = 1; - 50| 0| } - 51| 10| _ => { - 52| 10| let _ = x; - 53| 10| } - 54| | } - 55| 10| x = 3; - 56| | } - 57| 1| for _ in 0..10 { - 58| 1| match is_true { - 59| 0| false => { - 60| 0| x = 1; - 61| 0| } - 62| | _ => { - 63| 1| break; - 64| | } - 65| | } - 66| 0| x = 3; - 67| | } - 68| 1| let _ = x; - 69| 1|} + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 1|fn main() { + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let mut x = 0; + LL| 11| for _ in 0..10 { + LL| 10| match is_true { + LL| | true => { + LL| 10| continue; + LL| | } + LL| 0| _ => { + LL| 0| x = 1; + LL| 0| } + LL| 0| } + LL| 0| x = 3; + LL| | } + LL| 11| for _ in 0..10 { + LL| 10| match is_true { + LL| 0| false => { + LL| 0| x = 1; + LL| 0| } + LL| | _ => { + LL| 10| continue; + LL| | } + LL| | } + LL| 0| x = 3; + LL| | } + LL| 11| for _ in 0..10 { + LL| 10| match is_true { + LL| 10| true => { + LL| 10| x = 1; + LL| 10| } + LL| | _ => { + LL| 0| continue; + LL| | } + LL| | } + LL| 10| x = 3; + LL| | } + LL| 11| for _ in 0..10 { + LL| 10| if is_true { + LL| 10| continue; + LL| 0| } + LL| 0| x = 3; + LL| | } + LL| 11| for _ in 0..10 { + LL| 10| match is_true { + LL| 0| false => { + LL| 0| x = 1; + LL| 0| } + LL| 10| _ => { + LL| 10| let _ = x; + LL| 10| } + LL| | } + LL| 10| x = 3; + LL| | } + LL| 1| for _ in 0..10 { + LL| 1| match is_true { + LL| 0| false => { + LL| 0| x = 1; + LL| 0| } + LL| | _ => { + LL| 1| break; + LL| | } + LL| | } + LL| 0| x = 3; + LL| | } + LL| 1| let _ = x; + LL| 1|} diff --git a/tests/run-coverage/dead_code.coverage b/tests/run-coverage/dead_code.coverage index 09ff14c6f272..5074d8b3c377 100644 --- a/tests/run-coverage/dead_code.coverage +++ b/tests/run-coverage/dead_code.coverage @@ -1,39 +1,39 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 0|pub fn unused_pub_fn_not_in_library() { - 4| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 0| // dependent conditions. - 7| 0| let is_true = std::env::args().len() == 1; - 8| 0| - 9| 0| let mut countdown = 0; - 10| 0| if is_true { - 11| 0| countdown = 10; - 12| 0| } - 13| 0|} - 14| | - 15| 0|fn unused_fn() { - 16| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 17| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 18| 0| // dependent conditions. - 19| 0| let is_true = std::env::args().len() == 1; - 20| 0| - 21| 0| let mut countdown = 0; - 22| 0| if is_true { - 23| 0| countdown = 10; - 24| 0| } - 25| 0|} - 26| | - 27| 1|fn main() { - 28| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 29| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 30| 1| // dependent conditions. - 31| 1| let is_true = std::env::args().len() == 1; - 32| 1| - 33| 1| let mut countdown = 0; - 34| 1| if is_true { - 35| 1| countdown = 10; - 36| 1| } + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 0|pub fn unused_pub_fn_not_in_library() { + LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 0| // dependent conditions. + LL| 0| let is_true = std::env::args().len() == 1; + LL| 0| + LL| 0| let mut countdown = 0; + LL| 0| if is_true { + LL| 0| countdown = 10; + LL| 0| } + LL| 0|} + LL| | + LL| 0|fn unused_fn() { + LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 0| // dependent conditions. + LL| 0| let is_true = std::env::args().len() == 1; + LL| 0| + LL| 0| let mut countdown = 0; + LL| 0| if is_true { + LL| 0| countdown = 10; + LL| 0| } + LL| 0|} + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let mut countdown = 0; + LL| 1| if is_true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 37| 1|} + LL| 1|} diff --git a/tests/run-coverage/drop_trait.coverage b/tests/run-coverage/drop_trait.coverage index 293001e9590e..c99b980a339f 100644 --- a/tests/run-coverage/drop_trait.coverage +++ b/tests/run-coverage/drop_trait.coverage @@ -1,34 +1,34 @@ - 1| |#![allow(unused_assignments)] - 2| |// failure-status: 1 - 3| | - 4| |struct Firework { - 5| | strength: i32, - 6| |} - 7| | - 8| |impl Drop for Firework { - 9| 2| fn drop(&mut self) { - 10| 2| println!("BOOM times {}!!!", self.strength); - 11| 2| } - 12| |} - 13| | - 14| 1|fn main() -> Result<(),u8> { - 15| 1| let _firecracker = Firework { strength: 1 }; - 16| 1| - 17| 1| let _tnt = Firework { strength: 100 }; - 18| 1| - 19| 1| if true { - 20| 1| println!("Exiting with error..."); - 21| 1| return Err(1); - 22| 0| } - 23| 0| - 24| 0| let _ = Firework { strength: 1000 }; - 25| 0| - 26| 0| Ok(()) - 27| 1|} - 28| | - 29| |// Expected program output: - 30| |// Exiting with error... - 31| |// BOOM times 100!!! - 32| |// BOOM times 1!!! - 33| |// Error: 1 + LL| |#![allow(unused_assignments)] + LL| |// failure-status: 1 + LL| | + LL| |struct Firework { + LL| | strength: i32, + LL| |} + LL| | + LL| |impl Drop for Firework { + LL| 2| fn drop(&mut self) { + LL| 2| println!("BOOM times {}!!!", self.strength); + LL| 2| } + LL| |} + LL| | + LL| 1|fn main() -> Result<(),u8> { + LL| 1| let _firecracker = Firework { strength: 1 }; + LL| 1| + LL| 1| let _tnt = Firework { strength: 100 }; + LL| 1| + LL| 1| if true { + LL| 1| println!("Exiting with error..."); + LL| 1| return Err(1); + LL| 0| } + LL| 0| + LL| 0| let _ = Firework { strength: 1000 }; + LL| 0| + LL| 0| Ok(()) + LL| 1|} + LL| | + LL| |// Expected program output: + LL| |// Exiting with error... + LL| |// BOOM times 100!!! + LL| |// BOOM times 1!!! + LL| |// Error: 1 diff --git a/tests/run-coverage/generator.coverage b/tests/run-coverage/generator.coverage index 0fb3808ff2e3..daba2bea8b86 100644 --- a/tests/run-coverage/generator.coverage +++ b/tests/run-coverage/generator.coverage @@ -1,32 +1,32 @@ - 1| |#![feature(generators, generator_trait)] - 2| | - 3| |use std::ops::{Generator, GeneratorState}; - 4| |use std::pin::Pin; - 5| | - 6| |// The following implementation of a function called from a `yield` statement - 7| |// (apparently requiring the Result and the `String` type or constructor) - 8| |// creates conditions where the `generator::StateTransform` MIR transform will - 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic - 10| |// to handle this condition, and still report dead block coverage. - 11| 1|fn get_u32(val: bool) -> Result { - 12| 1| if val { Ok(1) } else { Err(String::from("some error")) } + LL| |#![feature(generators, generator_trait)] + LL| | + LL| |use std::ops::{Generator, GeneratorState}; + LL| |use std::pin::Pin; + LL| | + LL| |// The following implementation of a function called from a `yield` statement + LL| |// (apparently requiring the Result and the `String` type or constructor) + LL| |// creates conditions where the `generator::StateTransform` MIR transform will + LL| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic + LL| |// to handle this condition, and still report dead block coverage. + LL| 1|fn get_u32(val: bool) -> Result { + LL| 1| if val { Ok(1) } else { Err(String::from("some error")) } ^0 - 13| 1|} - 14| | - 15| 1|fn main() { - 16| 1| let is_true = std::env::args().len() == 1; - 17| 1| let mut generator = || { - 18| 1| yield get_u32(is_true); - 19| 1| return "foo"; - 20| 1| }; - 21| | - 22| 1| match Pin::new(&mut generator).resume(()) { - 23| 1| GeneratorState::Yielded(Ok(1)) => {} - 24| 0| _ => panic!("unexpected return from resume"), - 25| | } - 26| 1| match Pin::new(&mut generator).resume(()) { - 27| 1| GeneratorState::Complete("foo") => {} - 28| 0| _ => panic!("unexpected return from resume"), - 29| | } - 30| 1|} + LL| 1|} + LL| | + LL| 1|fn main() { + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| let mut generator = || { + LL| 1| yield get_u32(is_true); + LL| 1| return "foo"; + LL| 1| }; + LL| | + LL| 1| match Pin::new(&mut generator).resume(()) { + LL| 1| GeneratorState::Yielded(Ok(1)) => {} + LL| 0| _ => panic!("unexpected return from resume"), + LL| | } + LL| 1| match Pin::new(&mut generator).resume(()) { + LL| 1| GeneratorState::Complete("foo") => {} + LL| 0| _ => panic!("unexpected return from resume"), + LL| | } + LL| 1|} diff --git a/tests/run-coverage/generics.coverage b/tests/run-coverage/generics.coverage index 7a7649674cac..2ff8f917ed74 100644 --- a/tests/run-coverage/generics.coverage +++ b/tests/run-coverage/generics.coverage @@ -1,71 +1,71 @@ - 1| |#![allow(unused_assignments)] - 2| |// failure-status: 1 - 3| | - 4| |struct Firework where T: Copy + std::fmt::Display { - 5| | strength: T, - 6| |} - 7| | - 8| |impl Firework where T: Copy + std::fmt::Display { - 9| | #[inline(always)] - 10| 3| fn set_strength(&mut self, new_strength: T) { - 11| 3| self.strength = new_strength; - 12| 3| } + LL| |#![allow(unused_assignments)] + LL| |// failure-status: 1 + LL| | + LL| |struct Firework where T: Copy + std::fmt::Display { + LL| | strength: T, + LL| |} + LL| | + LL| |impl Firework where T: Copy + std::fmt::Display { + LL| | #[inline(always)] + LL| 3| fn set_strength(&mut self, new_strength: T) { + LL| 3| self.strength = new_strength; + LL| 3| } ------------------ | >::set_strength: - | 10| 2| fn set_strength(&mut self, new_strength: T) { - | 11| 2| self.strength = new_strength; - | 12| 2| } + | LL| 2| fn set_strength(&mut self, new_strength: T) { + | LL| 2| self.strength = new_strength; + | LL| 2| } ------------------ | >::set_strength: - | 10| 1| fn set_strength(&mut self, new_strength: T) { - | 11| 1| self.strength = new_strength; - | 12| 1| } + | LL| 1| fn set_strength(&mut self, new_strength: T) { + | LL| 1| self.strength = new_strength; + | LL| 1| } ------------------ - 13| |} - 14| | - 15| |impl Drop for Firework where T: Copy + std::fmt::Display { - 16| | #[inline(always)] - 17| 2| fn drop(&mut self) { - 18| 2| println!("BOOM times {}!!!", self.strength); - 19| 2| } + LL| |} + LL| | + LL| |impl Drop for Firework where T: Copy + std::fmt::Display { + LL| | #[inline(always)] + LL| 2| fn drop(&mut self) { + LL| 2| println!("BOOM times {}!!!", self.strength); + LL| 2| } ------------------ | as core::ops::drop::Drop>::drop: - | 17| 1| fn drop(&mut self) { - | 18| 1| println!("BOOM times {}!!!", self.strength); - | 19| 1| } + | LL| 1| fn drop(&mut self) { + | LL| 1| println!("BOOM times {}!!!", self.strength); + | LL| 1| } ------------------ | as core::ops::drop::Drop>::drop: - | 17| 1| fn drop(&mut self) { - | 18| 1| println!("BOOM times {}!!!", self.strength); - | 19| 1| } + | LL| 1| fn drop(&mut self) { + | LL| 1| println!("BOOM times {}!!!", self.strength); + | LL| 1| } ------------------ - 20| |} - 21| | - 22| 1|fn main() -> Result<(),u8> { - 23| 1| let mut firecracker = Firework { strength: 1 }; - 24| 1| firecracker.set_strength(2); - 25| 1| - 26| 1| let mut tnt = Firework { strength: 100.1 }; - 27| 1| tnt.set_strength(200.1); - 28| 1| tnt.set_strength(300.3); - 29| 1| - 30| 1| if true { - 31| 1| println!("Exiting with error..."); - 32| 1| return Err(1); - 33| 0| } - 34| 0| - 35| 0| - 36| 0| - 37| 0| - 38| 0| - 39| 0| let _ = Firework { strength: 1000 }; - 40| 0| - 41| 0| Ok(()) - 42| 1|} - 43| | - 44| |// Expected program output: - 45| |// Exiting with error... - 46| |// BOOM times 100!!! - 47| |// BOOM times 1!!! - 48| |// Error: 1 + LL| |} + LL| | + LL| 1|fn main() -> Result<(),u8> { + LL| 1| let mut firecracker = Firework { strength: 1 }; + LL| 1| firecracker.set_strength(2); + LL| 1| + LL| 1| let mut tnt = Firework { strength: 100.1 }; + LL| 1| tnt.set_strength(200.1); + LL| 1| tnt.set_strength(300.3); + LL| 1| + LL| 1| if true { + LL| 1| println!("Exiting with error..."); + LL| 1| return Err(1); + LL| 0| } + LL| 0| + LL| 0| + LL| 0| + LL| 0| + LL| 0| + LL| 0| let _ = Firework { strength: 1000 }; + LL| 0| + LL| 0| Ok(()) + LL| 1|} + LL| | + LL| |// Expected program output: + LL| |// Exiting with error... + LL| |// BOOM times 100!!! + LL| |// BOOM times 1!!! + LL| |// Error: 1 diff --git a/tests/run-coverage/if.coverage b/tests/run-coverage/if.coverage index 0c9eff227ed0..2e6845190aab 100644 --- a/tests/run-coverage/if.coverage +++ b/tests/run-coverage/if.coverage @@ -1,30 +1,30 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let - 8| 1| is_true - 9| 1| = - 10| 1| std::env::args().len() - 11| 1| == - 12| 1| 1 - 13| 1| ; - 14| 1| let - 15| 1| mut - 16| 1| countdown - 17| 1| = - 18| 1| 0 - 19| 1| ; - 20| 1| if - 21| 1| is_true - 22| 1| { - 23| 1| countdown - 24| 1| = - 25| 1| 10 - 26| 1| ; - 27| 1| } + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let + LL| 1| is_true + LL| 1| = + LL| 1| std::env::args().len() + LL| 1| == + LL| 1| 1 + LL| 1| ; + LL| 1| let + LL| 1| mut + LL| 1| countdown + LL| 1| = + LL| 1| 0 + LL| 1| ; + LL| 1| if + LL| 1| is_true + LL| 1| { + LL| 1| countdown + LL| 1| = + LL| 1| 10 + LL| 1| ; + LL| 1| } ^0 - 28| 1|} + LL| 1|} diff --git a/tests/run-coverage/if_else.coverage b/tests/run-coverage/if_else.coverage index 4285d3186868..0274401f0047 100644 --- a/tests/run-coverage/if_else.coverage +++ b/tests/run-coverage/if_else.coverage @@ -1,41 +1,41 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| if - 11| 1| is_true - 12| 1| { - 13| 1| countdown - 14| 1| = - 15| 1| 10 - 16| 1| ; - 17| 1| } - 18| | else // Note coverage region difference without semicolon - 19| | { - 20| 0| countdown - 21| 0| = - 22| 0| 100 - 23| | } - 24| | - 25| | if - 26| 1| is_true - 27| 1| { - 28| 1| countdown - 29| 1| = - 30| 1| 10 - 31| 1| ; - 32| 1| } - 33| | else - 34| 0| { - 35| 0| countdown - 36| 0| = - 37| 0| 100 - 38| 0| ; - 39| 0| } - 40| 1|} + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let mut countdown = 0; + LL| 1| if + LL| 1| is_true + LL| 1| { + LL| 1| countdown + LL| 1| = + LL| 1| 10 + LL| 1| ; + LL| 1| } + LL| | else // Note coverage region difference without semicolon + LL| | { + LL| 0| countdown + LL| 0| = + LL| 0| 100 + LL| | } + LL| | + LL| | if + LL| 1| is_true + LL| 1| { + LL| 1| countdown + LL| 1| = + LL| 1| 10 + LL| 1| ; + LL| 1| } + LL| | else + LL| 0| { + LL| 0| countdown + LL| 0| = + LL| 0| 100 + LL| 0| ; + LL| 0| } + LL| 1|} diff --git a/tests/run-coverage/inline-dead.coverage b/tests/run-coverage/inline-dead.coverage index a59fe1146f48..de96aa17acd6 100644 --- a/tests/run-coverage/inline-dead.coverage +++ b/tests/run-coverage/inline-dead.coverage @@ -1,28 +1,28 @@ - 1| |// Regression test for issue #98833. - 2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off - 3| | - 4| 1|fn main() { - 5| 1| println!("{}", live::()); - 6| 1| - 7| 1| let f = |x: bool| { - 8| | debug_assert!( - 9| 0| x - 10| | ); - 11| 1| }; - 12| 1| f(false); - 13| 1|} - 14| | - 15| |#[inline] - 16| 1|fn live() -> u32 { - 17| 1| if B { - 18| 0| dead() - 19| | } else { - 20| 1| 0 - 21| | } - 22| 1|} - 23| | - 24| |#[inline] - 25| 0|fn dead() -> u32 { - 26| 0| 42 - 27| 0|} + LL| |// Regression test for issue #98833. + LL| |// compile-flags: -Zinline-mir -Cdebug-assertions=off + LL| | + LL| 1|fn main() { + LL| 1| println!("{}", live::()); + LL| 1| + LL| 1| let f = |x: bool| { + LL| | debug_assert!( + LL| 0| x + LL| | ); + LL| 1| }; + LL| 1| f(false); + LL| 1|} + LL| | + LL| |#[inline] + LL| 1|fn live() -> u32 { + LL| 1| if B { + LL| 0| dead() + LL| | } else { + LL| 1| 0 + LL| | } + LL| 1|} + LL| | + LL| |#[inline] + LL| 0|fn dead() -> u32 { + LL| 0| 42 + LL| 0|} diff --git a/tests/run-coverage/inline.coverage b/tests/run-coverage/inline.coverage index 6f5d1544fa03..6efd9a0830b4 100644 --- a/tests/run-coverage/inline.coverage +++ b/tests/run-coverage/inline.coverage @@ -1,54 +1,54 @@ - 1| |// compile-flags: -Zinline-mir - 2| | - 3| |use std::fmt::Display; - 4| | - 5| 1|fn main() { - 6| 1| permutations(&['a', 'b', 'c']); - 7| 1|} - 8| | - 9| |#[inline(always)] - 10| 1|fn permutations(xs: &[T]) { - 11| 1| let mut ys = xs.to_owned(); - 12| 1| permutate(&mut ys, 0); - 13| 1|} - 14| | - 15| 16|fn permutate(xs: &mut [T], k: usize) { - 16| 16| let n = length(xs); - 17| 16| if k == n { - 18| 6| display(xs); - 19| 10| } else if k < n { - 20| 15| for i in k..n { + LL| |// compile-flags: -Zinline-mir + LL| | + LL| |use std::fmt::Display; + LL| | + LL| 1|fn main() { + LL| 1| permutations(&['a', 'b', 'c']); + LL| 1|} + LL| | + LL| |#[inline(always)] + LL| 1|fn permutations(xs: &[T]) { + LL| 1| let mut ys = xs.to_owned(); + LL| 1| permutate(&mut ys, 0); + LL| 1|} + LL| | + LL| 16|fn permutate(xs: &mut [T], k: usize) { + LL| 16| let n = length(xs); + LL| 16| if k == n { + LL| 6| display(xs); + LL| 10| } else if k < n { + LL| 15| for i in k..n { ^10 - 21| 15| swap(xs, i, k); - 22| 15| permutate(xs, k + 1); - 23| 15| swap(xs, i, k); - 24| 15| } - 25| 0| } else { - 26| 0| error(); - 27| 0| } - 28| 16|} - 29| | - 30| 16|fn length(xs: &[T]) -> usize { - 31| 16| xs.len() - 32| 16|} - 33| | - 34| |#[inline] - 35| 30|fn swap(xs: &mut [T], i: usize, j: usize) { - 36| 30| let t = xs[i]; - 37| 30| xs[i] = xs[j]; - 38| 30| xs[j] = t; - 39| 30|} - 40| | - 41| 6|fn display(xs: &[T]) { - 42| 24| for x in xs { + LL| 15| swap(xs, i, k); + LL| 15| permutate(xs, k + 1); + LL| 15| swap(xs, i, k); + LL| 15| } + LL| 0| } else { + LL| 0| error(); + LL| 0| } + LL| 16|} + LL| | + LL| 16|fn length(xs: &[T]) -> usize { + LL| 16| xs.len() + LL| 16|} + LL| | + LL| |#[inline] + LL| 30|fn swap(xs: &mut [T], i: usize, j: usize) { + LL| 30| let t = xs[i]; + LL| 30| xs[i] = xs[j]; + LL| 30| xs[j] = t; + LL| 30|} + LL| | + LL| 6|fn display(xs: &[T]) { + LL| 24| for x in xs { ^18 - 43| 18| print!("{}", x); - 44| 18| } - 45| 6| println!(); - 46| 6|} - 47| | - 48| |#[inline(always)] - 49| 0|fn error() { - 50| 0| panic!("error"); - 51| 0|} + LL| 18| print!("{}", x); + LL| 18| } + LL| 6| println!(); + LL| 6|} + LL| | + LL| |#[inline(always)] + LL| 0|fn error() { + LL| 0| panic!("error"); + LL| 0|} diff --git a/tests/run-coverage/inner_items.coverage b/tests/run-coverage/inner_items.coverage index 883254a09ba7..65493bcd9db4 100644 --- a/tests/run-coverage/inner_items.coverage +++ b/tests/run-coverage/inner_items.coverage @@ -1,60 +1,60 @@ - 1| |#![allow(unused_assignments, unused_variables, dead_code)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| if is_true { - 11| 1| countdown = 10; - 12| 1| } + LL| |#![allow(unused_assignments, unused_variables, dead_code)] + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let mut countdown = 0; + LL| 1| if is_true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 13| | - 14| | mod in_mod { - 15| | const IN_MOD_CONST: u32 = 1000; - 16| | } - 17| | - 18| 3| fn in_func(a: u32) { - 19| 3| let b = 1; - 20| 3| let c = a + b; - 21| 3| println!("c = {}", c) - 22| 3| } - 23| | - 24| | struct InStruct { - 25| | in_struct_field: u32, - 26| | } - 27| | - 28| | const IN_CONST: u32 = 1234; - 29| | - 30| | trait InTrait { - 31| | fn trait_func(&mut self, incr: u32); - 32| | - 33| 1| fn default_trait_func(&mut self) { - 34| 1| in_func(IN_CONST); - 35| 1| self.trait_func(IN_CONST); - 36| 1| } - 37| | } - 38| | - 39| | impl InTrait for InStruct { - 40| 1| fn trait_func(&mut self, incr: u32) { - 41| 1| self.in_struct_field += incr; - 42| 1| in_func(self.in_struct_field); - 43| 1| } - 44| | } - 45| | - 46| | type InType = String; - 47| | - 48| 1| if is_true { - 49| 1| in_func(countdown); - 50| 1| } + LL| | + LL| | mod in_mod { + LL| | const IN_MOD_CONST: u32 = 1000; + LL| | } + LL| | + LL| 3| fn in_func(a: u32) { + LL| 3| let b = 1; + LL| 3| let c = a + b; + LL| 3| println!("c = {}", c) + LL| 3| } + LL| | + LL| | struct InStruct { + LL| | in_struct_field: u32, + LL| | } + LL| | + LL| | const IN_CONST: u32 = 1234; + LL| | + LL| | trait InTrait { + LL| | fn trait_func(&mut self, incr: u32); + LL| | + LL| 1| fn default_trait_func(&mut self) { + LL| 1| in_func(IN_CONST); + LL| 1| self.trait_func(IN_CONST); + LL| 1| } + LL| | } + LL| | + LL| | impl InTrait for InStruct { + LL| 1| fn trait_func(&mut self, incr: u32) { + LL| 1| self.in_struct_field += incr; + LL| 1| in_func(self.in_struct_field); + LL| 1| } + LL| | } + LL| | + LL| | type InType = String; + LL| | + LL| 1| if is_true { + LL| 1| in_func(countdown); + LL| 1| } ^0 - 51| | - 52| 1| let mut val = InStruct { - 53| 1| in_struct_field: 101, - 54| 1| }; - 55| 1| - 56| 1| val.default_trait_func(); - 57| 1|} + LL| | + LL| 1| let mut val = InStruct { + LL| 1| in_struct_field: 101, + LL| 1| }; + LL| 1| + LL| 1| val.default_trait_func(); + LL| 1|} diff --git a/tests/run-coverage/issue-83601.coverage b/tests/run-coverage/issue-83601.coverage index 25c74ab2e70b..7995332cad33 100644 --- a/tests/run-coverage/issue-83601.coverage +++ b/tests/run-coverage/issue-83601.coverage @@ -1,16 +1,16 @@ - 1| |// Shows that rust-lang/rust/83601 is resolved - 2| | - 3| 3|#[derive(Debug, PartialEq, Eq)] + LL| |// Shows that rust-lang/rust/83601 is resolved + LL| | + LL| 3|#[derive(Debug, PartialEq, Eq)] ^2 - 4| |struct Foo(u32); - 5| | - 6| 1|fn main() { - 7| 1| let bar = Foo(1); - 8| 1| assert_eq!(bar, Foo(1)); - 9| 1| let baz = Foo(0); - 10| 1| assert_ne!(baz, Foo(1)); - 11| 1| println!("{:?}", Foo(1)); - 12| 1| println!("{:?}", bar); - 13| 1| println!("{:?}", baz); - 14| 1|} + LL| |struct Foo(u32); + LL| | + LL| 1|fn main() { + LL| 1| let bar = Foo(1); + LL| 1| assert_eq!(bar, Foo(1)); + LL| 1| let baz = Foo(0); + LL| 1| assert_ne!(baz, Foo(1)); + LL| 1| println!("{:?}", Foo(1)); + LL| 1| println!("{:?}", bar); + LL| 1| println!("{:?}", baz); + LL| 1|} diff --git a/tests/run-coverage/issue-84561.coverage b/tests/run-coverage/issue-84561.coverage index 7a97e353245a..222f877d36aa 100644 --- a/tests/run-coverage/issue-84561.coverage +++ b/tests/run-coverage/issue-84561.coverage @@ -1,189 +1,189 @@ - 1| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. - 2| | - 3| |// failure-status: 101 - 4| 21|#[derive(PartialEq, Eq)] - 5| |struct Foo(u32); - 6| 1|fn test3() { - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| let bar = Foo(1); - 9| 1| assert_eq!(bar, Foo(1)); - 10| 1| let baz = Foo(0); - 11| 1| assert_ne!(baz, Foo(1)); - 12| 1| println!("{:?}", Foo(1)); - 13| 1| println!("{:?}", bar); - 14| 1| println!("{:?}", baz); - 15| 1| - 16| 1| assert_eq!(Foo(1), Foo(1)); - 17| 1| assert_ne!(Foo(0), Foo(1)); - 18| 1| assert_eq!(Foo(2), Foo(2)); - 19| 1| let bar = Foo(0); - 20| 1| assert_ne!(bar, Foo(3)); - 21| 1| assert_ne!(Foo(0), Foo(4)); - 22| 1| assert_eq!(Foo(3), Foo(3), "with a message"); + LL| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. + LL| | + LL| |// failure-status: 101 + LL| 21|#[derive(PartialEq, Eq)] + LL| |struct Foo(u32); + LL| 1|fn test3() { + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| let bar = Foo(1); + LL| 1| assert_eq!(bar, Foo(1)); + LL| 1| let baz = Foo(0); + LL| 1| assert_ne!(baz, Foo(1)); + LL| 1| println!("{:?}", Foo(1)); + LL| 1| println!("{:?}", bar); + LL| 1| println!("{:?}", baz); + LL| 1| + LL| 1| assert_eq!(Foo(1), Foo(1)); + LL| 1| assert_ne!(Foo(0), Foo(1)); + LL| 1| assert_eq!(Foo(2), Foo(2)); + LL| 1| let bar = Foo(0); + LL| 1| assert_ne!(bar, Foo(3)); + LL| 1| assert_ne!(Foo(0), Foo(4)); + LL| 1| assert_eq!(Foo(3), Foo(3), "with a message"); ^0 - 23| 1| println!("{:?}", bar); - 24| 1| println!("{:?}", Foo(1)); - 25| 1| - 26| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); + LL| 1| println!("{:?}", bar); + LL| 1| println!("{:?}", Foo(1)); + LL| 1| + LL| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); ^0 ^0 ^0 - 27| 1| assert_ne!( - 28| | Foo(0) - 29| | , - 30| | Foo(5) - 31| | , - 32| 0| "{}" - 33| 0| , - 34| 0| if - 35| 0| is_true - 36| | { - 37| 0| "true message" - 38| | } else { - 39| 0| "false message" - 40| | } - 41| | ); - 42| | - 43| 1| let is_true = std::env::args().len() == 1; - 44| 1| - 45| 1| assert_eq!( - 46| 1| Foo(1), - 47| 1| Foo(1) - 48| 1| ); - 49| 1| assert_ne!( - 50| 1| Foo(0), - 51| 1| Foo(1) - 52| 1| ); - 53| 1| assert_eq!( - 54| 1| Foo(2), - 55| 1| Foo(2) - 56| 1| ); - 57| 1| let bar = Foo(1); - 58| 1| assert_ne!( - 59| 1| bar, - 60| 1| Foo(3) - 61| 1| ); - 62| 1| if is_true { - 63| 1| assert_ne!( - 64| 1| Foo(0), - 65| 1| Foo(4) - 66| 1| ); - 67| | } else { - 68| 0| assert_eq!( - 69| 0| Foo(3), - 70| 0| Foo(3) - 71| 0| ); - 72| | } - 73| 1| if is_true { - 74| 1| assert_ne!( - 75| | Foo(0), - 76| | Foo(4), - 77| 0| "with a message" - 78| | ); - 79| | } else { - 80| 0| assert_eq!( - 81| | Foo(3), - 82| | Foo(3), - 83| 0| "with a message" - 84| | ); - 85| | } - 86| 1| assert_ne!( - 87| 1| if is_true { - 88| 1| Foo(0) - 89| | } else { - 90| 0| Foo(1) - 91| | }, - 92| | Foo(5) - 93| | ); - 94| 1| assert_ne!( - 95| 1| Foo(5), - 96| 1| if is_true { - 97| 1| Foo(0) - 98| | } else { - 99| 0| Foo(1) - 100| | } - 101| | ); - 102| 1| assert_ne!( - 103| 1| if is_true { - 104| 1| assert_eq!( - 105| 1| Foo(3), - 106| 1| Foo(3) - 107| 1| ); - 108| 1| Foo(0) - 109| | } else { - 110| 0| assert_ne!( - 111| 0| if is_true { - 112| 0| Foo(0) - 113| | } else { - 114| 0| Foo(1) - 115| | }, - 116| | Foo(5) - 117| | ); - 118| 0| Foo(1) - 119| | }, - 120| | Foo(5), - 121| 0| "with a message" - 122| | ); - 123| 1| assert_eq!( - 124| | Foo(1), - 125| | Foo(3), - 126| 1| "this assert should fail" - 127| | ); - 128| 0| assert_eq!( - 129| | Foo(3), - 130| | Foo(3), - 131| 0| "this assert should not be reached" - 132| | ); - 133| 0|} - 134| | - 135| |impl std::fmt::Debug for Foo { - 136| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 137| 7| write!(f, "try and succeed")?; + LL| 1| assert_ne!( + LL| | Foo(0) + LL| | , + LL| | Foo(5) + LL| | , + LL| 0| "{}" + LL| 0| , + LL| 0| if + LL| 0| is_true + LL| | { + LL| 0| "true message" + LL| | } else { + LL| 0| "false message" + LL| | } + LL| | ); + LL| | + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| assert_eq!( + LL| 1| Foo(1), + LL| 1| Foo(1) + LL| 1| ); + LL| 1| assert_ne!( + LL| 1| Foo(0), + LL| 1| Foo(1) + LL| 1| ); + LL| 1| assert_eq!( + LL| 1| Foo(2), + LL| 1| Foo(2) + LL| 1| ); + LL| 1| let bar = Foo(1); + LL| 1| assert_ne!( + LL| 1| bar, + LL| 1| Foo(3) + LL| 1| ); + LL| 1| if is_true { + LL| 1| assert_ne!( + LL| 1| Foo(0), + LL| 1| Foo(4) + LL| 1| ); + LL| | } else { + LL| 0| assert_eq!( + LL| 0| Foo(3), + LL| 0| Foo(3) + LL| 0| ); + LL| | } + LL| 1| if is_true { + LL| 1| assert_ne!( + LL| | Foo(0), + LL| | Foo(4), + LL| 0| "with a message" + LL| | ); + LL| | } else { + LL| 0| assert_eq!( + LL| | Foo(3), + LL| | Foo(3), + LL| 0| "with a message" + LL| | ); + LL| | } + LL| 1| assert_ne!( + LL| 1| if is_true { + LL| 1| Foo(0) + LL| | } else { + LL| 0| Foo(1) + LL| | }, + LL| | Foo(5) + LL| | ); + LL| 1| assert_ne!( + LL| 1| Foo(5), + LL| 1| if is_true { + LL| 1| Foo(0) + LL| | } else { + LL| 0| Foo(1) + LL| | } + LL| | ); + LL| 1| assert_ne!( + LL| 1| if is_true { + LL| 1| assert_eq!( + LL| 1| Foo(3), + LL| 1| Foo(3) + LL| 1| ); + LL| 1| Foo(0) + LL| | } else { + LL| 0| assert_ne!( + LL| 0| if is_true { + LL| 0| Foo(0) + LL| | } else { + LL| 0| Foo(1) + LL| | }, + LL| | Foo(5) + LL| | ); + LL| 0| Foo(1) + LL| | }, + LL| | Foo(5), + LL| 0| "with a message" + LL| | ); + LL| 1| assert_eq!( + LL| | Foo(1), + LL| | Foo(3), + LL| 1| "this assert should fail" + LL| | ); + LL| 0| assert_eq!( + LL| | Foo(3), + LL| | Foo(3), + LL| 0| "this assert should not be reached" + LL| | ); + LL| 0|} + LL| | + LL| |impl std::fmt::Debug for Foo { + LL| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + LL| 7| write!(f, "try and succeed")?; ^0 - 138| 7| Ok(()) - 139| 7| } - 140| |} - 141| | - 142| |static mut DEBUG_LEVEL_ENABLED: bool = false; - 143| | - 144| |macro_rules! debug { - 145| | ($($arg:tt)+) => ( - 146| | if unsafe { DEBUG_LEVEL_ENABLED } { - 147| | println!($($arg)+); - 148| | } - 149| | ); - 150| |} - 151| | - 152| 1|fn test1() { - 153| 1| debug!("debug is enabled"); + LL| 7| Ok(()) + LL| 7| } + LL| |} + LL| | + LL| |static mut DEBUG_LEVEL_ENABLED: bool = false; + LL| | + LL| |macro_rules! debug { + LL| | ($($arg:tt)+) => ( + LL| | if unsafe { DEBUG_LEVEL_ENABLED } { + LL| | println!($($arg)+); + LL| | } + LL| | ); + LL| |} + LL| | + LL| 1|fn test1() { + LL| 1| debug!("debug is enabled"); ^0 - 154| 1| debug!("debug is enabled"); + LL| 1| debug!("debug is enabled"); ^0 - 155| 1| let _ = 0; - 156| 1| debug!("debug is enabled"); + LL| 1| let _ = 0; + LL| 1| debug!("debug is enabled"); ^0 - 157| 1| unsafe { - 158| 1| DEBUG_LEVEL_ENABLED = true; - 159| 1| } - 160| 1| debug!("debug is enabled"); - 161| 1|} - 162| | - 163| |macro_rules! call_debug { - 164| | ($($arg:tt)+) => ( - 165| 1| fn call_print(s: &str) { - 166| 1| print!("{}", s); - 167| 1| } - 168| | - 169| | call_print("called from call_debug: "); - 170| | debug!($($arg)+); - 171| | ); - 172| |} - 173| | - 174| 1|fn test2() { - 175| 1| call_debug!("debug is enabled"); - 176| 1|} - 177| | - 178| 1|fn main() { - 179| 1| test1(); - 180| 1| test2(); - 181| 1| test3(); - 182| 1|} + LL| 1| unsafe { + LL| 1| DEBUG_LEVEL_ENABLED = true; + LL| 1| } + LL| 1| debug!("debug is enabled"); + LL| 1|} + LL| | + LL| |macro_rules! call_debug { + LL| | ($($arg:tt)+) => ( + LL| 1| fn call_print(s: &str) { + LL| 1| print!("{}", s); + LL| 1| } + LL| | + LL| | call_print("called from call_debug: "); + LL| | debug!($($arg)+); + LL| | ); + LL| |} + LL| | + LL| 1|fn test2() { + LL| 1| call_debug!("debug is enabled"); + LL| 1|} + LL| | + LL| 1|fn main() { + LL| 1| test1(); + LL| 1| test2(); + LL| 1| test3(); + LL| 1|} diff --git a/tests/run-coverage/issue-85461.coverage b/tests/run-coverage/issue-85461.coverage index d78a4a1129ca..f97ab2303871 100644 --- a/tests/run-coverage/issue-85461.coverage +++ b/tests/run-coverage/issue-85461.coverage @@ -1,36 +1,36 @@ $DIR/auxiliary/inline_always_with_dead_code.rs: - 1| |// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0 - 2| | - 3| |#![allow(dead_code)] - 4| | - 5| |mod foo { - 6| | #[inline(always)] - 7| 2| pub fn called() { } - 8| | - 9| 0| fn uncalled() { } - 10| |} - 11| | - 12| |pub mod bar { - 13| 1| pub fn call_me() { - 14| 1| super::foo::called(); - 15| 1| } - 16| |} - 17| | - 18| |pub mod baz { - 19| 1| pub fn call_me() { - 20| 1| super::foo::called(); - 21| 1| } - 22| |} + LL| |// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0 + LL| | + LL| |#![allow(dead_code)] + LL| | + LL| |mod foo { + LL| | #[inline(always)] + LL| 2| pub fn called() { } + LL| | + LL| 0| fn uncalled() { } + LL| |} + LL| | + LL| |pub mod bar { + LL| 1| pub fn call_me() { + LL| 1| super::foo::called(); + LL| 1| } + LL| |} + LL| | + LL| |pub mod baz { + LL| 1| pub fn call_me() { + LL| 1| super::foo::called(); + LL| 1| } + LL| |} $DIR/issue-85461.rs: - 1| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] - 2| |// aux-build:inline_always_with_dead_code.rs - 3| |extern crate inline_always_with_dead_code; - 4| | - 5| |use inline_always_with_dead_code::{bar, baz}; - 6| | - 7| 1|fn main() { - 8| 1| bar::call_me(); - 9| 1| baz::call_me(); - 10| 1|} + LL| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] + LL| |// aux-build:inline_always_with_dead_code.rs + LL| |extern crate inline_always_with_dead_code; + LL| | + LL| |use inline_always_with_dead_code::{bar, baz}; + LL| | + LL| 1|fn main() { + LL| 1| bar::call_me(); + LL| 1| baz::call_me(); + LL| 1|} diff --git a/tests/run-coverage/issue-93054.coverage b/tests/run-coverage/issue-93054.coverage index a1655adedd44..074e6b9835a4 100644 --- a/tests/run-coverage/issue-93054.coverage +++ b/tests/run-coverage/issue-93054.coverage @@ -1,29 +1,29 @@ - 1| |// Regression test for #93054: Functions using uninhabited types often only have a single, - 2| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. - 3| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. - 4| | - 5| |// compile-flags: --edition=2021 - 6| | - 7| |enum Never { } - 8| | - 9| |impl Never { - 10| | fn foo(self) { - 11| | match self { } - 12| | make().map(|never| match never { }); - 13| | } - 14| | - 15| | fn bar(&self) { - 16| | match *self { } - 17| | } - 18| |} - 19| | - 20| 0|async fn foo2(never: Never) { - 21| | match never { } - 22| |} - 23| | - 24| 0|fn make() -> Option { - 25| 0| None - 26| 0|} - 27| | - 28| 1|fn main() { } + LL| |// Regression test for #93054: Functions using uninhabited types often only have a single, + LL| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. + LL| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. + LL| | + LL| |// compile-flags: --edition=2021 + LL| | + LL| |enum Never { } + LL| | + LL| |impl Never { + LL| | fn foo(self) { + LL| | match self { } + LL| | make().map(|never| match never { }); + LL| | } + LL| | + LL| | fn bar(&self) { + LL| | match *self { } + LL| | } + LL| |} + LL| | + LL| 0|async fn foo2(never: Never) { + LL| | match never { } + LL| |} + LL| | + LL| 0|fn make() -> Option { + LL| 0| None + LL| 0|} + LL| | + LL| 1|fn main() { } diff --git a/tests/run-coverage/lazy_boolean.coverage b/tests/run-coverage/lazy_boolean.coverage index bd349df2fbce..2d927a083560 100644 --- a/tests/run-coverage/lazy_boolean.coverage +++ b/tests/run-coverage/lazy_boolean.coverage @@ -1,64 +1,64 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let (mut a, mut b, mut c) = (0, 0, 0); - 10| 1| if is_true { - 11| 1| a = 1; - 12| 1| b = 10; - 13| 1| c = 100; - 14| 1| } + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let (mut a, mut b, mut c) = (0, 0, 0); + LL| 1| if is_true { + LL| 1| a = 1; + LL| 1| b = 10; + LL| 1| c = 100; + LL| 1| } ^0 - 15| | let - 16| 1| somebool - 17| | = - 18| 1| a < b - 19| | || - 20| 0| b < c - 21| | ; - 22| | let - 23| 1| somebool - 24| | = - 25| 1| b < a - 26| | || - 27| 1| b < c - 28| | ; - 29| 1| let somebool = a < b && b < c; - 30| 1| let somebool = b < a && b < c; + LL| | let + LL| 1| somebool + LL| | = + LL| 1| a < b + LL| | || + LL| 0| b < c + LL| | ; + LL| | let + LL| 1| somebool + LL| | = + LL| 1| b < a + LL| | || + LL| 1| b < c + LL| | ; + LL| 1| let somebool = a < b && b < c; + LL| 1| let somebool = b < a && b < c; ^0 - 31| | - 32| | if - 33| 1| ! - 34| 1| is_true - 35| 0| { - 36| 0| a = 2 - 37| 0| ; - 38| 1| } - 39| | - 40| | if - 41| 1| is_true - 42| 1| { - 43| 1| b = 30 - 44| 1| ; - 45| 1| } - 46| | else - 47| 0| { - 48| 0| c = 400 - 49| 0| ; - 50| 0| } - 51| | - 52| 1| if !is_true { - 53| 0| a = 2; - 54| 1| } - 55| | - 56| 1| if is_true { - 57| 1| b = 30; - 58| 1| } else { - 59| 0| c = 400; - 60| 0| } - 61| 1|} + LL| | + LL| | if + LL| 1| ! + LL| 1| is_true + LL| 0| { + LL| 0| a = 2 + LL| 0| ; + LL| 1| } + LL| | + LL| | if + LL| 1| is_true + LL| 1| { + LL| 1| b = 30 + LL| 1| ; + LL| 1| } + LL| | else + LL| 0| { + LL| 0| c = 400 + LL| 0| ; + LL| 0| } + LL| | + LL| 1| if !is_true { + LL| 0| a = 2; + LL| 1| } + LL| | + LL| 1| if is_true { + LL| 1| b = 30; + LL| 1| } else { + LL| 0| c = 400; + LL| 0| } + LL| 1|} diff --git a/tests/run-coverage/loop_break_value.coverage b/tests/run-coverage/loop_break_value.coverage index 022fe4c59620..1f0630636ddf 100644 --- a/tests/run-coverage/loop_break_value.coverage +++ b/tests/run-coverage/loop_break_value.coverage @@ -1,14 +1,14 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| let result - 5| 1| = - 6| 1| loop - 7| 1| { - 8| 1| break - 9| 1| 10 - 10| 1| ; - 11| 1| } - 12| 1| ; - 13| 1|} + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 1|fn main() { + LL| 1| let result + LL| 1| = + LL| 1| loop + LL| 1| { + LL| 1| break + LL| 1| 10 + LL| 1| ; + LL| 1| } + LL| 1| ; + LL| 1|} diff --git a/tests/run-coverage/loops_branches.coverage b/tests/run-coverage/loops_branches.coverage index b7ad79a24844..148a22377f32 100644 --- a/tests/run-coverage/loops_branches.coverage +++ b/tests/run-coverage/loops_branches.coverage @@ -1,68 +1,68 @@ - 1| |#![allow(unused_assignments, unused_variables, while_true)] - 2| | - 3| |// This test confirms that (1) unexecuted infinite loops are handled correctly by the - 4| |// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped. - 5| | - 6| |struct DebugTest; - 7| | - 8| |impl std::fmt::Debug for DebugTest { - 9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 10| 1| if true { - 11| 1| if false { - 12| 0| while true { - 13| 0| } - 14| 1| } - 15| 1| write!(f, "cool")?; + LL| |#![allow(unused_assignments, unused_variables, while_true)] + LL| | + LL| |// This test confirms that (1) unexecuted infinite loops are handled correctly by the + LL| |// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped. + LL| | + LL| |struct DebugTest; + LL| | + LL| |impl std::fmt::Debug for DebugTest { + LL| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + LL| 1| if true { + LL| 1| if false { + LL| 0| while true { + LL| 0| } + LL| 1| } + LL| 1| write!(f, "cool")?; ^0 - 16| 0| } else { - 17| 0| } - 18| | - 19| 11| for i in 0..10 { + LL| 0| } else { + LL| 0| } + LL| | + LL| 11| for i in 0..10 { ^10 - 20| 10| if true { - 21| 10| if false { - 22| 0| while true {} - 23| 10| } - 24| 10| write!(f, "cool")?; + LL| 10| if true { + LL| 10| if false { + LL| 0| while true {} + LL| 10| } + LL| 10| write!(f, "cool")?; ^0 - 25| 0| } else { - 26| 0| } - 27| | } - 28| 1| Ok(()) - 29| 1| } - 30| |} - 31| | - 32| |struct DisplayTest; - 33| | - 34| |impl std::fmt::Display for DisplayTest { - 35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 36| 1| if false { - 37| 0| } else { - 38| 1| if false { - 39| 0| while true {} - 40| 1| } - 41| 1| write!(f, "cool")?; + LL| 0| } else { + LL| 0| } + LL| | } + LL| 1| Ok(()) + LL| 1| } + LL| |} + LL| | + LL| |struct DisplayTest; + LL| | + LL| |impl std::fmt::Display for DisplayTest { + LL| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + LL| 1| if false { + LL| 0| } else { + LL| 1| if false { + LL| 0| while true {} + LL| 1| } + LL| 1| write!(f, "cool")?; ^0 - 42| | } - 43| 11| for i in 0..10 { + LL| | } + LL| 11| for i in 0..10 { ^10 - 44| 10| if false { - 45| 0| } else { - 46| 10| if false { - 47| 0| while true {} - 48| 10| } - 49| 10| write!(f, "cool")?; + LL| 10| if false { + LL| 0| } else { + LL| 10| if false { + LL| 0| while true {} + LL| 10| } + LL| 10| write!(f, "cool")?; ^0 - 50| | } - 51| | } - 52| 1| Ok(()) - 53| 1| } - 54| |} - 55| | - 56| 1|fn main() { - 57| 1| let debug_test = DebugTest; - 58| 1| println!("{:?}", debug_test); - 59| 1| let display_test = DisplayTest; - 60| 1| println!("{}", display_test); - 61| 1|} + LL| | } + LL| | } + LL| 1| Ok(()) + LL| 1| } + LL| |} + LL| | + LL| 1|fn main() { + LL| 1| let debug_test = DebugTest; + LL| 1| println!("{:?}", debug_test); + LL| 1| let display_test = DisplayTest; + LL| 1| println!("{}", display_test); + LL| 1|} diff --git a/tests/run-coverage/match_or_pattern.coverage b/tests/run-coverage/match_or_pattern.coverage index a0fccb24f998..0b5a2c03dd36 100644 --- a/tests/run-coverage/match_or_pattern.coverage +++ b/tests/run-coverage/match_or_pattern.coverage @@ -1,50 +1,50 @@ - 1| |#![feature(or_patterns)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut a: u8 = 0; - 10| 1| let mut b: u8 = 0; - 11| 1| if is_true { - 12| 1| a = 2; - 13| 1| b = 0; - 14| 1| } + LL| |#![feature(or_patterns)] + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let mut a: u8 = 0; + LL| 1| let mut b: u8 = 0; + LL| 1| if is_true { + LL| 1| a = 2; + LL| 1| b = 0; + LL| 1| } ^0 - 15| 1| match (a, b) { - 16| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. - 17| | // This test confirms a fix for Issue #79569. - 18| 0| (0 | 1, 2 | 3) => {} - 19| 1| _ => {} - 20| | } - 21| 1| if is_true { - 22| 1| a = 0; - 23| 1| b = 0; - 24| 1| } + LL| 1| match (a, b) { + LL| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + LL| | // This test confirms a fix for Issue #79569. + LL| 0| (0 | 1, 2 | 3) => {} + LL| 1| _ => {} + LL| | } + LL| 1| if is_true { + LL| 1| a = 0; + LL| 1| b = 0; + LL| 1| } ^0 - 25| 1| match (a, b) { - 26| 0| (0 | 1, 2 | 3) => {} - 27| 1| _ => {} - 28| | } - 29| 1| if is_true { - 30| 1| a = 2; - 31| 1| b = 2; - 32| 1| } + LL| 1| match (a, b) { + LL| 0| (0 | 1, 2 | 3) => {} + LL| 1| _ => {} + LL| | } + LL| 1| if is_true { + LL| 1| a = 2; + LL| 1| b = 2; + LL| 1| } ^0 - 33| 1| match (a, b) { - 34| 0| (0 | 1, 2 | 3) => {} - 35| 1| _ => {} - 36| | } - 37| 1| if is_true { - 38| 1| a = 0; - 39| 1| b = 2; - 40| 1| } + LL| 1| match (a, b) { + LL| 0| (0 | 1, 2 | 3) => {} + LL| 1| _ => {} + LL| | } + LL| 1| if is_true { + LL| 1| a = 0; + LL| 1| b = 2; + LL| 1| } ^0 - 41| 1| match (a, b) { - 42| 1| (0 | 1, 2 | 3) => {} - 43| 0| _ => {} - 44| | } - 45| 1|} + LL| 1| match (a, b) { + LL| 1| (0 | 1, 2 | 3) => {} + LL| 0| _ => {} + LL| | } + LL| 1|} diff --git a/tests/run-coverage/nested_loops.coverage b/tests/run-coverage/nested_loops.coverage index 0dbd6bcf313e..143d0d26aa7f 100644 --- a/tests/run-coverage/nested_loops.coverage +++ b/tests/run-coverage/nested_loops.coverage @@ -1,26 +1,26 @@ - 1| 1|fn main() { - 2| 1| let is_true = std::env::args().len() == 1; - 3| 1| let mut countdown = 10; - 4| | - 5| 1| 'outer: while countdown > 0 { - 6| 1| let mut a = 100; - 7| 1| let mut b = 100; - 8| 3| for _ in 0..50 { - 9| 3| if a < 30 { - 10| 0| break; - 11| 3| } - 12| 3| a -= 5; - 13| 3| b -= 5; - 14| 3| if b < 90 { - 15| 1| a -= 10; - 16| 1| if is_true { - 17| 1| break 'outer; - 18| 0| } else { - 19| 0| a -= 2; - 20| 0| } - 21| 2| } - 22| | } - 23| 0| countdown -= 1; - 24| | } - 25| 1|} + LL| 1|fn main() { + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| let mut countdown = 10; + LL| | + LL| 1| 'outer: while countdown > 0 { + LL| 1| let mut a = 100; + LL| 1| let mut b = 100; + LL| 3| for _ in 0..50 { + LL| 3| if a < 30 { + LL| 0| break; + LL| 3| } + LL| 3| a -= 5; + LL| 3| b -= 5; + LL| 3| if b < 90 { + LL| 1| a -= 10; + LL| 1| if is_true { + LL| 1| break 'outer; + LL| 0| } else { + LL| 0| a -= 2; + LL| 0| } + LL| 2| } + LL| | } + LL| 0| countdown -= 1; + LL| | } + LL| 1|} diff --git a/tests/run-coverage/no_cov_crate.coverage b/tests/run-coverage/no_cov_crate.coverage index 83a9204136f7..c34dbde888ae 100644 --- a/tests/run-coverage/no_cov_crate.coverage +++ b/tests/run-coverage/no_cov_crate.coverage @@ -1,87 +1,87 @@ - 1| |// Enables `no_coverage` on the entire crate - 2| |#![feature(no_coverage)] - 3| | - 4| |#[no_coverage] - 5| |fn do_not_add_coverage_1() { - 6| | println!("called but not covered"); - 7| |} - 8| | - 9| |fn do_not_add_coverage_2() { - 10| | #![no_coverage] - 11| | println!("called but not covered"); - 12| |} - 13| | - 14| |#[no_coverage] - 15| |fn do_not_add_coverage_not_called() { - 16| | println!("not called and not covered"); - 17| |} - 18| | - 19| 1|fn add_coverage_1() { - 20| 1| println!("called and covered"); - 21| 1|} - 22| | - 23| 1|fn add_coverage_2() { - 24| 1| println!("called and covered"); - 25| 1|} - 26| | - 27| 0|fn add_coverage_not_called() { - 28| 0| println!("not called but covered"); - 29| 0|} - 30| | - 31| |// FIXME: These test-cases illustrate confusing results of nested functions. - 32| |// See https://github.com/rust-lang/rust/issues/93319 - 33| |mod nested_fns { - 34| | #[no_coverage] - 35| | pub fn outer_not_covered(is_true: bool) { - 36| 1| fn inner(is_true: bool) { - 37| 1| if is_true { - 38| 1| println!("called and covered"); - 39| 1| } else { - 40| 0| println!("absolutely not covered"); - 41| 0| } - 42| 1| } - 43| | println!("called but not covered"); - 44| | inner(is_true); - 45| | } - 46| | - 47| 1| pub fn outer(is_true: bool) { - 48| 1| println!("called and covered"); - 49| 1| inner_not_covered(is_true); - 50| 1| - 51| 1| #[no_coverage] - 52| 1| fn inner_not_covered(is_true: bool) { - 53| 1| if is_true { - 54| 1| println!("called but not covered"); - 55| 1| } else { - 56| 1| println!("absolutely not covered"); - 57| 1| } - 58| 1| } - 59| 1| } - 60| | - 61| 1| pub fn outer_both_covered(is_true: bool) { - 62| 1| println!("called and covered"); - 63| 1| inner(is_true); - 64| 1| - 65| 1| fn inner(is_true: bool) { - 66| 1| if is_true { - 67| 1| println!("called and covered"); - 68| 1| } else { - 69| 0| println!("absolutely not covered"); - 70| 0| } - 71| 1| } - 72| 1| } - 73| |} - 74| | - 75| 1|fn main() { - 76| 1| let is_true = std::env::args().len() == 1; - 77| 1| - 78| 1| do_not_add_coverage_1(); - 79| 1| do_not_add_coverage_2(); - 80| 1| add_coverage_1(); - 81| 1| add_coverage_2(); - 82| 1| - 83| 1| nested_fns::outer_not_covered(is_true); - 84| 1| nested_fns::outer(is_true); - 85| 1| nested_fns::outer_both_covered(is_true); - 86| 1|} + LL| |// Enables `no_coverage` on the entire crate + LL| |#![feature(no_coverage)] + LL| | + LL| |#[no_coverage] + LL| |fn do_not_add_coverage_1() { + LL| | println!("called but not covered"); + LL| |} + LL| | + LL| |fn do_not_add_coverage_2() { + LL| | #![no_coverage] + LL| | println!("called but not covered"); + LL| |} + LL| | + LL| |#[no_coverage] + LL| |fn do_not_add_coverage_not_called() { + LL| | println!("not called and not covered"); + LL| |} + LL| | + LL| 1|fn add_coverage_1() { + LL| 1| println!("called and covered"); + LL| 1|} + LL| | + LL| 1|fn add_coverage_2() { + LL| 1| println!("called and covered"); + LL| 1|} + LL| | + LL| 0|fn add_coverage_not_called() { + LL| 0| println!("not called but covered"); + LL| 0|} + LL| | + LL| |// FIXME: These test-cases illustrate confusing results of nested functions. + LL| |// See https://github.com/rust-lang/rust/issues/93319 + LL| |mod nested_fns { + LL| | #[no_coverage] + LL| | pub fn outer_not_covered(is_true: bool) { + LL| 1| fn inner(is_true: bool) { + LL| 1| if is_true { + LL| 1| println!("called and covered"); + LL| 1| } else { + LL| 0| println!("absolutely not covered"); + LL| 0| } + LL| 1| } + LL| | println!("called but not covered"); + LL| | inner(is_true); + LL| | } + LL| | + LL| 1| pub fn outer(is_true: bool) { + LL| 1| println!("called and covered"); + LL| 1| inner_not_covered(is_true); + LL| 1| + LL| 1| #[no_coverage] + LL| 1| fn inner_not_covered(is_true: bool) { + LL| 1| if is_true { + LL| 1| println!("called but not covered"); + LL| 1| } else { + LL| 1| println!("absolutely not covered"); + LL| 1| } + LL| 1| } + LL| 1| } + LL| | + LL| 1| pub fn outer_both_covered(is_true: bool) { + LL| 1| println!("called and covered"); + LL| 1| inner(is_true); + LL| 1| + LL| 1| fn inner(is_true: bool) { + LL| 1| if is_true { + LL| 1| println!("called and covered"); + LL| 1| } else { + LL| 0| println!("absolutely not covered"); + LL| 0| } + LL| 1| } + LL| 1| } + LL| |} + LL| | + LL| 1|fn main() { + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| do_not_add_coverage_1(); + LL| 1| do_not_add_coverage_2(); + LL| 1| add_coverage_1(); + LL| 1| add_coverage_2(); + LL| 1| + LL| 1| nested_fns::outer_not_covered(is_true); + LL| 1| nested_fns::outer(is_true); + LL| 1| nested_fns::outer_both_covered(is_true); + LL| 1|} diff --git a/tests/run-coverage/overflow.coverage b/tests/run-coverage/overflow.coverage index 95043759166b..2d60316e2158 100644 --- a/tests/run-coverage/overflow.coverage +++ b/tests/run-coverage/overflow.coverage @@ -1,64 +1,64 @@ - 1| |#![allow(unused_assignments)] - 2| |// failure-status: 101 - 3| | - 4| 4|fn might_overflow(to_add: u32) -> u32 { - 5| 4| if to_add > 5 { - 6| 1| println!("this will probably overflow"); - 7| 3| } - 8| 4| let add_to = u32::MAX - 5; - 9| 4| println!("does {} + {} overflow?", add_to, to_add); - 10| 4| let result = to_add + add_to; - 11| 4| println!("continuing after overflow check"); - 12| 4| result - 13| 4|} - 14| | - 15| 1|fn main() -> Result<(),u8> { - 16| 1| let mut countdown = 10; - 17| 11| while countdown > 0 { - 18| 11| if countdown == 1 { - 19| 1| let result = might_overflow(10); - 20| 1| println!("Result: {}", result); - 21| 10| } else if countdown < 5 { - 22| 3| let result = might_overflow(1); - 23| 3| println!("Result: {}", result); - 24| 6| } - 25| 10| countdown -= 1; - 26| | } - 27| 0| Ok(()) - 28| 0|} - 29| | - 30| |// Notes: - 31| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, - 32| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. - 33| |// 2. This test confirms the coverage generated when a program passes or fails a - 34| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). - 35| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, - 36| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not - 37| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as - 38| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and - 39| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not - 40| |// get its own coverage counter. - 41| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. - 42| |// In this test, the final count for the statements after the `if` block in `might_overflow()` - 43| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending - 44| |// on the MIR graph and the structure of the code, this count could have been 3 (which might - 45| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before - 46| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented - 47| |// via StatementKind::Counter at the end of the block, but (as in the case in this test), - 48| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on - 49| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was - 50| |// executed, and counted, 4 times, before reaching the overflow add. - 51| | - 52| |// If the program did not overflow, the coverage for `might_overflow()` would look like this: - 53| |// - 54| |// 4| |fn might_overflow(to_add: u32) -> u32 { - 55| |// 5| 4| if to_add > 5 { - 56| |// 6| 0| println!("this will probably overflow"); - 57| |// 7| 4| } - 58| |// 8| 4| let add_to = u32::MAX - 5; - 59| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add); - 60| |// 10| 4| let result = to_add + add_to; - 61| |// 11| 4| println!("continuing after overflow check"); - 62| |// 12| 4| result - 63| |// 13| 4|} + LL| |#![allow(unused_assignments)] + LL| |// failure-status: 101 + LL| | + LL| 4|fn might_overflow(to_add: u32) -> u32 { + LL| 4| if to_add > 5 { + LL| 1| println!("this will probably overflow"); + LL| 3| } + LL| 4| let add_to = u32::MAX - 5; + LL| 4| println!("does {} + {} overflow?", add_to, to_add); + LL| 4| let result = to_add + add_to; + LL| 4| println!("continuing after overflow check"); + LL| 4| result + LL| 4|} + LL| | + LL| 1|fn main() -> Result<(),u8> { + LL| 1| let mut countdown = 10; + LL| 11| while countdown > 0 { + LL| 11| if countdown == 1 { + LL| 1| let result = might_overflow(10); + LL| 1| println!("Result: {}", result); + LL| 10| } else if countdown < 5 { + LL| 3| let result = might_overflow(1); + LL| 3| println!("Result: {}", result); + LL| 6| } + LL| 10| countdown -= 1; + LL| | } + LL| 0| Ok(()) + LL| 0|} + LL| | + LL| |// Notes: + LL| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, + LL| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. + LL| |// 2. This test confirms the coverage generated when a program passes or fails a + LL| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). + LL| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, + LL| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not + LL| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as + LL| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and + LL| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not + LL| |// get its own coverage counter. + LL| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. + LL| |// In this test, the final count for the statements after the `if` block in `might_overflow()` + LL| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending + LL| |// on the MIR graph and the structure of the code, this count could have been 3 (which might + LL| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before + LL| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented + LL| |// via StatementKind::Counter at the end of the block, but (as in the case in this test), + LL| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on + LL| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was + LL| |// executed, and counted, 4 times, before reaching the overflow add. + LL| | + LL| |// If the program did not overflow, the coverage for `might_overflow()` would look like this: + LL| |// + LL| |// 4| |fn might_overflow(to_add: u32) -> u32 { + LL| |// 5| 4| if to_add > 5 { + LL| |// 6| 0| println!("this will probably overflow"); + LL| |// 7| 4| } + LL| |// 8| 4| let add_to = u32::MAX - 5; + LL| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add); + LL| |// 10| 4| let result = to_add + add_to; + LL| |// 11| 4| println!("continuing after overflow check"); + LL| |// 12| 4| result + LL| |// 13| 4|} diff --git a/tests/run-coverage/panic_unwind.coverage b/tests/run-coverage/panic_unwind.coverage index 58b9ba448eea..2b0777ef215d 100644 --- a/tests/run-coverage/panic_unwind.coverage +++ b/tests/run-coverage/panic_unwind.coverage @@ -1,32 +1,32 @@ - 1| |#![allow(unused_assignments)] - 2| |// failure-status: 101 - 3| | - 4| 4|fn might_panic(should_panic: bool) { - 5| 4| if should_panic { - 6| 1| println!("panicking..."); - 7| 1| panic!("panics"); - 8| 3| } else { - 9| 3| println!("Don't Panic"); - 10| 3| } - 11| 3|} - 12| | - 13| 1|fn main() -> Result<(), u8> { - 14| 1| let mut countdown = 10; - 15| 11| while countdown > 0 { - 16| 11| if countdown == 1 { - 17| 1| might_panic(true); - 18| 10| } else if countdown < 5 { - 19| 3| might_panic(false); - 20| 6| } - 21| 10| countdown -= 1; - 22| | } - 23| 0| Ok(()) - 24| 0|} - 25| | - 26| |// Notes: - 27| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and - 28| |// `try_error_result.rs`. - 29| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the - 30| |// normal program exit cleanup, including writing out the current values of the coverage - 31| |// counters. + LL| |#![allow(unused_assignments)] + LL| |// failure-status: 101 + LL| | + LL| 4|fn might_panic(should_panic: bool) { + LL| 4| if should_panic { + LL| 1| println!("panicking..."); + LL| 1| panic!("panics"); + LL| 3| } else { + LL| 3| println!("Don't Panic"); + LL| 3| } + LL| 3|} + LL| | + LL| 1|fn main() -> Result<(), u8> { + LL| 1| let mut countdown = 10; + LL| 11| while countdown > 0 { + LL| 11| if countdown == 1 { + LL| 1| might_panic(true); + LL| 10| } else if countdown < 5 { + LL| 3| might_panic(false); + LL| 6| } + LL| 10| countdown -= 1; + LL| | } + LL| 0| Ok(()) + LL| 0|} + LL| | + LL| |// Notes: + LL| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and + LL| |// `try_error_result.rs`. + LL| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the + LL| |// normal program exit cleanup, including writing out the current values of the coverage + LL| |// counters. diff --git a/tests/run-coverage/partial_eq.coverage b/tests/run-coverage/partial_eq.coverage index be4f23ec0bad..c6d9ad6cf27e 100644 --- a/tests/run-coverage/partial_eq.coverage +++ b/tests/run-coverage/partial_eq.coverage @@ -1,48 +1,48 @@ - 1| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the - 2| |// structure of this test. - 3| | - 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + LL| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the + LL| |// structure of this test. + LL| | + LL| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] ^0 ^0 ^0 ^1 ^1 ^0^0 - 5| |pub struct Version { - 6| | major: usize, - 7| | minor: usize, - 8| | patch: usize, - 9| |} - 10| | - 11| |impl Version { - 12| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 13| 2| Self { - 14| 2| major, - 15| 2| minor, - 16| 2| patch, - 17| 2| } - 18| 2| } - 19| |} - 20| | - 21| 1|fn main() { - 22| 1| let version_3_2_1 = Version::new(3, 2, 1); - 23| 1| let version_3_3_0 = Version::new(3, 3, 0); - 24| 1| - 25| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); - 26| 1|} - 27| | - 28| |/* - 29| | - 30| |This test verifies a bug was fixed that otherwise generated this error: - 31| | - 32| |thread 'rustc' panicked at 'No counters provided the source_hash for function: - 33| | Instance { - 34| | def: Item(WithOptConstParam { - 35| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), - 36| | const_param_did: None - 37| | }), - 38| | args: [] - 39| | }' - 40| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage - 41| |without a code region associated with any `Counter`. Code regions were associated with at least - 42| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen - 43| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the - 44| |`function_source_hash` without a code region, if necessary. - 45| | - 46| |*/ + LL| |pub struct Version { + LL| | major: usize, + LL| | minor: usize, + LL| | patch: usize, + LL| |} + LL| | + LL| |impl Version { + LL| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self { + LL| 2| Self { + LL| 2| major, + LL| 2| minor, + LL| 2| patch, + LL| 2| } + LL| 2| } + LL| |} + LL| | + LL| 1|fn main() { + LL| 1| let version_3_2_1 = Version::new(3, 2, 1); + LL| 1| let version_3_3_0 = Version::new(3, 3, 0); + LL| 1| + LL| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); + LL| 1|} + LL| | + LL| |/* + LL| | + LL| |This test verifies a bug was fixed that otherwise generated this error: + LL| | + LL| |thread 'rustc' panicked at 'No counters provided the source_hash for function: + LL| | Instance { + LL| | def: Item(WithOptConstParam { + LL| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), + LL| | const_param_did: None + LL| | }), + LL| | args: [] + LL| | }' + LL| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage + LL| |without a code region associated with any `Counter`. Code regions were associated with at least + LL| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen + LL| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the + LL| |`function_source_hash` without a code region, if necessary. + LL| | + LL| |*/ diff --git a/tests/run-coverage/simple_loop.coverage b/tests/run-coverage/simple_loop.coverage index feb83bad674d..691c6cd1e7dd 100644 --- a/tests/run-coverage/simple_loop.coverage +++ b/tests/run-coverage/simple_loop.coverage @@ -1,37 +1,37 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| - 11| 1| if - 12| 1| is_true - 13| 1| { - 14| 1| countdown - 15| 1| = - 16| 1| 10 - 17| 1| ; - 18| 1| } + LL| |#![allow(unused_assignments)] + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let mut countdown = 0; + LL| 1| + LL| 1| if + LL| 1| is_true + LL| 1| { + LL| 1| countdown + LL| 1| = + LL| 1| 10 + LL| 1| ; + LL| 1| } ^0 - 19| | - 20| | loop - 21| | { - 22| | if - 23| 11| countdown - 24| 11| == - 25| 11| 0 - 26| | { - 27| 1| break - 28| | ; - 29| 10| } - 30| 10| countdown - 31| 10| -= - 32| 10| 1 - 33| | ; - 34| | } - 35| 1|} + LL| | + LL| | loop + LL| | { + LL| | if + LL| 11| countdown + LL| 11| == + LL| 11| 0 + LL| | { + LL| 1| break + LL| | ; + LL| 10| } + LL| 10| countdown + LL| 10| -= + LL| 10| 1 + LL| | ; + LL| | } + LL| 1|} diff --git a/tests/run-coverage/simple_match.coverage b/tests/run-coverage/simple_match.coverage index b9298213111c..7f5dd3bb6463 100644 --- a/tests/run-coverage/simple_match.coverage +++ b/tests/run-coverage/simple_match.coverage @@ -1,45 +1,45 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 1; - 10| 1| if is_true { - 11| 1| countdown = 0; - 12| 1| } + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| 1|fn main() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| + LL| 1| let mut countdown = 1; + LL| 1| if is_true { + LL| 1| countdown = 0; + LL| 1| } ^0 - 13| | - 14| | for - 15| | _ - 16| | in - 17| 3| 0..2 - 18| | { - 19| | let z - 20| | ; - 21| | match - 22| 2| countdown - 23| | { - 24| 1| x - 25| | if - 26| 2| x - 27| 2| < - 28| 2| 1 - 29| | => - 30| 1| { - 31| 1| z = countdown - 32| 1| ; - 33| 1| let y = countdown - 34| 1| ; - 35| 1| countdown = 10 - 36| 1| ; - 37| 1| } - 38| | _ - 39| | => - 40| 1| {} - 41| | } - 42| | } - 43| 1|} + LL| | + LL| | for + LL| | _ + LL| | in + LL| 3| 0..2 + LL| | { + LL| | let z + LL| | ; + LL| | match + LL| 2| countdown + LL| | { + LL| 1| x + LL| | if + LL| 2| x + LL| 2| < + LL| 2| 1 + LL| | => + LL| 1| { + LL| 1| z = countdown + LL| 1| ; + LL| 1| let y = countdown + LL| 1| ; + LL| 1| countdown = 10 + LL| 1| ; + LL| 1| } + LL| | _ + LL| | => + LL| 1| {} + LL| | } + LL| | } + LL| 1|} diff --git a/tests/run-coverage/sort_groups.coverage b/tests/run-coverage/sort_groups.coverage index 81468cb35dac..8733bf48a9c8 100644 --- a/tests/run-coverage/sort_groups.coverage +++ b/tests/run-coverage/sort_groups.coverage @@ -1,49 +1,49 @@ - 1| |// compile-flags: --edition=2021 - 2| | - 3| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a - 4| |// predictable order, while preserving their heterogeneous contents. - 5| | - 6| 1|fn main() { - 7| 1| let cond = std::env::args().len() > 1; - 8| 1| generic_fn::<()>(cond); - 9| 1| generic_fn::<&'static str>(!cond); - 10| 1| if false { - 11| 0| generic_fn::(cond); - 12| 1| } - 13| 1| generic_fn::(cond); - 14| 1| other_fn(); - 15| 1|} - 16| | - 17| 3|fn generic_fn(cond: bool) { - 18| 3| if cond { - 19| 1| println!("{}", std::any::type_name::()); - 20| 2| } - 21| 3|} + LL| |// compile-flags: --edition=2021 + LL| | + LL| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a + LL| |// predictable order, while preserving their heterogeneous contents. + LL| | + LL| 1|fn main() { + LL| 1| let cond = std::env::args().len() > 1; + LL| 1| generic_fn::<()>(cond); + LL| 1| generic_fn::<&'static str>(!cond); + LL| 1| if false { + LL| 0| generic_fn::(cond); + LL| 1| } + LL| 1| generic_fn::(cond); + LL| 1| other_fn(); + LL| 1|} + LL| | + LL| 3|fn generic_fn(cond: bool) { + LL| 3| if cond { + LL| 1| println!("{}", std::any::type_name::()); + LL| 2| } + LL| 3|} ------------------ | Unexecuted instantiation: sort_groups::generic_fn:: ------------------ | sort_groups::generic_fn::<&str>: - | 17| 1|fn generic_fn(cond: bool) { - | 18| 1| if cond { - | 19| 1| println!("{}", std::any::type_name::()); - | 20| 1| } + | LL| 1|fn generic_fn(cond: bool) { + | LL| 1| if cond { + | LL| 1| println!("{}", std::any::type_name::()); + | LL| 1| } | ^0 - | 21| 1|} + | LL| 1|} ------------------ | sort_groups::generic_fn::<()>: - | 17| 1|fn generic_fn(cond: bool) { - | 18| 1| if cond { - | 19| 0| println!("{}", std::any::type_name::()); - | 20| 1| } - | 21| 1|} + | LL| 1|fn generic_fn(cond: bool) { + | LL| 1| if cond { + | LL| 0| println!("{}", std::any::type_name::()); + | LL| 1| } + | LL| 1|} ------------------ | sort_groups::generic_fn::: - | 17| 1|fn generic_fn(cond: bool) { - | 18| 1| if cond { - | 19| 0| println!("{}", std::any::type_name::()); - | 20| 1| } - | 21| 1|} + | LL| 1|fn generic_fn(cond: bool) { + | LL| 1| if cond { + | LL| 0| println!("{}", std::any::type_name::()); + | LL| 1| } + | LL| 1|} ------------------ - 22| | - 23| 1|fn other_fn() {} + LL| | + LL| 1|fn other_fn() {} diff --git a/tests/run-coverage/test_harness.coverage b/tests/run-coverage/test_harness.coverage index 93bd1cfcb489..ff6009f6fce4 100644 --- a/tests/run-coverage/test_harness.coverage +++ b/tests/run-coverage/test_harness.coverage @@ -1,11 +1,11 @@ - 1| |// Verify that the entry point injected by the test harness doesn't cause - 2| |// weird artifacts in the coverage report (e.g. issue #10749). - 3| | - 4| |// compile-flags: --test - 5| | - 6| |#[allow(dead_code)] - 7| 0|fn unused() {} - 8| | - 9| 1|#[test] - 10| 1|fn my_test() {} + LL| |// Verify that the entry point injected by the test harness doesn't cause + LL| |// weird artifacts in the coverage report (e.g. issue #10749). + LL| | + LL| |// compile-flags: --test + LL| | + LL| |#[allow(dead_code)] + LL| 0|fn unused() {} + LL| | + LL| 1|#[test] + LL| 1|fn my_test() {} diff --git a/tests/run-coverage/tight_inf_loop.coverage b/tests/run-coverage/tight_inf_loop.coverage index 2d4c57f451a2..c15c76b3aba2 100644 --- a/tests/run-coverage/tight_inf_loop.coverage +++ b/tests/run-coverage/tight_inf_loop.coverage @@ -1,6 +1,6 @@ - 1| 1|fn main() { - 2| 1| if false { - 3| 0| loop {} - 4| 1| } - 5| 1|} + LL| 1|fn main() { + LL| 1| if false { + LL| 0| loop {} + LL| 1| } + LL| 1|} diff --git a/tests/run-coverage/try_error_result.coverage b/tests/run-coverage/try_error_result.coverage index efe573a5607d..fcdb7437d00d 100644 --- a/tests/run-coverage/try_error_result.coverage +++ b/tests/run-coverage/try_error_result.coverage @@ -1,125 +1,125 @@ - 1| |#![allow(unused_assignments)] - 2| |// failure-status: 1 - 3| | - 4| 6|fn call(return_error: bool) -> Result<(),()> { - 5| 6| if return_error { - 6| 1| Err(()) - 7| | } else { - 8| 5| Ok(()) - 9| | } - 10| 6|} - 11| | - 12| 1|fn test1() -> Result<(),()> { - 13| 1| let mut - 14| 1| countdown = 10 - 15| | ; - 16| | for - 17| | _ - 18| | in - 19| 6| 0..10 - 20| | { - 21| 6| countdown - 22| 6| -= 1 - 23| 6| ; - 24| 6| if - 25| 6| countdown < 5 - 26| | { - 27| 1| call(/*return_error=*/ true)?; - 28| 0| call(/*return_error=*/ false)?; - 29| | } - 30| | else - 31| | { - 32| 5| call(/*return_error=*/ false)?; + LL| |#![allow(unused_assignments)] + LL| |// failure-status: 1 + LL| | + LL| 6|fn call(return_error: bool) -> Result<(),()> { + LL| 6| if return_error { + LL| 1| Err(()) + LL| | } else { + LL| 5| Ok(()) + LL| | } + LL| 6|} + LL| | + LL| 1|fn test1() -> Result<(),()> { + LL| 1| let mut + LL| 1| countdown = 10 + LL| | ; + LL| | for + LL| | _ + LL| | in + LL| 6| 0..10 + LL| | { + LL| 6| countdown + LL| 6| -= 1 + LL| 6| ; + LL| 6| if + LL| 6| countdown < 5 + LL| | { + LL| 1| call(/*return_error=*/ true)?; + LL| 0| call(/*return_error=*/ false)?; + LL| | } + LL| | else + LL| | { + LL| 5| call(/*return_error=*/ false)?; ^0 - 33| | } - 34| | } - 35| 0| Ok(()) - 36| 1|} - 37| | - 38| |struct Thing1; - 39| |impl Thing1 { - 40| 18| fn get_thing_2(&self, return_error: bool) -> Result { - 41| 18| if return_error { - 42| 1| Err(()) - 43| | } else { - 44| 17| Ok(Thing2{}) - 45| | } - 46| 18| } - 47| |} - 48| | - 49| |struct Thing2; - 50| |impl Thing2 { - 51| 17| fn call(&self, return_error: bool) -> Result { - 52| 17| if return_error { - 53| 2| Err(()) - 54| | } else { - 55| 15| Ok(57) - 56| | } - 57| 17| } - 58| |} - 59| | - 60| 1|fn test2() -> Result<(),()> { - 61| 1| let thing1 = Thing1{}; - 62| 1| let mut - 63| 1| countdown = 10 - 64| | ; - 65| | for - 66| | _ - 67| | in - 68| 6| 0..10 - 69| | { - 70| 6| countdown - 71| 6| -= 1 - 72| 6| ; - 73| 6| if - 74| 6| countdown < 5 - 75| | { - 76| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); + LL| | } + LL| | } + LL| 0| Ok(()) + LL| 1|} + LL| | + LL| |struct Thing1; + LL| |impl Thing1 { + LL| 18| fn get_thing_2(&self, return_error: bool) -> Result { + LL| 18| if return_error { + LL| 1| Err(()) + LL| | } else { + LL| 17| Ok(Thing2{}) + LL| | } + LL| 18| } + LL| |} + LL| | + LL| |struct Thing2; + LL| |impl Thing2 { + LL| 17| fn call(&self, return_error: bool) -> Result { + LL| 17| if return_error { + LL| 2| Err(()) + LL| | } else { + LL| 15| Ok(57) + LL| | } + LL| 17| } + LL| |} + LL| | + LL| 1|fn test2() -> Result<(),()> { + LL| 1| let thing1 = Thing1{}; + LL| 1| let mut + LL| 1| countdown = 10 + LL| | ; + LL| | for + LL| | _ + LL| | in + LL| 6| 0..10 + LL| | { + LL| 6| countdown + LL| 6| -= 1 + LL| 6| ; + LL| 6| if + LL| 6| countdown < 5 + LL| | { + LL| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); ^0 - 77| 1| thing1 - 78| 1| . - 79| 1| get_thing_2(/*return_error=*/ false) - 80| 0| ? - 81| | . - 82| 1| call(/*return_error=*/ true) - 83| 1| . - 84| 1| expect_err( - 85| 1| "call should fail" - 86| 1| ); - 87| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; + LL| 1| thing1 + LL| 1| . + LL| 1| get_thing_2(/*return_error=*/ false) + LL| 0| ? + LL| | . + LL| 1| call(/*return_error=*/ true) + LL| 1| . + LL| 1| expect_err( + LL| 1| "call should fail" + LL| 1| ); + LL| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; ^0 ^0 ^0 - 88| 0| assert_eq!(val, 57); - 89| 0| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; - 90| 0| assert_eq!(val, 57); - 91| | } - 92| | else - 93| | { - 94| 5| let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; + LL| 0| assert_eq!(val, 57); + LL| 0| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; + LL| 0| assert_eq!(val, 57); + LL| | } + LL| | else + LL| | { + LL| 5| let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; ^0 ^0 - 95| 5| assert_eq!(val, 57); - 96| 5| let val = thing1 - 97| 5| .get_thing_2(/*return_error=*/ false)? + LL| 5| assert_eq!(val, 57); + LL| 5| let val = thing1 + LL| 5| .get_thing_2(/*return_error=*/ false)? ^0 - 98| 5| .call(/*return_error=*/ false)?; + LL| 5| .call(/*return_error=*/ false)?; ^0 - 99| 5| assert_eq!(val, 57); - 100| 5| let val = thing1 - 101| 5| .get_thing_2(/*return_error=*/ false) - 102| 0| ? - 103| 5| .call(/*return_error=*/ false) - 104| 0| ? - 105| | ; - 106| 5| assert_eq!(val, 57); - 107| | } - 108| | } - 109| 0| Ok(()) - 110| 1|} - 111| | - 112| 1|fn main() -> Result<(),()> { - 113| 1| test1().expect_err("test1 should fail"); - 114| 1| test2() - 115| 1| ? - 116| | ; - 117| 0| Ok(()) - 118| 1|} + LL| 5| assert_eq!(val, 57); + LL| 5| let val = thing1 + LL| 5| .get_thing_2(/*return_error=*/ false) + LL| 0| ? + LL| 5| .call(/*return_error=*/ false) + LL| 0| ? + LL| | ; + LL| 5| assert_eq!(val, 57); + LL| | } + LL| | } + LL| 0| Ok(()) + LL| 1|} + LL| | + LL| 1|fn main() -> Result<(),()> { + LL| 1| test1().expect_err("test1 should fail"); + LL| 1| test2() + LL| 1| ? + LL| | ; + LL| 0| Ok(()) + LL| 1|} diff --git a/tests/run-coverage/unused.coverage b/tests/run-coverage/unused.coverage index 15fcf21c0ef3..ba25e34bf86d 100644 --- a/tests/run-coverage/unused.coverage +++ b/tests/run-coverage/unused.coverage @@ -1,62 +1,62 @@ - 1| 2|fn foo(x: T) { - 2| 2| let mut i = 0; - 3| 22| while i < 10 { - 4| 20| i != 0 || i != 0; + LL| 2|fn foo(x: T) { + LL| 2| let mut i = 0; + LL| 22| while i < 10 { + LL| 20| i != 0 || i != 0; ^2 - 5| 20| i += 1; - 6| | } - 7| 2|} + LL| 20| i += 1; + LL| | } + LL| 2|} ------------------ | unused::foo::: - | 1| 1|fn foo(x: T) { - | 2| 1| let mut i = 0; - | 3| 11| while i < 10 { - | 4| 10| i != 0 || i != 0; + | LL| 1|fn foo(x: T) { + | LL| 1| let mut i = 0; + | LL| 11| while i < 10 { + | LL| 10| i != 0 || i != 0; | ^1 - | 5| 10| i += 1; - | 6| | } - | 7| 1|} + | LL| 10| i += 1; + | LL| | } + | LL| 1|} ------------------ | unused::foo::: - | 1| 1|fn foo(x: T) { - | 2| 1| let mut i = 0; - | 3| 11| while i < 10 { - | 4| 10| i != 0 || i != 0; + | LL| 1|fn foo(x: T) { + | LL| 1| let mut i = 0; + | LL| 11| while i < 10 { + | LL| 10| i != 0 || i != 0; | ^1 - | 5| 10| i += 1; - | 6| | } - | 7| 1|} + | LL| 10| i += 1; + | LL| | } + | LL| 1|} ------------------ - 8| | - 9| 0|fn unused_template_func(x: T) { - 10| 0| let mut i = 0; - 11| 0| while i < 10 { - 12| 0| i != 0 || i != 0; - 13| 0| i += 1; - 14| | } - 15| 0|} - 16| | - 17| 0|fn unused_func(mut a: u32) { - 18| 0| if a != 0 { - 19| 0| a += 1; - 20| 0| } - 21| 0|} - 22| | - 23| 0|fn unused_func2(mut a: u32) { - 24| 0| if a != 0 { - 25| 0| a += 1; - 26| 0| } - 27| 0|} - 28| | - 29| 0|fn unused_func3(mut a: u32) { - 30| 0| if a != 0 { - 31| 0| a += 1; - 32| 0| } - 33| 0|} - 34| | - 35| 1|fn main() -> Result<(), u8> { - 36| 1| foo::(0); - 37| 1| foo::(0.0); - 38| 1| Ok(()) - 39| 1|} + LL| | + LL| 0|fn unused_template_func(x: T) { + LL| 0| let mut i = 0; + LL| 0| while i < 10 { + LL| 0| i != 0 || i != 0; + LL| 0| i += 1; + LL| | } + LL| 0|} + LL| | + LL| 0|fn unused_func(mut a: u32) { + LL| 0| if a != 0 { + LL| 0| a += 1; + LL| 0| } + LL| 0|} + LL| | + LL| 0|fn unused_func2(mut a: u32) { + LL| 0| if a != 0 { + LL| 0| a += 1; + LL| 0| } + LL| 0|} + LL| | + LL| 0|fn unused_func3(mut a: u32) { + LL| 0| if a != 0 { + LL| 0| a += 1; + LL| 0| } + LL| 0|} + LL| | + LL| 1|fn main() -> Result<(), u8> { + LL| 1| foo::(0); + LL| 1| foo::(0.0); + LL| 1| Ok(()) + LL| 1|} diff --git a/tests/run-coverage/unused_mod.coverage b/tests/run-coverage/unused_mod.coverage index e1d82f66f755..558dfaa5cffc 100644 --- a/tests/run-coverage/unused_mod.coverage +++ b/tests/run-coverage/unused_mod.coverage @@ -1,13 +1,13 @@ $DIR/auxiliary/unused_mod_helper.rs: - 1| 0|pub fn never_called_function() { - 2| 0| println!("I am never called"); - 3| 0|} + LL| 0|pub fn never_called_function() { + LL| 0| println!("I am never called"); + LL| 0|} $DIR/unused_mod.rs: - 1| |#[path = "auxiliary/unused_mod_helper.rs"] - 2| |mod unused_module; - 3| | - 4| 1|fn main() { - 5| 1| println!("hello world!"); - 6| 1|} + LL| |#[path = "auxiliary/unused_mod_helper.rs"] + LL| |mod unused_module; + LL| | + LL| 1|fn main() { + LL| 1| println!("hello world!"); + LL| 1|} diff --git a/tests/run-coverage/uses_crate.coverage b/tests/run-coverage/uses_crate.coverage index ccdcf3503349..9da096dbd50a 100644 --- a/tests/run-coverage/uses_crate.coverage +++ b/tests/run-coverage/uses_crate.coverage @@ -1,170 +1,170 @@ $DIR/auxiliary/used_crate.rs: - 1| |#![allow(unused_assignments, unused_variables)] - 2| |// compile-flags: -C opt-level=3 - 3| |use std::fmt::Debug; // ^^ validates coverage now works with optimizations - 4| | - 5| 1|pub fn used_function() { - 6| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 7| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 8| 1| // dependent conditions. - 9| 1| let is_true = std::env::args().len() == 1; - 10| 1| let mut countdown = 0; - 11| 1| if is_true { - 12| 1| countdown = 10; - 13| 1| } + LL| |#![allow(unused_assignments, unused_variables)] + LL| |// compile-flags: -C opt-level=3 + LL| |use std::fmt::Debug; // ^^ validates coverage now works with optimizations + LL| | + LL| 1|pub fn used_function() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| let mut countdown = 0; + LL| 1| if is_true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 14| 1| use_this_lib_crate(); - 15| 1|} - 16| | - 17| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - 19| 2|} + LL| 1| use_this_lib_crate(); + LL| 1|} + LL| | + LL| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { + LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + LL| 2|} ------------------ | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> ------------------ | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: - | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 19| 1|} + | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ | used_crate::used_only_from_bin_crate_generic_function::<&str>: - | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 19| 1|} + | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ - 20| |// Expect for above function: `Unexecuted instantiation` (see below) - 21| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - 23| 2|} + LL| |// Expect for above function: `Unexecuted instantiation` (see below) + LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + LL| 2|} ------------------ | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: - | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 23| 1|} + | LL| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ | used_crate::used_only_from_this_lib_crate_generic_function::>: - | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 23| 1|} + | LL| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ - 24| | - 25| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 26| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 27| 2|} + LL| | + LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 2|} ------------------ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 27| 1|} + | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::>: - | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 27| 1|} + | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ - 28| | - 29| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 30| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 31| 2|} + LL| | + LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 2|} ------------------ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 29| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 30| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 31| 1|} + | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 29| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 30| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 31| 1|} + | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ - 32| | - 33| 0|pub fn unused_generic_function(arg: T) { - 34| 0| println!("unused_generic_function with {:?}", arg); - 35| 0|} - 36| | - 37| 0|pub fn unused_function() { - 38| 0| let is_true = std::env::args().len() == 1; - 39| 0| let mut countdown = 2; - 40| 0| if !is_true { - 41| 0| countdown = 20; - 42| 0| } - 43| 0|} - 44| | - 45| 0|fn unused_private_function() { - 46| 0| let is_true = std::env::args().len() == 1; - 47| 0| let mut countdown = 2; - 48| 0| if !is_true { - 49| 0| countdown = 20; - 50| 0| } - 51| 0|} - 52| | - 53| 1|fn use_this_lib_crate() { - 54| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - 55| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - 56| 1| "used from library used_crate.rs", - 57| 1| ); - 58| 1| let some_vec = vec![5, 6, 7, 8]; - 59| 1| used_only_from_this_lib_crate_generic_function(some_vec); - 60| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); - 61| 1|} - 62| | - 63| |// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results, - 64| |// for example: - 65| |// - 66| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> - 67| |// - 68| |// These notices appear when `llvm-cov` shows instantiations. This may be a - 69| |// default option, but it can be suppressed with: - 70| |// - 71| |// ```shell - 72| |// $ `llvm-cov show --show-instantiations=0 ...` - 73| |// ``` - 74| |// - 75| |// The notice is triggered because the function is unused by the library itself, - 76| |// and when the library is compiled, a synthetic function is generated, so - 77| |// unused function coverage can be reported. Coverage can be skipped for unused - 78| |// generic functions with: - 79| |// - 80| |// ```shell - 81| |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` - 82| |// ``` - 83| |// - 84| |// Even though this function is used by `uses_crate.rs` (and - 85| |// counted), with substitutions for `T`, those instantiations are only generated - 86| |// when the generic function is actually used (from the binary, not from this - 87| |// library crate). So the test result shows coverage for all instantiated - 88| |// versions and their generic type substitutions, plus the `Unexecuted - 89| |// instantiation` message for the non-substituted version. This is valid, but - 90| |// unfortunately a little confusing. - 91| |// - 92| |// The library crate has its own coverage map, and the only way to show unused - 93| |// coverage of a generic function is to include the generic function in the - 94| |// coverage map, marked as an "unused function". If the library were used by - 95| |// another binary that never used this generic function, then it would be valid - 96| |// to show the unused generic, with unknown substitution (`_`). - 97| |// - 98| |// The alternative is to exclude all generics from being included in the "unused - 99| |// functions" list, which would then omit coverage results for - 100| |// `unused_generic_function()`, below. + LL| | + LL| 0|pub fn unused_generic_function(arg: T) { + LL| 0| println!("unused_generic_function with {:?}", arg); + LL| 0|} + LL| | + LL| 0|pub fn unused_function() { + LL| 0| let is_true = std::env::args().len() == 1; + LL| 0| let mut countdown = 2; + LL| 0| if !is_true { + LL| 0| countdown = 20; + LL| 0| } + LL| 0|} + LL| | + LL| 0|fn unused_private_function() { + LL| 0| let is_true = std::env::args().len() == 1; + LL| 0| let mut countdown = 2; + LL| 0| if !is_true { + LL| 0| countdown = 20; + LL| 0| } + LL| 0|} + LL| | + LL| 1|fn use_this_lib_crate() { + LL| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + LL| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + LL| 1| "used from library used_crate.rs", + LL| 1| ); + LL| 1| let some_vec = vec![5, 6, 7, 8]; + LL| 1| used_only_from_this_lib_crate_generic_function(some_vec); + LL| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); + LL| 1|} + LL| | + LL| |// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results, + LL| |// for example: + LL| |// + LL| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> + LL| |// + LL| |// These notices appear when `llvm-cov` shows instantiations. This may be a + LL| |// default option, but it can be suppressed with: + LL| |// + LL| |// ```shell + LL| |// $ `llvm-cov show --show-instantiations=0 ...` + LL| |// ``` + LL| |// + LL| |// The notice is triggered because the function is unused by the library itself, + LL| |// and when the library is compiled, a synthetic function is generated, so + LL| |// unused function coverage can be reported. Coverage can be skipped for unused + LL| |// generic functions with: + LL| |// + LL| |// ```shell + LL| |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` + LL| |// ``` + LL| |// + LL| |// Even though this function is used by `uses_crate.rs` (and + LL| |// counted), with substitutions for `T`, those instantiations are only generated + LL| |// when the generic function is actually used (from the binary, not from this + LL| |// library crate). So the test result shows coverage for all instantiated + LL| |// versions and their generic type substitutions, plus the `Unexecuted + LL| |// instantiation` message for the non-substituted version. This is valid, but + LL| |// unfortunately a little confusing. + LL| |// + LL| |// The library crate has its own coverage map, and the only way to show unused + LL| |// coverage of a generic function is to include the generic function in the + LL| |// coverage map, marked as an "unused function". If the library were used by + LL| |// another binary that never used this generic function, then it would be valid + LL| |// to show the unused generic, with unknown substitution (`_`). + LL| |// + LL| |// The alternative is to exclude all generics from being included in the "unused + LL| |// functions" list, which would then omit coverage results for + LL| |// `unused_generic_function()`, below. $DIR/uses_crate.rs: - 1| |// This test was failing on Linux for a while due to #110393 somehow making - 2| |// the unused functions not instrumented, but it seems to be fine now. - 3| | - 4| |// Validates coverage now works with optimizations - 5| |// compile-flags: -C opt-level=3 - 6| | - 7| |#![allow(unused_assignments, unused_variables)] - 8| | - 9| |// aux-build:used_crate.rs - 10| |extern crate used_crate; - 11| | - 12| 1|fn main() { - 13| 1| used_crate::used_function(); - 14| 1| let some_vec = vec![1, 2, 3, 4]; - 15| 1| used_crate::used_only_from_bin_crate_generic_function(&some_vec); - 16| 1| used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); - 17| 1| used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); - 18| 1| used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); - 19| 1|} + LL| |// This test was failing on Linux for a while due to #110393 somehow making + LL| |// the unused functions not instrumented, but it seems to be fine now. + LL| | + LL| |// Validates coverage now works with optimizations + LL| |// compile-flags: -C opt-level=3 + LL| | + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| |// aux-build:used_crate.rs + LL| |extern crate used_crate; + LL| | + LL| 1|fn main() { + LL| 1| used_crate::used_function(); + LL| 1| let some_vec = vec![1, 2, 3, 4]; + LL| 1| used_crate::used_only_from_bin_crate_generic_function(&some_vec); + LL| 1| used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + LL| 1| used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + LL| 1| used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); + LL| 1|} diff --git a/tests/run-coverage/uses_inline_crate.coverage b/tests/run-coverage/uses_inline_crate.coverage index 64308c796d6f..48493e2079ca 100644 --- a/tests/run-coverage/uses_inline_crate.coverage +++ b/tests/run-coverage/uses_inline_crate.coverage @@ -1,164 +1,164 @@ $DIR/auxiliary/used_inline_crate.rs: - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |// compile-flags: -C opt-level=3 - 4| |// ^^ validates coverage now works with optimizations - 5| |use std::fmt::Debug; - 6| | - 7| 1|pub fn used_function() { - 8| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 9| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 10| 1| // dependent conditions. - 11| 1| let is_true = std::env::args().len() == 1; - 12| 1| let mut countdown = 0; - 13| 1| if is_true { - 14| 1| countdown = 10; - 15| 1| } + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| |// compile-flags: -C opt-level=3 + LL| |// ^^ validates coverage now works with optimizations + LL| |use std::fmt::Debug; + LL| | + LL| 1|pub fn used_function() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| let mut countdown = 0; + LL| 1| if is_true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 16| 1| use_this_lib_crate(); - 17| 1|} - 18| | - 19| |#[inline(always)] - 20| 1|pub fn used_inline_function() { - 21| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 22| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 23| 1| // dependent conditions. - 24| 1| let is_true = std::env::args().len() == 1; - 25| 1| let mut countdown = 0; - 26| 1| if is_true { - 27| 1| countdown = 10; - 28| 1| } + LL| 1| use_this_lib_crate(); + LL| 1|} + LL| | + LL| |#[inline(always)] + LL| 1|pub fn used_inline_function() { + LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| 1| // dependent conditions. + LL| 1| let is_true = std::env::args().len() == 1; + LL| 1| let mut countdown = 0; + LL| 1| if is_true { + LL| 1| countdown = 10; + LL| 1| } ^0 - 29| 1| use_this_lib_crate(); - 30| 1|} - 31| | - 32| | - 33| | - 34| | - 35| | - 36| | - 37| | - 38| |#[inline(always)] - 39| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - 41| 2|} + LL| 1| use_this_lib_crate(); + LL| 1|} + LL| | + LL| | + LL| | + LL| | + LL| | + LL| | + LL| | + LL| |#[inline(always)] + LL| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { + LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + LL| 2|} ------------------ | Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_> ------------------ | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: - | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 41| 1|} + | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: - | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 41| 1|} + | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ - 42| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) - 43| | - 44| |#[inline(always)] - 45| 4|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - 46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - 47| 4|} + LL| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) + LL| | + LL| |#[inline(always)] + LL| 4|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + LL| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + LL| 4|} ------------------ | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: - | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 47| 2|} + | LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 2|} ------------------ | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: - | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 47| 2|} + | LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 2|} ------------------ - 48| | - 49| |#[inline(always)] - 50| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 51| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 52| 3|} + LL| | + LL| |#[inline(always)] + LL| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 3|} ------------------ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 50| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 51| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 52| 2|} + | LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 2|} ------------------ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::>: - | 50| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 51| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 52| 1|} + | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ - 53| | - 54| |#[inline(always)] - 55| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 56| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 57| 3|} + LL| | + LL| |#[inline(always)] + LL| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 3|} ------------------ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 55| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 56| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 57| 1|} + | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1|} ------------------ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 55| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 56| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 57| 2|} + | LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 2|} ------------------ - 58| | - 59| |#[inline(always)] - 60| 0|pub fn unused_generic_function(arg: T) { - 61| 0| println!("unused_generic_function with {:?}", arg); - 62| 0|} - 63| | - 64| |#[inline(always)] - 65| 0|pub fn unused_function() { - 66| 0| let is_true = std::env::args().len() == 1; - 67| 0| let mut countdown = 2; - 68| 0| if !is_true { - 69| 0| countdown = 20; - 70| 0| } - 71| 0|} - 72| | - 73| |#[inline(always)] - 74| 0|fn unused_private_function() { - 75| 0| let is_true = std::env::args().len() == 1; - 76| 0| let mut countdown = 2; - 77| 0| if !is_true { - 78| 0| countdown = 20; - 79| 0| } - 80| 0|} - 81| | - 82| 2|fn use_this_lib_crate() { - 83| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - 84| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - 85| 2| "used from library used_crate.rs", - 86| 2| ); - 87| 2| let some_vec = vec![5, 6, 7, 8]; - 88| 2| used_only_from_this_lib_crate_generic_function(some_vec); - 89| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); - 90| 2|} + LL| | + LL| |#[inline(always)] + LL| 0|pub fn unused_generic_function(arg: T) { + LL| 0| println!("unused_generic_function with {:?}", arg); + LL| 0|} + LL| | + LL| |#[inline(always)] + LL| 0|pub fn unused_function() { + LL| 0| let is_true = std::env::args().len() == 1; + LL| 0| let mut countdown = 2; + LL| 0| if !is_true { + LL| 0| countdown = 20; + LL| 0| } + LL| 0|} + LL| | + LL| |#[inline(always)] + LL| 0|fn unused_private_function() { + LL| 0| let is_true = std::env::args().len() == 1; + LL| 0| let mut countdown = 2; + LL| 0| if !is_true { + LL| 0| countdown = 20; + LL| 0| } + LL| 0|} + LL| | + LL| 2|fn use_this_lib_crate() { + LL| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + LL| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + LL| 2| "used from library used_crate.rs", + LL| 2| ); + LL| 2| let some_vec = vec![5, 6, 7, 8]; + LL| 2| used_only_from_this_lib_crate_generic_function(some_vec); + LL| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); + LL| 2|} $DIR/uses_inline_crate.rs: - 1| |// This test was failing on Linux for a while due to #110393 somehow making - 2| |// the unused functions not instrumented, but it seems to be fine now. - 3| | - 4| |// Validates coverage now works with optimizations - 5| |// compile-flags: -C opt-level=3 - 6| | - 7| |#![allow(unused_assignments, unused_variables)] - 8| | - 9| |// aux-build:used_inline_crate.rs - 10| |extern crate used_inline_crate; - 11| | - 12| 1|fn main() { - 13| 1| used_inline_crate::used_function(); - 14| 1| used_inline_crate::used_inline_function(); - 15| 1| let some_vec = vec![1, 2, 3, 4]; - 16| 1| used_inline_crate::used_only_from_bin_crate_generic_function(&some_vec); - 17| 1| used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); - 18| 1| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); - 19| 1| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - 20| 1| "interesting?", - 21| 1| ); - 22| 1|} + LL| |// This test was failing on Linux for a while due to #110393 somehow making + LL| |// the unused functions not instrumented, but it seems to be fine now. + LL| | + LL| |// Validates coverage now works with optimizations + LL| |// compile-flags: -C opt-level=3 + LL| | + LL| |#![allow(unused_assignments, unused_variables)] + LL| | + LL| |// aux-build:used_inline_crate.rs + LL| |extern crate used_inline_crate; + LL| | + LL| 1|fn main() { + LL| 1| used_inline_crate::used_function(); + LL| 1| used_inline_crate::used_inline_function(); + LL| 1| let some_vec = vec![1, 2, 3, 4]; + LL| 1| used_inline_crate::used_only_from_bin_crate_generic_function(&some_vec); + LL| 1| used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + LL| 1| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + LL| 1| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + LL| 1| "interesting?", + LL| 1| ); + LL| 1|} diff --git a/tests/run-coverage/while.coverage b/tests/run-coverage/while.coverage index efa7d083f0c6..c9d497651c9f 100644 --- a/tests/run-coverage/while.coverage +++ b/tests/run-coverage/while.coverage @@ -1,6 +1,6 @@ - 1| 1|fn main() { - 2| 1| let num = 9; - 3| 1| while num >= 10 { - 4| 0| } - 5| 1|} + LL| 1|fn main() { + LL| 1| let num = 9; + LL| 1| while num >= 10 { + LL| 0| } + LL| 1|} diff --git a/tests/run-coverage/while_early_ret.coverage b/tests/run-coverage/while_early_ret.coverage index 2ce94e0131d1..97808447ab74 100644 --- a/tests/run-coverage/while_early_ret.coverage +++ b/tests/run-coverage/while_early_ret.coverage @@ -1,43 +1,43 @@ - 1| |#![allow(unused_assignments)] - 2| |// failure-status: 1 - 3| | - 4| 1|fn main() -> Result<(),u8> { - 5| 1| let mut countdown = 10; - 6| | while - 7| 7| countdown - 8| 7| > - 9| 7| 0 - 10| | { - 11| | if - 12| 7| countdown - 13| 7| < - 14| 7| 5 - 15| | { - 16| | return - 17| | if - 18| 1| countdown - 19| 1| > - 20| 1| 8 - 21| | { - 22| 0| Ok(()) - 23| | } - 24| | else - 25| | { - 26| 1| Err(1) - 27| | } - 28| | ; - 29| 6| } - 30| 6| countdown - 31| 6| -= - 32| 6| 1 - 33| | ; - 34| | } - 35| 0| Ok(()) - 36| 1|} - 37| | - 38| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and - 39| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux - 40| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program - 41| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical - 42| |// to the coverage test for early returns, but this is a limitation that should be fixed. + LL| |#![allow(unused_assignments)] + LL| |// failure-status: 1 + LL| | + LL| 1|fn main() -> Result<(),u8> { + LL| 1| let mut countdown = 10; + LL| | while + LL| 7| countdown + LL| 7| > + LL| 7| 0 + LL| | { + LL| | if + LL| 7| countdown + LL| 7| < + LL| 7| 5 + LL| | { + LL| | return + LL| | if + LL| 1| countdown + LL| 1| > + LL| 1| 8 + LL| | { + LL| 0| Ok(()) + LL| | } + LL| | else + LL| | { + LL| 1| Err(1) + LL| | } + LL| | ; + LL| 6| } + LL| 6| countdown + LL| 6| -= + LL| 6| 1 + LL| | ; + LL| | } + LL| 0| Ok(()) + LL| 1|} + LL| | + LL| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and + LL| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux + LL| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program + LL| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical + LL| |// to the coverage test for early returns, but this is a limitation that should be fixed. diff --git a/tests/run-coverage/yield.coverage b/tests/run-coverage/yield.coverage index 6e2f23ee77b8..383dd9915004 100644 --- a/tests/run-coverage/yield.coverage +++ b/tests/run-coverage/yield.coverage @@ -1,38 +1,38 @@ - 1| |#![feature(generators, generator_trait)] - 2| |#![allow(unused_assignments)] - 3| | - 4| |use std::ops::{Generator, GeneratorState}; - 5| |use std::pin::Pin; - 6| | - 7| 1|fn main() { - 8| 1| let mut generator = || { - 9| 1| yield 1; - 10| 1| return "foo" - 11| 1| }; - 12| | - 13| 1| match Pin::new(&mut generator).resume(()) { - 14| 1| GeneratorState::Yielded(1) => {} - 15| 0| _ => panic!("unexpected value from resume"), - 16| | } - 17| 1| match Pin::new(&mut generator).resume(()) { - 18| 1| GeneratorState::Complete("foo") => {} - 19| 0| _ => panic!("unexpected value from resume"), - 20| | } - 21| | - 22| 1| let mut generator = || { - 23| 1| yield 1; - 24| 1| yield 2; - 25| 0| yield 3; - 26| 0| return "foo" - 27| 0| }; - 28| | - 29| 1| match Pin::new(&mut generator).resume(()) { - 30| 1| GeneratorState::Yielded(1) => {} - 31| 0| _ => panic!("unexpected value from resume"), - 32| | } - 33| 1| match Pin::new(&mut generator).resume(()) { - 34| 1| GeneratorState::Yielded(2) => {} - 35| 0| _ => panic!("unexpected value from resume"), - 36| | } - 37| 1|} + LL| |#![feature(generators, generator_trait)] + LL| |#![allow(unused_assignments)] + LL| | + LL| |use std::ops::{Generator, GeneratorState}; + LL| |use std::pin::Pin; + LL| | + LL| 1|fn main() { + LL| 1| let mut generator = || { + LL| 1| yield 1; + LL| 1| return "foo" + LL| 1| }; + LL| | + LL| 1| match Pin::new(&mut generator).resume(()) { + LL| 1| GeneratorState::Yielded(1) => {} + LL| 0| _ => panic!("unexpected value from resume"), + LL| | } + LL| 1| match Pin::new(&mut generator).resume(()) { + LL| 1| GeneratorState::Complete("foo") => {} + LL| 0| _ => panic!("unexpected value from resume"), + LL| | } + LL| | + LL| 1| let mut generator = || { + LL| 1| yield 1; + LL| 1| yield 2; + LL| 0| yield 3; + LL| 0| return "foo" + LL| 0| }; + LL| | + LL| 1| match Pin::new(&mut generator).resume(()) { + LL| 1| GeneratorState::Yielded(1) => {} + LL| 0| _ => panic!("unexpected value from resume"), + LL| | } + LL| 1| match Pin::new(&mut generator).resume(()) { + LL| 1| GeneratorState::Yielded(2) => {} + LL| 0| _ => panic!("unexpected value from resume"), + LL| | } + LL| 1|} From 9a3dfd7e92ef3ecf51e42500a7240947fe0949e5 Mon Sep 17 00:00:00 2001 From: Folyd Date: Thu, 17 Aug 2023 12:24:28 +0800 Subject: [PATCH 076/169] Remove Folyd from librustdoc static files --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index b2ea206a8a28..2c71b650f68c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -386,7 +386,6 @@ cc = ["@camelid"] message = "Some changes occurred in HTML/CSS/JS." cc = [ "@GuillaumeGomez", - "@Folyd", "@jsha", ] From 6395dc2cde4421a4d74a8e01dd253957b3f96844 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 17 Aug 2023 08:52:37 -0300 Subject: [PATCH 077/169] [RFC-3086] Restrict the parsing of `count` --- compiler/rustc_expand/src/mbe/metavar_expr.rs | 12 +++++++++++- .../rfc-3086-metavar-expr/issue-111904.rs | 14 ++++++++++++++ .../rfc-3086-metavar-expr/issue-111904.stderr | 19 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs create mode 100644 tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index b6382dcb8944..7c37aadc67ae 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -93,7 +93,17 @@ fn parse_count<'sess>( span: Span, ) -> PResult<'sess, MetaVarExpr> { let ident = parse_ident(iter, sess, span)?; - let depth = if try_eat_comma(iter) { Some(parse_depth(iter, sess, span)?) } else { None }; + let depth = if try_eat_comma(iter) { + if iter.look_ahead(0).is_none() { + return Err(sess.span_diagnostic.struct_span_err( + span, + "`count` followed by a comma must have an associated index indicating its depth", + )); + } + Some(parse_depth(iter, sess, span)?) + } else { + None + }; Ok(MetaVarExpr::Count(ident, depth)) } diff --git a/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs new file mode 100644 index 000000000000..9cc572c23a1a --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs @@ -0,0 +1,14 @@ +#![feature(macro_metavar_expr)] + +macro_rules! foo { + ( $( $($t:ident),* );* ) => { ${count(t,)} } + //~^ ERROR `count` followed by a comma must have an associated + //~| ERROR expected expression, found `$` +} + +fn test() { + foo!(a, a; b, b); +} + +fn main() { +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr new file mode 100644 index 000000000000..e9317a5c3477 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr @@ -0,0 +1,19 @@ +error: `count` followed by a comma must have an associated index indicating its depth + --> $DIR/issue-111904.rs:4:37 + | +LL | ( $( $($t:ident),* );* ) => { ${count(t,)} } + | ^^^^^ + +error: expected expression, found `$` + --> $DIR/issue-111904.rs:4:35 + | +LL | ( $( $($t:ident),* );* ) => { ${count(t,)} } + | ^ expected expression +... +LL | foo!(a, a; b, b); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + From 1c73248b67167dd18c9bd01bf541f5ea35be66d8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 17 Aug 2023 14:09:32 +0200 Subject: [PATCH 078/169] Revert PR #114052 to fix invalid suggestion --- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/errors.rs | 29 ++++++++------- .../src/fn_ctxt/suggestions.rs | 11 +----- .../dont-suggest-cyclic-constraint.fixed | 13 ------- .../dont-suggest-cyclic-constraint.rs | 2 - .../dont-suggest-cyclic-constraint.stderr | 6 +-- tests/ui/suggestions/copied-and-cloned.fixed | 18 +++++++-- tests/ui/suggestions/copied-and-cloned.rs | 16 +++++++- tests/ui/suggestions/copied-and-cloned.stderr | 37 +++++++++++++------ 9 files changed, 73 insertions(+), 61 deletions(-) delete mode 100644 tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 5b06088c3481..6aeabc1bebb2 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -53,7 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_no_capture_closure(err, expected, expr_ty) || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty) || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) - || self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected, expected_ty_expr) + || self.suggest_copied_cloned_or_as_ref(err, expr, expr_ty, expected) || self.suggest_clone_for_ref(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 36096aa35d4c..054d23c71d4a 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -253,7 +253,7 @@ impl HelpUseLatestEdition { } #[derive(Subdiagnostic)] -pub enum OptionResultRefMismatch<'tcx> { +pub enum OptionResultRefMismatch { #[suggestion( hir_typeck_option_result_copied, code = ".copied()", @@ -276,19 +276,20 @@ pub enum OptionResultRefMismatch<'tcx> { span: Span, def_path: String, }, - #[suggestion( - hir_typeck_option_result_asref, - code = ".as_ref()", - style = "verbose", - applicability = "machine-applicable" - )] - AsRef { - #[primary_span] - span: Span, - def_path: String, - expected_ty: Ty<'tcx>, - expr_ty: Ty<'tcx>, - }, + // FIXME: #114050 + // #[suggestion( + // hir_typeck_option_result_asref, + // code = ".as_ref()", + // style = "verbose", + // applicability = "machine-applicable" + // )] + // AsRef { + // #[primary_span] + // span: Span, + // def_path: String, + // expected_ty: Ty<'tcx>, + // expr_ty: Ty<'tcx>, + // }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 48358e338dae..d2a53ee8b5e1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1097,7 +1097,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, - expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let ty::Adt(adt_def, args) = expr_ty.kind() else { return false; @@ -1115,7 +1114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let expr_inner_ty = args.type_at(0); let expected_inner_ty = expected_args.type_at(0); - if let &ty::Ref(_, ty, mutability) = expr_inner_ty.kind() + if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind() && self.can_eq(self.param_env, ty, expected_inner_ty) { let def_path = self.tcx.def_path_str(adt_def.did()); @@ -1124,14 +1123,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { errors::OptionResultRefMismatch::Copied { span, def_path } - } else if let Some(expected_ty_expr) = expected_ty_expr - // FIXME: suggest changes to both expressions to convert both to - // Option/Result<&T> - && mutability.is_not() - { - errors::OptionResultRefMismatch::AsRef { - span: expected_ty_expr.span.shrink_to_hi(), expected_ty, expr_ty, def_path - } } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( self, diff --git a/tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed b/tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed deleted file mode 100644 index ec4165cc71e2..000000000000 --- a/tests/ui/associated-types/dont-suggest-cyclic-constraint.fixed +++ /dev/null @@ -1,13 +0,0 @@ -// run-rustfix - -use std::fmt::Debug; - -pub fn foo(mut iter: I, value: &I::Item) -where - I::Item: Eq + Debug, -{ - debug_assert_eq!(iter.next().as_ref(), Some(value)); - //~^ ERROR mismatched types -} - -fn main() {} diff --git a/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs b/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs index 0b4df08783d6..0848b4c559b3 100644 --- a/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs +++ b/tests/ui/associated-types/dont-suggest-cyclic-constraint.rs @@ -1,5 +1,3 @@ -// run-rustfix - use std::fmt::Debug; pub fn foo(mut iter: I, value: &I::Item) diff --git a/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr b/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr index 65d18761b187..3ecac9c83e57 100644 --- a/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr +++ b/tests/ui/associated-types/dont-suggest-cyclic-constraint.stderr @@ -1,15 +1,11 @@ error[E0308]: mismatched types - --> $DIR/dont-suggest-cyclic-constraint.rs:9:35 + --> $DIR/dont-suggest-cyclic-constraint.rs:7:35 | LL | debug_assert_eq!(iter.next(), Some(value)); | ^^^^^^^^^^^ expected `Option<::Item>`, found `Option<&::Item>` | = note: expected enum `Option<::Item>` found enum `Option<&::Item>` -help: use `Option::as_ref` to convert `Option<::Item>` to `Option<&::Item>` - | -LL | debug_assert_eq!(iter.next().as_ref(), Some(value)); - | +++++++++ error: aborting due to previous error diff --git a/tests/ui/suggestions/copied-and-cloned.fixed b/tests/ui/suggestions/copied-and-cloned.fixed index 77159d5075af..4cecf9e26f9e 100644 --- a/tests/ui/suggestions/copied-and-cloned.fixed +++ b/tests/ui/suggestions/copied-and-cloned.fixed @@ -2,6 +2,16 @@ fn expect(_: T) {} +struct Issue114925 { + x: Option, +} + +fn issue_114925(lol: &mut Issue114925, x: Option<&String>) { + lol.x = x.clone().cloned(); + //~^ ERROR mismatched types + //~| HELP use `Option::cloned` to clone the value inside the `Option` +} + fn main() { let x = Some(&()); expect::>(x.copied()); @@ -24,10 +34,10 @@ fn main() { let s = String::new(); let x = Some(s.clone()); let y = Some(&s); - println!("{}", x.as_ref() == y); + println!("{}", x == y.cloned()); //~^ ERROR mismatched types - //~| HELP use `Option::as_ref` to convert `Option` to `Option<&String>` - + //~| HELP use `Option::cloned` to clone the value inside the `Option` + //FIXME(#114050) ~| HELP use `Option::as_ref` to convert `Option` to `Option<&String>` let mut s = (); let x = Some(s); @@ -42,4 +52,6 @@ fn main() { println!("{}", x == y.cloned()); //~^ ERROR mismatched types //~| HELP use `Option::cloned` to clone the value inside the `Option` + + issue_114925(&mut Issue114925 { x: None }, None); } diff --git a/tests/ui/suggestions/copied-and-cloned.rs b/tests/ui/suggestions/copied-and-cloned.rs index c506494ee141..a79928c50d56 100644 --- a/tests/ui/suggestions/copied-and-cloned.rs +++ b/tests/ui/suggestions/copied-and-cloned.rs @@ -2,6 +2,16 @@ fn expect(_: T) {} +struct Issue114925 { + x: Option, +} + +fn issue_114925(lol: &mut Issue114925, x: Option<&String>) { + lol.x = x.clone(); + //~^ ERROR mismatched types + //~| HELP use `Option::cloned` to clone the value inside the `Option` +} + fn main() { let x = Some(&()); expect::>(x); @@ -26,8 +36,8 @@ fn main() { let y = Some(&s); println!("{}", x == y); //~^ ERROR mismatched types - //~| HELP use `Option::as_ref` to convert `Option` to `Option<&String>` - + //~| HELP use `Option::cloned` to clone the value inside the `Option` + //FIXME(#114050) ~| HELP use `Option::as_ref` to convert `Option` to `Option<&String>` let mut s = (); let x = Some(s); @@ -42,4 +52,6 @@ fn main() { println!("{}", x == y); //~^ ERROR mismatched types //~| HELP use `Option::cloned` to clone the value inside the `Option` + + issue_114925(&mut Issue114925 { x: None }, None); } diff --git a/tests/ui/suggestions/copied-and-cloned.stderr b/tests/ui/suggestions/copied-and-cloned.stderr index f8712d0a39e1..87b0624d48be 100644 --- a/tests/ui/suggestions/copied-and-cloned.stderr +++ b/tests/ui/suggestions/copied-and-cloned.stderr @@ -1,5 +1,20 @@ error[E0308]: mismatched types - --> $DIR/copied-and-cloned.rs:7:26 + --> $DIR/copied-and-cloned.rs:10:13 + | +LL | lol.x = x.clone(); + | ----- ^^^^^^^^^ expected `Option`, found `Option<&String>` + | | + | expected due to the type of this binding + | + = note: expected enum `Option` + found enum `Option<&String>` +help: use `Option::cloned` to clone the value inside the `Option` + | +LL | lol.x = x.clone().cloned(); + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/copied-and-cloned.rs:17:26 | LL | expect::>(x); | -------------------- ^ expected `Option<()>`, found `Option<&()>` @@ -19,7 +34,7 @@ LL | expect::>(x.copied()); | +++++++++ error[E0308]: mismatched types - --> $DIR/copied-and-cloned.rs:11:30 + --> $DIR/copied-and-cloned.rs:21:30 | LL | expect::>(x); | ------------------------ ^ expected `Result<(), ()>`, found `Result<&(), _>` @@ -39,7 +54,7 @@ LL | expect::>(x.copied()); | +++++++++ error[E0308]: mismatched types - --> $DIR/copied-and-cloned.rs:16:30 + --> $DIR/copied-and-cloned.rs:26:30 | LL | expect::>(x); | ------------------------ ^ expected `Option`, found `Option<&String>` @@ -59,7 +74,7 @@ LL | expect::>(x.cloned()); | +++++++++ error[E0308]: mismatched types - --> $DIR/copied-and-cloned.rs:20:34 + --> $DIR/copied-and-cloned.rs:30:34 | LL | expect::>(x); | ---------------------------- ^ expected `Result`, found `Result<&String, _>` @@ -79,20 +94,20 @@ LL | expect::>(x.cloned()); | +++++++++ error[E0308]: mismatched types - --> $DIR/copied-and-cloned.rs:27:25 + --> $DIR/copied-and-cloned.rs:37:25 | LL | println!("{}", x == y); | ^ expected `Option`, found `Option<&String>` | = note: expected enum `Option` found enum `Option<&String>` -help: use `Option::as_ref` to convert `Option` to `Option<&String>` +help: use `Option::cloned` to clone the value inside the `Option` | -LL | println!("{}", x.as_ref() == y); - | +++++++++ +LL | println!("{}", x == y.cloned()); + | +++++++++ error[E0308]: mismatched types - --> $DIR/copied-and-cloned.rs:35:25 + --> $DIR/copied-and-cloned.rs:45:25 | LL | println!("{}", x == y); | ^ expected `Option<()>`, found `Option<&mut ()>` @@ -105,7 +120,7 @@ LL | println!("{}", x == y.copied()); | +++++++++ error[E0308]: mismatched types - --> $DIR/copied-and-cloned.rs:42:25 + --> $DIR/copied-and-cloned.rs:52:25 | LL | println!("{}", x == y); | ^ expected `Option`, found `Option<&mut String>` @@ -117,6 +132,6 @@ help: use `Option::cloned` to clone the value inside the `Option` LL | println!("{}", x == y.cloned()); | +++++++++ -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0308`. From 09d05c04da516d4f54ccf41e22b544bc8c425373 Mon Sep 17 00:00:00 2001 From: bors Date: Thu, 17 Aug 2023 14:41:46 +0000 Subject: [PATCH 079/169] Auto merge of #11070 - y21:issue11065, r=flip1995 [`useless_conversion`]: only lint on paths to fn items and fix FP in macro Fixes #11065 (which is actually two issues: an ICE and a false positive) It now makes sure that the function call path points to a function-like item (and not e.g. a `const` like in the linked issue), so that calling `TyCtxt::fn_sig` later in the lint does not ICE (fixes https://github.com/rust-lang/rust-clippy/issues/11065#issuecomment-1616836099). It *also* makes sure that the expression is not part of a macro call (fixes https://github.com/rust-lang/rust-clippy/issues/11065#issuecomment-1616919639). ~~I'm not sure if there's a better way to check this other than to walk the parent expr chain and see if any of them are expansions.~~ (edit: it doesn't do this anymore) changelog: [`useless_conversion`]: fix ICE when call receiver is a non-fn item changelog: [`useless_conversion`]: don't lint if argument is a macro argument (fixes a FP) r? `@llogiq` (reviewed #10814, which introduced these issues) --- .../clippy_lints/src/useless_conversion.rs | 18 ++++++++++++++--- .../clippy/tests/ui/crashes/ice-11065.rs | 19 ++++++++++++++++++ .../clippy/tests/ui/useless_conversion.fixed | 14 +++++++++++++ .../clippy/tests/ui/useless_conversion.rs | 14 +++++++++++++ .../clippy/tests/ui/useless_conversion.stderr | 20 +++++++++---------- 5 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 src/tools/clippy/tests/ui/crashes/ice-11065.rs diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index bd4dc07a42bf..5ac4f0aa46c1 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -5,6 +5,7 @@ use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -39,6 +40,7 @@ declare_clippy_lint! { #[derive(Default)] pub struct UselessConversion { try_desugar_arm: Vec, + expn_depth: u32, } impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]); @@ -105,6 +107,7 @@ fn into_iter_deep_call<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) - impl<'tcx> LateLintPass<'tcx> for UselessConversion { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if e.span.from_expansion() { + self.expn_depth += 1; return; } @@ -150,9 +153,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { { if let Some(parent) = get_parent_expr(cx, e) { let parent_fn = match parent.kind { - ExprKind::Call(recv, args) if let ExprKind::Path(ref qpath) = recv.kind => { - cx.qpath_res(qpath, recv.hir_id).opt_def_id() - .map(|did| (did, args, MethodOrFunction::Function)) + ExprKind::Call(recv, args) + if let ExprKind::Path(ref qpath) = recv.kind + && let Some(did) = cx.qpath_res(qpath, recv.hir_id).opt_def_id() + // make sure that the path indeed points to a fn-like item, so that + // `fn_sig` does not ICE. (see #11065) + && cx.tcx.opt_def_kind(did).is_some_and(DefKind::is_fn_like) => + { + Some((did, args, MethodOrFunction::Function)) } ExprKind::MethodCall(.., args, _) => { cx.typeck_results().type_dependent_def_id(parent.hir_id) @@ -168,6 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { && let Some(&into_iter_param) = sig.inputs().get(kind.param_pos(arg_pos)) && let ty::Param(param) = into_iter_param.kind() && let Some(span) = into_iter_bound(cx, parent_fn_did, into_iter_did, param.index) + && self.expn_depth == 0 { // Get the "innermost" `.into_iter()` call, e.g. given this expression: // `foo.into_iter().into_iter()` @@ -303,5 +312,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if Some(&e.hir_id) == self.try_desugar_arm.last() { self.try_desugar_arm.pop(); } + if e.span.from_expansion() { + self.expn_depth -= 1; + } } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-11065.rs b/src/tools/clippy/tests/ui/crashes/ice-11065.rs new file mode 100644 index 000000000000..f5cf6b1cd77a --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-11065.rs @@ -0,0 +1,19 @@ +#![warn(clippy::useless_conversion)] + +use std::iter::FromIterator; +use std::option::IntoIter as OptionIter; + +fn eq(a: T, b: T) -> bool { + a == b +} + +macro_rules! tests { + ($($expr:expr, $ty:ty, ($($test:expr),*);)+) => (pub fn main() {$({ + const C: $ty = $expr; + assert!(eq(C($($test),*), $expr($($test),*))); + })+}) +} + +tests! { + FromIterator::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); +} diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 5d2c5b11658e..53d8a5a9ff18 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -155,6 +155,20 @@ fn main() { let _ = vec![s4, s4, s4].into_iter(); } +#[allow(dead_code)] +fn issue11065_fp() { + use std::option::IntoIter; + fn takes_into_iter(_: impl IntoIterator) {} + + macro_rules! x { + ($e:expr) => { + takes_into_iter($e); + let _: IntoIter = $e; // removing `.into_iter()` leads to a type error here + }; + } + x!(Some(5).into_iter()); +} + #[allow(dead_code)] fn explicit_into_iter_fn_arg() { fn a(_: T) {} diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 03a3e3f95ba4..51ba49873396 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -155,6 +155,20 @@ fn main() { let _ = vec![s4, s4, s4].into_iter().into_iter(); } +#[allow(dead_code)] +fn issue11065_fp() { + use std::option::IntoIter; + fn takes_into_iter(_: impl IntoIterator) {} + + macro_rules! x { + ($e:expr) => { + takes_into_iter($e); + let _: IntoIter = $e; // removing `.into_iter()` leads to a type error here + }; + } + x!(Some(5).into_iter()); +} + #[allow(dead_code)] fn explicit_into_iter_fn_arg() { fn a(_: T) {} diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index 4957f73a469a..6f7dc01d2cd2 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -119,61 +119,61 @@ LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> $DIR/useless_conversion.rs:171:7 + --> $DIR/useless_conversion.rs:185:7 | LL | b(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> $DIR/useless_conversion.rs:161:13 + --> $DIR/useless_conversion.rs:175:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> $DIR/useless_conversion.rs:172:7 + --> $DIR/useless_conversion.rs:186:7 | LL | c(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> $DIR/useless_conversion.rs:162:18 + --> $DIR/useless_conversion.rs:176:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> $DIR/useless_conversion.rs:173:7 + --> $DIR/useless_conversion.rs:187:7 | LL | d(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> $DIR/useless_conversion.rs:165:12 + --> $DIR/useless_conversion.rs:179:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> $DIR/useless_conversion.rs:176:7 + --> $DIR/useless_conversion.rs:190:7 | LL | b(vec![1, 2].into_iter().into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> $DIR/useless_conversion.rs:161:13 + --> $DIR/useless_conversion.rs:175:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> $DIR/useless_conversion.rs:177:7 + --> $DIR/useless_conversion.rs:191:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> $DIR/useless_conversion.rs:161:13 + --> $DIR/useless_conversion.rs:175:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ From ff89efeda2c905575665de2bd87d546d208b8195 Mon Sep 17 00:00:00 2001 From: bors Date: Thu, 17 Aug 2023 15:55:23 +0000 Subject: [PATCH 080/169] Auto merge of #11314 - GuillaumeGomez:needless_ref_mut_async_block, r=Centri3 Correctly handle async blocks for NEEDLESS_PASS_BY_REF_MUT Fixes https://github.com/rust-lang/rust-clippy/issues/11299. The problem was that the `async block`s are popping a closure which we didn't go into, making it miss the mutable access to the variables. cc `@Centri3` changelog: none --- .../src/needless_pass_by_ref_mut.rs | 103 ++++++++++++++---- .../tests/ui/needless_pass_by_ref_mut.rs | 35 ++++++ .../tests/ui/needless_pass_by_ref_mut.stderr | 14 ++- 3 files changed, 129 insertions(+), 23 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index c634de960d13..7b00eabf97b4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -5,14 +5,16 @@ use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor}; -use rustc_hir::{Body, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath}; +use rustc_hir::{ + Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath, +}; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::associated_body; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::{self, Ty, UpvarId, UpvarPath}; +use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; @@ -147,22 +149,36 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // Collect variables mutably used and spans which will need dereferencings from the // function body. let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = { - let mut ctx = MutablyUsedVariablesCtxt::default(); + let mut ctx = MutablyUsedVariablesCtxt { + mutably_used_vars: HirIdSet::default(), + prev_bind: None, + prev_move_to_closure: HirIdSet::default(), + aliases: HirIdMap::default(), + async_closures: FxHashSet::default(), + tcx: cx.tcx, + }; let infcx = cx.tcx.infer_ctxt().build(); euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); if is_async { - let closures = ctx.async_closures.clone(); - let hir = cx.tcx.hir(); - for closure in closures { - ctx.prev_bind = None; - ctx.prev_move_to_closure.clear(); - if let Some(body) = hir - .find_by_def_id(closure) - .and_then(associated_body) - .map(|(_, body_id)| hir.body(body_id)) - { - euv::ExprUseVisitor::new(&mut ctx, &infcx, closure, cx.param_env, cx.typeck_results()) - .consume_body(body); + let mut checked_closures = FxHashSet::default(); + while !ctx.async_closures.is_empty() { + let closures = ctx.async_closures.clone(); + ctx.async_closures.clear(); + let hir = cx.tcx.hir(); + for closure in closures { + if !checked_closures.insert(closure) { + continue; + } + ctx.prev_bind = None; + ctx.prev_move_to_closure.clear(); + if let Some(body) = hir + .find_by_def_id(closure) + .and_then(associated_body) + .map(|(_, body_id)| hir.body(body_id)) + { + euv::ExprUseVisitor::new(&mut ctx, &infcx, closure, cx.param_env, cx.typeck_results()) + .consume_body(body); + } } } } @@ -225,16 +241,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { } } -#[derive(Default)] -struct MutablyUsedVariablesCtxt { +struct MutablyUsedVariablesCtxt<'tcx> { mutably_used_vars: HirIdSet, prev_bind: Option, prev_move_to_closure: HirIdSet, aliases: HirIdMap, async_closures: FxHashSet, + tcx: TyCtxt<'tcx>, } -impl MutablyUsedVariablesCtxt { +impl<'tcx> MutablyUsedVariablesCtxt<'tcx> { fn add_mutably_used_var(&mut self, mut used_id: HirId) { while let Some(id) = self.aliases.get(&used_id) { self.mutably_used_vars.insert(used_id); @@ -242,9 +258,27 @@ impl MutablyUsedVariablesCtxt { } self.mutably_used_vars.insert(used_id); } + + fn would_be_alias_cycle(&self, alias: HirId, mut target: HirId) -> bool { + while let Some(id) = self.aliases.get(&target) { + if *id == alias { + return true; + } + target = *id; + } + false + } + + fn add_alias(&mut self, alias: HirId, target: HirId) { + // This is to prevent alias loop. + if alias == target || self.would_be_alias_cycle(alias, target) { + return; + } + self.aliases.insert(alias, target); + } } -impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt { +impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { if let euv::Place { base: @@ -259,7 +293,7 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt { { if let Some(bind_id) = self.prev_bind.take() { if bind_id != *vid { - self.aliases.insert(bind_id, *vid); + self.add_alias(bind_id, *vid); } } else if !self.prev_move_to_closure.contains(vid) && matches!(base_ty.ref_mutability(), Some(Mutability::Mut)) @@ -289,6 +323,25 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt { { self.add_mutably_used_var(*vid); } + } else if borrow == ty::ImmBorrow { + // If there is an `async block`, it'll contain a call to a closure which we need to + // go into to ensure all "mutate" checks are found. + if let Node::Expr(Expr { + kind: + ExprKind::Call( + _, + [ + Expr { + kind: ExprKind::Closure(Closure { def_id, .. }), + .. + }, + ], + ), + .. + }) = self.tcx.hir().get(cmt.hir_id) + { + self.async_closures.insert(*def_id); + } } } @@ -296,7 +349,12 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt { self.prev_bind = None; if let euv::Place { projections, - base: euv::PlaceBase::Local(vid), + base: + euv::PlaceBase::Local(vid) + | euv::PlaceBase::Upvar(UpvarId { + var_path: UpvarPath { hir_id: vid }, + .. + }), .. } = &cmt.place { @@ -329,8 +387,9 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt { // Seems like we are inside an async function. We need to store the closure `DefId` // to go through it afterwards. self.async_closures.insert(inner); - self.aliases.insert(cmt.hir_id, *vid); + self.add_alias(cmt.hir_id, *vid); self.prev_move_to_closure.insert(*vid); + self.prev_bind = None; } } } diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs index ae7b018d0e25..ec87d4475975 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs @@ -196,6 +196,41 @@ mod foo { //~| NOTE: this is cfg-gated and may require further changes } +// Should not warn. +async fn inner_async(x: &mut i32, y: &mut u32) { + async { + *y += 1; + *x += 1; + } + .await; +} + +async fn inner_async2(x: &mut i32, y: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *x += 1; + } + .await; +} + +async fn inner_async3(x: &mut i32, y: &mut u32) { + //~^ ERROR: this argument is a mutable reference, but not used mutably + async { + *y += 1; + } + .await; +} + +// Should not warn. +async fn async_vec(b: &mut Vec) { + b.append(&mut vec![]); +} + +// Should not warn. +async fn async_vec2(b: &mut Vec) { + b.push(true); +} + fn main() { let mut u = 0; let mut v = vec![0]; diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr index 0d426ce32f9d..2e06e7252d9b 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr @@ -94,5 +94,17 @@ LL | fn cfg_warn(s: &mut u32) {} | = note: this is cfg-gated and may require further changes -error: aborting due to 15 previous errors +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:208:39 + | +LL | async fn inner_async2(x: &mut i32, y: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&u32` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:216:26 + | +LL | async fn inner_async3(x: &mut i32, y: &mut u32) { + | ^^^^^^^^ help: consider changing to: `&i32` + +error: aborting due to 17 previous errors From 3bd54c14bcf74bd5beedbfdb1300626e2a649659 Mon Sep 17 00:00:00 2001 From: ChoKyuWon Date: Tue, 18 Jul 2023 14:01:33 +0900 Subject: [PATCH 081/169] Replace the \01__gnu_mcount_nc to LLVM intrinsic for ARM Current `-Zinstrument-mcount` for ARM32 use the `\01__gnu_mcount_nc` directly for its instrumentation function. However, the LLVM does not use this mcount function directly, but it wraps it to intrinsic, `llvm.arm.gnu.eabi.mcount` and the transform pass also only handle the intrinsic. As a result, current `-Zinstrument-mcount` not work on ARM32. Refer: https://github.com/namhyung/uftrace/issues/1764 This commit replaces the mcount name from native function to the LLVM intrinsic so that the transform pass can handle it. Signed-off-by: ChoKyuWon --- compiler/rustc_codegen_llvm/src/attributes.rs | 5 ++++- compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs | 1 + .../rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs | 1 + .../rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs | 1 + .../rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs | 1 + compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs | 1 + .../rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 6 ++++++ 8 files changed, 16 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 39275272e422..57e7f86f703d 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -128,7 +128,10 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr // The function name varies on platforms. // See test/CodeGen/mcount.c in clang. - let mcount_name = cx.sess().target.mcount.as_ref(); + let mcount_name = match &cx.sess().target.llvm_mcount_intrinsic { + Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(), + None => cx.sess().target.mcount.as_ref(), + }; attrs.push(llvm::CreateAttrStringValue( cx.llcx, diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs index c0f1827ad3f8..400030ca0c60 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { features: "+strict-align,+v6".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), ..super::linux_gnu_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs index 79b8958c22ad..6228fb15a83f 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { features: "+strict-align,+v6,+vfp2,-d32".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), ..super::linux_gnu_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs index 4836f3cf7202..1d66515a72e0 100644 --- a/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armeb_unknown_linux_gnueabi.rs @@ -13,6 +13,7 @@ pub fn target() -> Target { endian: Endian::Big, max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), ..super::linux_gnu_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs index 1de63a920c80..cffebcc9581c 100644 --- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs @@ -12,6 +12,7 @@ pub fn target() -> Target { // Atomic operations provided by compiler-builtins max_atomic_width: Some(32), mcount: "\u{1}__gnu_mcount_nc".into(), + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), has_thumb_interworking: true, ..super::linux_gnu_base::opts() }, diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs index b7cfccc8b3da..4a8aa31576fa 100644 --- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs @@ -13,6 +13,7 @@ pub fn target() -> Target { features: "+v6,+vfp2,-d32".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), ..super::freebsd_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs index 903042d7e7a0..73ae212a7a6e 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs @@ -14,6 +14,7 @@ pub fn target() -> Target { features: "+v7,+thumb2,+soft-float,-neon".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), + llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), ..super::linux_gnu_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6ae07f45f4a4..2834ac33dd9e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1912,6 +1912,9 @@ pub struct TargetOptions { /// Use platform dependent mcount function pub mcount: StaticCow, + /// Use LLVM intrinsic for mcount function name + pub llvm_mcount_intrinsic: Option>, + /// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers pub llvm_abiname: StaticCow, @@ -2173,6 +2176,7 @@ impl Default for TargetOptions { override_export_symbols: None, merge_functions: MergeFunctions::Aliases, mcount: "mcount".into(), + llvm_mcount_intrinsic: None, llvm_abiname: "".into(), relax_elf_relocations: false, llvm_args: cvs![], @@ -2829,6 +2833,7 @@ impl Target { key!(override_export_symbols, opt_list); key!(merge_functions, MergeFunctions)?; key!(mcount = "target-mcount"); + key!(llvm_mcount_intrinsic, optional); key!(llvm_abiname); key!(relax_elf_relocations, bool); key!(llvm_args, list); @@ -3085,6 +3090,7 @@ impl ToJson for Target { target_option_val!(override_export_symbols); target_option_val!(merge_functions); target_option_val!(mcount, "target-mcount"); + target_option_val!(llvm_mcount_intrinsic); target_option_val!(llvm_abiname); target_option_val!(relax_elf_relocations); target_option_val!(llvm_args); From 933b618360ae4b0e952ac2c8cc89bc0db9edec59 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 16 Aug 2023 17:31:00 +0000 Subject: [PATCH 082/169] Revert "Implement references VarDebugInfo." This reverts commit 2ec007191348ef7cc13eb55e44e007b02cf75cf3. --- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 54 ++++----------- .../src/transform/validate.rs | 6 -- compiler/rustc_middle/src/mir/mod.rs | 4 -- compiler/rustc_middle/src/mir/pretty.rs | 9 +-- compiler/rustc_middle/src/mir/visit.rs | 1 - .../rustc_middle/src/ty/structural_impls.rs | 1 - .../rustc_mir_build/src/build/matches/mod.rs | 2 - compiler/rustc_mir_build/src/build/mod.rs | 2 - compiler/rustc_mir_transform/src/ref_prop.rs | 8 --- .../rustc_type_ir/src/structural_impls.rs | 1 - ...implifyComparisonIntegral.panic-abort.diff | 22 ++++-- ...mplifyComparisonIntegral.panic-unwind.diff | 22 ++++-- ..._to_digit.PreCodegen.after.panic-abort.mir | 5 +- ...to_digit.PreCodegen.after.panic-unwind.mir | 5 +- ...e_prop.debuginfo.ReferencePropagation.diff | 59 ++++++++-------- ...raw_then_mut_shr.ReferencePropagation.diff | 9 ++- ...ence_propagation.ReferencePropagation.diff | 51 ++++++-------- ...gation_const_ptr.ReferencePropagation.diff | 68 ++++++++----------- ..._propagation_mut.ReferencePropagation.diff | 51 ++++++-------- ...pagation_mut_ptr.ReferencePropagation.diff | 51 ++++++-------- 20 files changed, 183 insertions(+), 248 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 4167a85ccd59..564b5da32cc0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -42,9 +42,6 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { /// `.place.projection` from `mir::VarDebugInfo`. pub projection: &'tcx ty::List>, - - /// `references` from `mir::VarDebugInfo`. - pub references: u8, } #[derive(Clone, Copy, Debug)] @@ -323,7 +320,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: ty::List::empty(), - references: 0, }) } } else { @@ -399,15 +395,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, bx: &mut Bx, local: mir::Local, - mut base: PlaceRef<'tcx, Bx::Value>, + base: PlaceRef<'tcx, Bx::Value>, var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>, ) { let Some(dbg_var) = var.dbg_var else { return }; let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return }; - let DebugInfoOffset { mut direct_offset, indirect_offsets, result: _ } = + let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = calculate_debuginfo_offset(bx, local, &var, base.layout); - let mut indirect_offsets = &indirect_offsets[..]; // When targeting MSVC, create extra allocas for arguments instead of pointing multiple // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records @@ -421,9 +416,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // LLVM can handle simple things but anything more complex than just a direct // offset or one indirect offset of 0 is too complex for it to generate CV records // correctly. - && (direct_offset != Size::ZERO || !matches!(indirect_offsets, [Size::ZERO] | [])); + && (direct_offset != Size::ZERO || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); + + if should_create_individual_allocas { + let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } = + calculate_debuginfo_offset(bx, local, &var, base); - let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| { // Create a variable which will be a pointer to the actual value let ptr_ty = Ty::new_ptr( bx.tcx(), @@ -431,35 +429,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); let ptr_layout = bx.layout_of(ptr_ty); let alloca = PlaceRef::alloca(bx, ptr_layout); - bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount)); + bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); // Write the pointer to the variable bx.store(place.llval, alloca.llval, alloca.align); // Point the debug info to `*alloca` for the current variable - alloca - }; - - if var.references > 0 { - base = calculate_debuginfo_offset(bx, local, &var, base).result; - - // Point the debug info to `&...&base == alloca` for the current variable - for refcount in 0..var.references { - base = create_alloca(bx, base, refcount); - } - - direct_offset = Size::ZERO; - indirect_offsets = &[]; - } else if should_create_individual_allocas { - let place = calculate_debuginfo_offset(bx, local, &var, base).result; - - // Point the debug info to `*alloca` for the current variable - base = create_alloca(bx, place, 0); - direct_offset = Size::ZERO; - indirect_offsets = &[Size::ZERO]; + bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); + } else { + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets, None); } - - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, indirect_offsets, None); } pub fn debug_introduce_locals(&self, bx: &mut Bx) { @@ -492,7 +471,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let (mut var_ty, var_kind) = match var.value { + let (var_ty, var_kind) = match var.value { mir::VarDebugInfoContents::Place(place) => { let var_ty = self.monomorphized_place_ty(place.as_ref()); let var_kind = if let Some(arg_index) = var.argument_index @@ -529,13 +508,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; - for _ in 0..var.references { - var_ty = Ty::new_ptr( - bx.tcx(), - ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty }, - ); - } - self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); @@ -547,7 +519,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: place.projection, - references: var.references, }); } mir::VarDebugInfoContents::Const(c) => { @@ -601,7 +572,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(fragment_start..fragment_start + fragment_layout.size) }, projection: place.projection, - references: var.references, }); } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 83004492c8bf..33e73ad66535 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -701,12 +701,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { VarDebugInfoContents::Const(_) => {} VarDebugInfoContents::Place(place) => { check_place(self, place); - if debuginfo.references != 0 && place.projection.last() == Some(&PlaceElem::Deref) { - self.fail( - START_BLOCK.start_location(), - format!("debuginfo {debuginfo:?}, has both ref and deref"), - ); - } } VarDebugInfoContents::Composite { ty, ref fragments } => { for f in fragments { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ddb5e248cdc5..9ef3a1b30e49 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1109,10 +1109,6 @@ pub struct VarDebugInfo<'tcx> { /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the /// argument number in the original function before it was inlined. pub argument_index: Option, - - /// The data represents `name` dereferenced `references` times, - /// and not the direct value. - pub references: u8, } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 27e391370923..773056e8a179 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -555,13 +555,8 @@ fn write_scope_tree( } let indented_debug_info = format!( - "{0:1$}debug {2} => {3:&<4$}{5:?};", - INDENT, - indent, - var_debug_info.name, - "", - var_debug_info.references as usize, - var_debug_info.value, + "{0:1$}debug {2} => {3:?};", + INDENT, indent, var_debug_info.name, var_debug_info.value, ); if tcx.sess.opts.unstable_opts.mir_include_spans { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 64bc4fa7926d..069b38591684 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -840,7 +840,6 @@ macro_rules! make_mir_visitor { source_info, value, argument_index: _, - references: _, } = var_debug_info; self.visit_source_info(source_info); diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1347b35556d3..f979ddd00fa0 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -438,7 +438,6 @@ CloneLiftImpls! { (), bool, usize, - u8, u16, u32, u64, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index ed3ac7cb3ec7..3c450740712c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2242,7 +2242,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, - references: 0, value: VarDebugInfoContents::Place(for_arm_body.into()), argument_index: None, }); @@ -2262,7 +2261,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, - references: 0, value: VarDebugInfoContents::Place(ref_for_guard.into()), argument_index: None, }); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index c66eba5520e1..2a23a69b5841 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -820,7 +820,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; self.var_debug_info.push(VarDebugInfo { name, - references: 0, source_info: SourceInfo::outermost(captured_place.var_ident.span), value: VarDebugInfoContents::Place(use_place), argument_index: None, @@ -851,7 +850,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info, - references: 0, value: VarDebugInfoContents::Place(arg_local.into()), argument_index: Some(argument_index as u16 + 1), }); diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index c17c791f9c3f..49a940b57799 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -265,7 +265,6 @@ fn compute_replacement<'tcx>( targets, storage_to_remove, allowed_replacements, - fully_replacable_locals, any_replacement: false, }; @@ -346,7 +345,6 @@ struct Replacer<'tcx> { storage_to_remove: BitSet, allowed_replacements: FxHashSet<(Local, Location)>, any_replacement: bool, - fully_replacable_locals: BitSet, } impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { @@ -366,12 +364,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { if let Some((&PlaceElem::Deref, rest)) = target.projection.split_last() { *place = Place::from(target.local).project_deeper(rest, self.tcx); self.any_replacement = true; - } else if self.fully_replacable_locals.contains(place.local) - && let Some(references) = debuginfo.references.checked_add(1) - { - debuginfo.references = references; - *place = target; - self.any_replacement = true; } else { break } diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index 1a2d6d64eb05..f36f4ec8697f 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -23,7 +23,6 @@ TrivialTypeTraversalImpls! { (), bool, usize, - u8, u16, u32, u64, diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index b647455aeec3..f61632728baa 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -13,13 +13,16 @@ let mut _8: usize; let mut _9: usize; let mut _10: bool; - let mut _11: !; + let mut _14: !; scope 1 { debug v => _2; + let _11: &T; + let _12: &T; + let _13: &T; scope 2 { - debug v1 => &(*_2)[0 of 3]; - debug v2 => &(*_2)[1 of 3]; - debug v3 => &(*_2)[2 of 3]; + debug v1 => _11; + debug v2 => _12; + debug v3 => _13; } } @@ -39,10 +42,19 @@ } bb1: { - _11 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable; + _14 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable; } bb2: { + StorageLive(_11); + _11 = &(*_2)[0 of 3]; + StorageLive(_12); + _12 = &(*_2)[1 of 3]; + StorageLive(_13); + _13 = &(*_2)[2 of 3]; + StorageDead(_13); + StorageDead(_12); + StorageDead(_11); StorageDead(_4); return; } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index b02be61d0310..f6c337be10f2 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -13,13 +13,16 @@ let mut _8: usize; let mut _9: usize; let mut _10: bool; - let mut _11: !; + let mut _14: !; scope 1 { debug v => _2; + let _11: &T; + let _12: &T; + let _13: &T; scope 2 { - debug v1 => &(*_2)[0 of 3]; - debug v2 => &(*_2)[1 of 3]; - debug v3 => &(*_2)[2 of 3]; + debug v1 => _11; + debug v2 => _12; + debug v3 => _13; } } @@ -39,10 +42,19 @@ } bb1: { - _11 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue; + _14 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue; } bb2: { + StorageLive(_11); + _11 = &(*_2)[0 of 3]; + StorageLive(_12); + _12 = &(*_2)[1 of 3]; + StorageLive(_13); + _13 = &(*_2)[2 of 3]; + StorageDead(_13); + StorageDead(_12); + StorageDead(_11); StorageDead(_4); return; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir index a7a14ea645b0..f8c85941813c 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir @@ -8,8 +8,9 @@ fn num_to_digit(_1: char) -> u32 { debug self => _1; debug radix => const 8_u32; let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { - debug self => &_2; + debug self => _7; let mut _3: isize; } } @@ -23,12 +24,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(_1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { _3 = discriminant(_2); + StorageDead(_7); StorageDead(_2); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir index 5f8c6f7283c5..df7392edc50c 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir @@ -8,8 +8,9 @@ fn num_to_digit(_1: char) -> u32 { debug self => _1; debug radix => const 8_u32; let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { - debug self => &_2; + debug self => _7; let mut _3: isize; } } @@ -23,12 +24,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(_1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { _3 = discriminant(_2); + StorageDead(_7); StorageDead(_2); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff index 132f66a1ad3c..8fe361f2be4a 100644 --- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff @@ -22,27 +22,23 @@ let _24: &mut u8; let mut _25: debuginfo::T; scope 1 { -- debug ref_mut_u8 => _1; -+ debug ref_mut_u8 => &_2; + debug ref_mut_u8 => _1; let _3: &u8; let mut _28: &debuginfo::T; scope 2 { -- debug field => _3; -+ debug field => &((*_28).0: u8); + debug field => _3; let _5: &u8; scope 3 { - debug reborrow => _5; -+ debug reborrow => &_2; ++ debug reborrow => _1; let _9: &i32; let _22: &&&mut u8; let mut _27: &std::option::Option; scope 4 { -- debug variant_field => _9; -+ debug variant_field => &(((*_27) as Some).0: i32); + debug variant_field => _9; } scope 5 { -- debug constant_index => _19; -+ debug constant_index => &(*_11)[1 of 3]; + debug constant_index => _19; debug subslice => _20; debug constant_index_from_end => _21; let _19: &i32; @@ -51,21 +47,20 @@ let mut _26: &[i32; 10]; } scope 6 { -- debug multiple_borrow => _22; -+ debug multiple_borrow => &&&(_25.0: u8); + debug multiple_borrow => _22; } } } } bb0: { -- StorageLive(_1); + StorageLive(_1); StorageLive(_2); _2 = const 5_u8; -- _1 = &mut _2; -- StorageLive(_3); + _1 = &mut _2; + StorageLive(_3); _28 = const _; -- _3 = &((*_28).0: u8); + _3 = &((*_28).0: u8); - StorageLive(_5); - _5 = &(*_1); - StorageLive(_6); @@ -76,11 +71,11 @@ } bb1: { -- StorageLive(_9); + StorageLive(_9); _27 = const _; -- _9 = &(((*_27) as Some).0: i32); + _9 = &(((*_27) as Some).0: i32); - _6 = const (); -- StorageDead(_9); + StorageDead(_9); goto -> bb4; } @@ -118,8 +113,8 @@ } bb6: { -- StorageLive(_19); -- _19 = &(*_11)[1 of 3]; + StorageLive(_19); + _19 = &(*_11)[1 of 3]; StorageLive(_20); _20 = &(*_11)[2:-1]; StorageLive(_21); @@ -127,7 +122,7 @@ - _10 = const (); StorageDead(_21); StorageDead(_20); -- StorageDead(_19); + StorageDead(_19); goto -> bb8; } @@ -140,23 +135,23 @@ StorageDead(_12); StorageDead(_11); - StorageDead(_10); -- StorageLive(_22); -- StorageLive(_23); -- StorageLive(_24); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); StorageLive(_25); _25 = T(const 6_u8); -- _24 = &mut (_25.0: u8); -- _23 = &_24; -- _22 = &_23; + _24 = &mut (_25.0: u8); + _23 = &_24; + _22 = &_23; _0 = const (); StorageDead(_25); -- StorageDead(_24); -- StorageDead(_23); -- StorageDead(_22); + StorageDead(_24); + StorageDead(_23); + StorageDead(_22); - StorageDead(_5); -- StorageDead(_3); + StorageDead(_3); StorageDead(_2); -- StorageDead(_1); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff index 9ec8f9d78bbb..747028e128fc 100644 --- a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff @@ -13,16 +13,15 @@ debug x => _1; let _2: &mut i32; scope 2 { -- debug xref => _2; -+ debug xref => &_1; + debug xref => _2; let _3: *mut i32; scope 3 { - debug xraw => _3; -+ debug xraw => &_1; ++ debug xraw => _2; let _6: &i32; scope 4 { - debug xshr => _6; -+ debug xshr => &_1; ++ debug xshr => _2; let _7: i32; scope 5 { debug a => _7; @@ -38,7 +37,7 @@ StorageLive(_1); _1 = const 2_i32; - StorageLive(_2); -- _2 = &mut _1; + _2 = &mut _1; - StorageLive(_3); - StorageLive(_4); - StorageLive(_5); diff --git a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff index f1f77cffd200..1be2ce8d0bbd 100644 --- a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff @@ -52,8 +52,7 @@ debug a => _4; let _5: &usize; scope 2 { -- debug b => _5; -+ debug b => &_4; + debug b => _5; let _6: usize; scope 3 { debug c => _6; @@ -158,12 +157,10 @@ debug a => _60; let _61: &usize; scope 30 { -- debug b => _61; -+ debug b => &_60; + debug b => _61; let _62: &&usize; scope 31 { -- debug d => _62; -+ debug d => &&_60; + debug d => _62; let _63: usize; scope 32 { debug c => _63; @@ -175,12 +172,10 @@ debug a => _66; let mut _67: &usize; scope 34 { -- debug b => _67; -+ debug b => &_66; + debug b => _67; let _68: &mut &usize; scope 35 { -- debug d => _68; -+ debug d => &&_66; + debug d => _68; let _69: usize; scope 36 { debug c => _69; @@ -193,8 +188,8 @@ - StorageLive(_3); StorageLive(_4); _4 = const 5_usize; -- StorageLive(_5); -- _5 = &_4; + StorageLive(_5); + _5 = &_4; StorageLive(_6); - _6 = (*_5); + _6 = _4; @@ -209,7 +204,7 @@ StorageDead(_7); - _3 = const (); StorageDead(_6); -- StorageDead(_5); + StorageDead(_5); StorageDead(_4); - StorageDead(_3); - StorageLive(_9); @@ -394,13 +389,12 @@ - StorageLive(_59); StorageLive(_60); _60 = const 5_usize; -- StorageLive(_61); -- _61 = &_60; -- StorageLive(_62); -- _62 = &_61; + StorageLive(_61); + _61 = &_60; + StorageLive(_62); + _62 = &_61; StorageLive(_63); -- _63 = (*_61); -+ _63 = _60; + _63 = (*_61); StorageLive(_64); StorageLive(_65); _65 = (); @@ -412,19 +406,18 @@ StorageDead(_64); - _59 = const (); StorageDead(_63); -- StorageDead(_62); -- StorageDead(_61); + StorageDead(_62); + StorageDead(_61); StorageDead(_60); - StorageDead(_59); StorageLive(_66); _66 = const 5_usize; -- StorageLive(_67); -- _67 = &_66; -- StorageLive(_68); -- _68 = &mut _67; + StorageLive(_67); + _67 = &_66; + StorageLive(_68); + _68 = &mut _67; StorageLive(_69); -- _69 = (*_67); -+ _69 = _66; + _69 = (*_67); StorageLive(_70); StorageLive(_71); _71 = (); @@ -436,8 +429,8 @@ StorageDead(_70); _0 = const (); StorageDead(_69); -- StorageDead(_68); -- StorageDead(_67); + StorageDead(_68); + StorageDead(_67); StorageDead(_66); return; } diff --git a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff index 05eab7989dfb..ce5ddbfdd123 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff @@ -45,8 +45,7 @@ debug a => _4; let _5: *const usize; scope 3 { -- debug b => _5; -+ debug b => &_4; + debug b => _5; let _6: usize; scope 4 { debug c => _6; @@ -175,12 +174,10 @@ debug a => _58; let _59: *const usize; scope 39 { -- debug b => _59; -+ debug b => &_58; + debug b => _59; let _60: *const usize; scope 40 { -- debug c => _60; -+ debug c => &_58; + debug c => _60; let _61: usize; scope 41 { debug e => _61; @@ -195,12 +192,10 @@ debug a => _65; let _66: *const usize; scope 44 { -- debug b => _66; -+ debug b => &_65; + debug b => _66; let _67: &*const usize; scope 45 { -- debug d => _67; -+ debug d => &&_65; + debug d => _67; let _68: usize; scope 46 { debug c => _68; @@ -215,12 +210,10 @@ debug a => _71; let mut _72: *const usize; scope 49 { -- debug b => _72; -+ debug b => &_71; + debug b => _72; let _73: &mut *const usize; scope 50 { -- debug d => _73; -+ debug d => &&_71; + debug d => _73; let _74: usize; scope 51 { debug c => _74; @@ -234,8 +227,8 @@ - StorageLive(_3); StorageLive(_4); _4 = const 5_usize; -- StorageLive(_5); -- _5 = &raw const _4; + StorageLive(_5); + _5 = &raw const _4; StorageLive(_6); - _6 = (*_5); + _6 = _4; @@ -250,7 +243,7 @@ StorageDead(_7); - _3 = const (); StorageDead(_6); -- StorageDead(_5); + StorageDead(_5); StorageDead(_4); - StorageDead(_3); - StorageLive(_9); @@ -427,10 +420,11 @@ - StorageLive(_57); StorageLive(_58); _58 = const 13_usize; -- StorageLive(_59); -- _59 = &raw const _58; -- StorageLive(_60); + StorageLive(_59); + _59 = &raw const _58; + StorageLive(_60); - _60 = &raw const (*_59); ++ _60 = &raw const _58; StorageLive(_61); - _61 = (*_60); + _61 = _58; @@ -445,20 +439,19 @@ StorageDead(_62); - _57 = const (); StorageDead(_61); -- StorageDead(_60); -- StorageDead(_59); + StorageDead(_60); + StorageDead(_59); StorageDead(_58); - StorageDead(_57); - StorageLive(_64); StorageLive(_65); _65 = const 5_usize; -- StorageLive(_66); -- _66 = &raw const _65; -- StorageLive(_67); -- _67 = &_66; + StorageLive(_66); + _66 = &raw const _65; + StorageLive(_67); + _67 = &_66; StorageLive(_68); -- _68 = (*_66); -+ _68 = _65; + _68 = (*_66); StorageLive(_69); StorageLive(_70); _70 = (); @@ -470,19 +463,18 @@ StorageDead(_69); - _64 = const (); StorageDead(_68); -- StorageDead(_67); -- StorageDead(_66); + StorageDead(_67); + StorageDead(_66); StorageDead(_65); - StorageDead(_64); StorageLive(_71); _71 = const 5_usize; -- StorageLive(_72); -- _72 = &raw const _71; -- StorageLive(_73); -- _73 = &mut _72; + StorageLive(_72); + _72 = &raw const _71; + StorageLive(_73); + _73 = &mut _72; StorageLive(_74); -- _74 = (*_72); -+ _74 = _71; + _74 = (*_72); StorageLive(_75); StorageLive(_76); _76 = (); @@ -494,8 +486,8 @@ StorageDead(_75); _0 = const (); StorageDead(_74); -- StorageDead(_73); -- StorageDead(_72); + StorageDead(_73); + StorageDead(_72); StorageDead(_71); return; } diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff index ee680fdb3f21..7c7f424bba2b 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff @@ -52,8 +52,7 @@ debug a => _4; let _5: &mut usize; scope 2 { -- debug b => _5; -+ debug b => &_4; + debug b => _5; let _6: usize; scope 3 { debug c => _6; @@ -158,12 +157,10 @@ debug a => _60; let _61: &mut usize; scope 30 { -- debug b => _61; -+ debug b => &_60; + debug b => _61; let _62: &&mut usize; scope 31 { -- debug d => _62; -+ debug d => &&_60; + debug d => _62; let _63: usize; scope 32 { debug c => _63; @@ -175,12 +172,10 @@ debug a => _66; let mut _67: &mut usize; scope 34 { -- debug b => _67; -+ debug b => &_66; + debug b => _67; let _68: &mut &mut usize; scope 35 { -- debug d => _68; -+ debug d => &&_66; + debug d => _68; let _69: usize; scope 36 { debug c => _69; @@ -193,8 +188,8 @@ - StorageLive(_3); StorageLive(_4); _4 = const 5_usize; -- StorageLive(_5); -- _5 = &mut _4; + StorageLive(_5); + _5 = &mut _4; StorageLive(_6); - _6 = (*_5); + _6 = _4; @@ -209,7 +204,7 @@ StorageDead(_7); - _3 = const (); StorageDead(_6); -- StorageDead(_5); + StorageDead(_5); StorageDead(_4); - StorageDead(_3); - StorageLive(_9); @@ -391,13 +386,12 @@ - StorageLive(_59); StorageLive(_60); _60 = const 5_usize; -- StorageLive(_61); -- _61 = &mut _60; -- StorageLive(_62); -- _62 = &_61; + StorageLive(_61); + _61 = &mut _60; + StorageLive(_62); + _62 = &_61; StorageLive(_63); -- _63 = (*_61); -+ _63 = _60; + _63 = (*_61); StorageLive(_64); StorageLive(_65); _65 = (); @@ -409,19 +403,18 @@ StorageDead(_64); - _59 = const (); StorageDead(_63); -- StorageDead(_62); -- StorageDead(_61); + StorageDead(_62); + StorageDead(_61); StorageDead(_60); - StorageDead(_59); StorageLive(_66); _66 = const 5_usize; -- StorageLive(_67); -- _67 = &mut _66; -- StorageLive(_68); -- _68 = &mut _67; + StorageLive(_67); + _67 = &mut _66; + StorageLive(_68); + _68 = &mut _67; StorageLive(_69); -- _69 = (*_67); -+ _69 = _66; + _69 = (*_67); StorageLive(_70); StorageLive(_71); _71 = (); @@ -433,8 +426,8 @@ StorageDead(_70); _0 = const (); StorageDead(_69); -- StorageDead(_68); -- StorageDead(_67); + StorageDead(_68); + StorageDead(_67); StorageDead(_66); return; } diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff index fb0ef3184f00..b6b2acc0b439 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff @@ -42,8 +42,7 @@ debug a => _4; let _5: *mut usize; scope 3 { -- debug b => _5; -+ debug b => &_4; + debug b => _5; let _6: usize; scope 4 { debug c => _6; @@ -172,12 +171,10 @@ debug a => _58; let _59: *mut usize; scope 39 { -- debug b => _59; -+ debug b => &_58; + debug b => _59; let _60: &*mut usize; scope 40 { -- debug d => _60; -+ debug d => &&_58; + debug d => _60; let _61: usize; scope 41 { debug c => _61; @@ -192,12 +189,10 @@ debug a => _64; let mut _65: *mut usize; scope 44 { -- debug b => _65; -+ debug b => &_64; + debug b => _65; let _66: &mut *mut usize; scope 45 { -- debug d => _66; -+ debug d => &&_64; + debug d => _66; let _67: usize; scope 46 { debug c => _67; @@ -211,8 +206,8 @@ - StorageLive(_3); StorageLive(_4); _4 = const 5_usize; -- StorageLive(_5); -- _5 = &raw mut _4; + StorageLive(_5); + _5 = &raw mut _4; StorageLive(_6); - _6 = (*_5); + _6 = _4; @@ -227,7 +222,7 @@ StorageDead(_7); - _3 = const (); StorageDead(_6); -- StorageDead(_5); + StorageDead(_5); StorageDead(_4); - StorageDead(_3); - StorageLive(_9); @@ -401,13 +396,12 @@ - StorageLive(_57); StorageLive(_58); _58 = const 5_usize; -- StorageLive(_59); -- _59 = &raw mut _58; -- StorageLive(_60); -- _60 = &_59; + StorageLive(_59); + _59 = &raw mut _58; + StorageLive(_60); + _60 = &_59; StorageLive(_61); -- _61 = (*_59); -+ _61 = _58; + _61 = (*_59); StorageLive(_62); StorageLive(_63); _63 = (); @@ -419,19 +413,18 @@ StorageDead(_62); - _57 = const (); StorageDead(_61); -- StorageDead(_60); -- StorageDead(_59); + StorageDead(_60); + StorageDead(_59); StorageDead(_58); - StorageDead(_57); StorageLive(_64); _64 = const 5_usize; -- StorageLive(_65); -- _65 = &raw mut _64; -- StorageLive(_66); -- _66 = &mut _65; + StorageLive(_65); + _65 = &raw mut _64; + StorageLive(_66); + _66 = &mut _65; StorageLive(_67); -- _67 = (*_65); -+ _67 = _64; + _67 = (*_65); StorageLive(_68); StorageLive(_69); _69 = (); @@ -443,8 +436,8 @@ StorageDead(_68); _0 = const (); StorageDead(_67); -- StorageDead(_66); -- StorageDead(_65); + StorageDead(_66); + StorageDead(_65); StorageDead(_64); return; } From c535326537964e44ee70d4f58a8b0985e3ab5574 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 16 Aug 2023 17:47:34 +0000 Subject: [PATCH 083/169] Add test. --- tests/ui/mir/debug-ref-undef.rs | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/ui/mir/debug-ref-undef.rs diff --git a/tests/ui/mir/debug-ref-undef.rs b/tests/ui/mir/debug-ref-undef.rs new file mode 100644 index 000000000000..37fd22a9dd2d --- /dev/null +++ b/tests/ui/mir/debug-ref-undef.rs @@ -0,0 +1,57 @@ +// run-pass +// compile-flags: -g -O -Zmir-opt-level=0 -Zinline-mir=y -Zmir-enable-passes=+ReferencePropagation + +#![allow(dead_code)] + +use std::marker::PhantomData; + +struct RawTable { + marker: PhantomData, +} + +impl RawTable { + fn iter(&self) -> RawIter { + RawIter { marker: PhantomData } + } +} + +struct RawIter { + marker: PhantomData, +} + +impl Iterator for RawIter { + type Item = (); + fn next(&mut self) -> Option<()> { + None + } +} + +struct HashMap { + table: RawTable, +} + +struct Iter { + inner: RawIter, // Removing this breaks the reproducer +} + +impl IntoIterator for &HashMap { + type Item = T; + type IntoIter = Iter; + fn into_iter(self) -> Iter { + Iter { inner: self.table.iter() } + } +} + +impl Iterator for Iter { + type Item = T; + fn next(&mut self) -> Option { + None + } +} + +pub fn main() { + let maybe_hash_set: Option> = None; + for _ in maybe_hash_set.as_ref().unwrap_or(&HashMap { table: RawTable { marker: PhantomData } }) + { + } +} From b542c5526f494230989d94821cb1918ef6d3da6e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 17 Aug 2023 17:06:55 +0000 Subject: [PATCH 084/169] Bless mir-opt tests. --- ...d.unwrap_unchecked.Inline.panic-abort.diff | 11 +- ....unwrap_unchecked.Inline.panic-unwind.diff | 11 +- ...unchecked.PreCodegen.after.panic-abort.mir | 5 +- ...nchecked.PreCodegen.after.panic-unwind.mir | 5 +- ...cked_ops.step_forward.PreCodegen.after.mir | 7 +- .../loops.filter_mapped.PreCodegen.after.mir | 3 +- .../loops.int_range.PreCodegen.after.mir | 93 ++++--- ...ward_loop.PreCodegen.after.panic-abort.mir | 109 ++++---- ...ard_loop.PreCodegen.after.panic-unwind.mir | 109 ++++---- ...iter_next.PreCodegen.after.panic-abort.mir | 10 +- ...ter_next.PreCodegen.after.panic-unwind.mir | 10 +- ...variant_a-{closure#0}.PreCodegen.after.mir | 238 ++++++++++++------ ...ange_loop.PreCodegen.after.panic-abort.mir | 128 +++++----- ...nge_loop.PreCodegen.after.panic-unwind.mir | 128 +++++----- ...erse_loop.PreCodegen.after.panic-abort.mir | 15 +- ...rse_loop.PreCodegen.after.panic-unwind.mir | 15 +- 16 files changed, 533 insertions(+), 364 deletions(-) diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index 486f276b21c8..e3c57347392a 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -7,7 +7,8 @@ let mut _2: std::option::Option; + scope 1 (inlined #[track_caller] Option::::unwrap_unchecked) { + debug self => _2; -+ let mut _3: isize; ++ let mut _3: &std::option::Option; ++ let mut _4: isize; + scope 2 { + debug val => _0; + } @@ -20,7 +21,7 @@ + } + } + scope 4 (inlined Option::::is_some) { -+ debug self => &_2; ++ debug self => _3; + } + } @@ -28,8 +29,9 @@ StorageLive(_2); _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind unreachable]; -+ _3 = discriminant(_2); -+ switchInt(move _3) -> [1: bb2, otherwise: bb1]; ++ StorageLive(_3); ++ _4 = discriminant(_2); ++ switchInt(move _4) -> [1: bb2, otherwise: bb1]; } bb1: { @@ -38,6 +40,7 @@ + + bb2: { + _0 = move ((_2 as Some).0: T); ++ StorageDead(_3); StorageDead(_2); return; } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index 1c3aa5379460..fc638cb3acef 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -7,7 +7,8 @@ let mut _2: std::option::Option; + scope 1 (inlined #[track_caller] Option::::unwrap_unchecked) { + debug self => _2; -+ let mut _3: isize; ++ let mut _3: &std::option::Option; ++ let mut _4: isize; + scope 2 { + debug val => _0; + } @@ -20,7 +21,7 @@ + } + } + scope 4 (inlined Option::::is_some) { -+ debug self => &_2; ++ debug self => _3; + } + } @@ -28,8 +29,9 @@ StorageLive(_2); _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind: bb2]; -+ _3 = discriminant(_2); -+ switchInt(move _3) -> [1: bb2, otherwise: bb1]; ++ StorageLive(_3); ++ _4 = discriminant(_2); ++ switchInt(move _4) -> [1: bb2, otherwise: bb1]; } bb1: { @@ -42,6 +44,7 @@ - resume; + bb2: { + _0 = move ((_2 as Some).0: T); ++ StorageDead(_3); + StorageDead(_2); + return; } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir index 82238626798e..fcc4d43ced66 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir @@ -6,6 +6,7 @@ fn unwrap_unchecked(_1: Option) -> T { scope 1 (inlined #[track_caller] Option::::unwrap_unchecked) { debug self => _1; let mut _2: isize; + let mut _3: &std::option::Option; scope 2 { debug val => _0; } @@ -18,17 +19,19 @@ fn unwrap_unchecked(_1: Option) -> T { } } scope 4 (inlined Option::::is_some) { - debug self => &_1; + debug self => _3; } } bb0: { + StorageLive(_3); _2 = discriminant(_1); switchInt(move _2) -> [1: bb1, otherwise: bb2]; } bb1: { _0 = move ((_1 as Some).0: T); + StorageDead(_3); return; } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir index 82238626798e..fcc4d43ced66 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir @@ -6,6 +6,7 @@ fn unwrap_unchecked(_1: Option) -> T { scope 1 (inlined #[track_caller] Option::::unwrap_unchecked) { debug self => _1; let mut _2: isize; + let mut _3: &std::option::Option; scope 2 { debug val => _0; } @@ -18,17 +19,19 @@ fn unwrap_unchecked(_1: Option) -> T { } } scope 4 (inlined Option::::is_some) { - debug self => &_1; + debug self => _3; } } bb0: { + StorageLive(_3); _2 = discriminant(_1); switchInt(move _2) -> [1: bb1, otherwise: bb2]; } bb1: { _0 = move ((_1 as Some).0: T); + StorageDead(_3); return; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir index 9be41bff3cab..b2ea96f033ef 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir @@ -10,13 +10,14 @@ fn step_forward(_1: u32, _2: usize) -> u32 { let _3: std::option::Option; let mut _6: bool; let mut _7: u32; + let mut _8: &std::option::Option; scope 2 { } scope 3 (inlined Option::::is_none) { - debug self => &_3; + debug self => _8; let mut _5: bool; scope 4 (inlined Option::::is_some) { - debug self => &_3; + debug self => _8; let mut _4: isize; } } @@ -28,6 +29,7 @@ fn step_forward(_1: u32, _2: usize) -> u32 { bb0: { StorageLive(_6); + StorageLive(_8); StorageLive(_3); _3 = ::forward_checked(_1, _2) -> [return: bb1, unwind continue]; } @@ -39,6 +41,7 @@ fn step_forward(_1: u32, _2: usize) -> u32 { _6 = Not(move _5); StorageDead(_5); StorageDead(_3); + StorageDead(_8); switchInt(move _6) -> [0: bb3, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir index 07a57a7b5785..940b9ae11561 100644 --- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir @@ -10,6 +10,7 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () let mut _8: std::option::Option; let mut _9: isize; let _11: (); + let mut _12: &mut std::iter::FilterMap, impl Fn(T) -> Option>; scope 1 { debug iter => _5; let _10: U; @@ -17,7 +18,7 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () debug x => _10; } scope 4 (inlined , impl Fn(T) -> Option> as Iterator>::next) { - debug self => &_5; + debug self => _12; let mut _6: &mut impl Iterator; let mut _7: &mut impl Fn(T) -> Option; } diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index 4c6bcd1bdbd5..2e51faeba5ae 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -4,95 +4,108 @@ fn int_range(_1: usize, _2: usize) -> () { debug start => _1; debug end => _2; let mut _0: (); - let mut _3: usize; - let mut _6: std::option::Option; - let mut _9: isize; - let _11: (); + let mut _3: std::ops::Range; + let mut _4: std::ops::Range; + let mut _8: std::option::Option; + let mut _11: isize; + let _13: (); + let mut _14: &mut std::ops::Range; scope 1 { - debug iter => std::ops::Range{ .0 => _3, .1 => _2, }; - let _10: usize; + debug iter => _4; + let _12: usize; scope 2 { - debug i => _10; + debug i => _12; } scope 4 (inlined iter::range::>::next) { - debug self => &std::ops::Range{ .0 => _3, .1 => _2, }; + debug self => _14; scope 5 (inlined as iter::range::RangeIteratorImpl>::spec_next) { - debug self => &std::ops::Range{ .0 => _3, .1 => _2, }; - let mut _5: bool; - let _7: usize; - let mut _8: usize; + debug self => _14; + let mut _7: bool; + let _9: usize; + let mut _10: usize; + let mut _15: &usize; + let mut _16: &usize; scope 6 { - debug old => _7; + debug old => _9; scope 7 { } } scope 8 (inlined cmp::impls::::lt) { - debug self => &_3; - debug other => &_2; - let mut _4: usize; + debug self => _15; + debug other => _16; + let mut _5: usize; + let mut _6: usize; } } } } scope 3 (inlined as IntoIterator>::into_iter) { - debug self => std::ops::Range{ .0 => _1, .1 => _2, }; + debug self => _3; } bb0: { - StorageLive(_3); - _3 = _1; + _3 = std::ops::Range:: { start: _1, end: _2 }; + StorageLive(_4); + _4 = move _3; goto -> bb1; } bb1: { - StorageLive(_6); + StorageLive(_8); + StorageLive(_9); StorageLive(_7); + StorageLive(_15); + StorageLive(_16); StorageLive(_5); - StorageLive(_4); - _4 = _3; - _5 = Lt(move _4, _2); - StorageDead(_4); - switchInt(move _5) -> [0: bb2, otherwise: bb3]; + _5 = (_4.0: usize); + StorageLive(_6); + _6 = (_4.1: usize); + _7 = Lt(move _5, move _6); + StorageDead(_6); + StorageDead(_5); + StorageDead(_16); + StorageDead(_15); + switchInt(move _7) -> [0: bb2, otherwise: bb3]; } bb2: { - _6 = Option::::None; + _8 = Option::::None; goto -> bb5; } bb3: { - _7 = _3; - StorageLive(_8); - _8 = ::forward_unchecked(_7, const 1_usize) -> [return: bb4, unwind continue]; + _9 = (_4.0: usize); + StorageLive(_10); + _10 = ::forward_unchecked(_9, const 1_usize) -> [return: bb4, unwind continue]; } bb4: { - _3 = move _8; - StorageDead(_8); - _6 = Option::::Some(_7); + (_4.0: usize) = move _10; + StorageDead(_10); + _8 = Option::::Some(_9); goto -> bb5; } bb5: { - StorageDead(_5); StorageDead(_7); - _9 = discriminant(_6); - switchInt(move _9) -> [0: bb6, 1: bb7, otherwise: bb9]; + StorageDead(_9); + _11 = discriminant(_8); + switchInt(move _11) -> [0: bb6, 1: bb7, otherwise: bb9]; } bb6: { - StorageDead(_6); - StorageDead(_3); + StorageDead(_8); + StorageDead(_4); return; } bb7: { - _10 = ((_6 as Some).0: usize); - _11 = opaque::(move _10) -> [return: bb8, unwind continue]; + _12 = ((_8 as Some).0: usize); + _13 = opaque::(move _12) -> [return: bb8, unwind continue]; } bb8: { - StorageDead(_6); + StorageDead(_8); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir index cdaa3cfc9955..d76b46bdd94a 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -5,87 +5,100 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { debug end => _2; debug f => _3; let mut _0: (); - let mut _4: u32; - let mut _7: std::option::Option; - let mut _10: isize; - let mut _12: &impl Fn(u32); - let mut _13: (u32,); - let _14: (); + let mut _4: std::ops::Range; + let mut _5: std::ops::Range; + let mut _9: std::option::Option; + let mut _12: isize; + let mut _14: &impl Fn(u32); + let mut _15: (u32,); + let _16: (); + let mut _17: &mut std::ops::Range; scope 1 { - debug iter => std::ops::Range{ .0 => _4, .1 => _2, }; - let _11: u32; + debug iter => _5; + let _13: u32; scope 2 { - debug x => _11; + debug x => _13; } scope 4 (inlined iter::range::>::next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _2, }; + debug self => _17; scope 5 (inlined as iter::range::RangeIteratorImpl>::spec_next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _2, }; - let mut _6: bool; - let _8: u32; - let mut _9: u32; + debug self => _17; + let mut _8: bool; + let _10: u32; + let mut _11: u32; + let mut _18: &u32; + let mut _19: &u32; scope 6 { - debug old => _8; + debug old => _10; scope 7 { } } scope 8 (inlined cmp::impls::::lt) { - debug self => &_4; - debug other => &_2; - let mut _5: u32; + debug self => _18; + debug other => _19; + let mut _6: u32; + let mut _7: u32; } } } } scope 3 (inlined as IntoIterator>::into_iter) { - debug self => std::ops::Range{ .0 => _1, .1 => _2, }; + debug self => _4; } bb0: { - StorageLive(_4); - _4 = _1; + _4 = std::ops::Range:: { start: _1, end: _2 }; + StorageLive(_5); + _5 = move _4; goto -> bb1; } bb1: { - StorageLive(_7); + StorageLive(_9); + StorageLive(_10); StorageLive(_8); + StorageLive(_18); + StorageLive(_19); StorageLive(_6); - StorageLive(_5); - _5 = _4; - _6 = Lt(move _5, _2); - StorageDead(_5); - switchInt(move _6) -> [0: bb2, otherwise: bb3]; + _6 = (_5.0: u32); + StorageLive(_7); + _7 = (_5.1: u32); + _8 = Lt(move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_19); + StorageDead(_18); + switchInt(move _8) -> [0: bb2, otherwise: bb3]; } bb2: { - _7 = Option::::None; + _9 = Option::::None; goto -> bb5; } bb3: { - _8 = _4; - StorageLive(_9); - _9 = ::forward_unchecked(_8, const 1_usize) -> [return: bb4, unwind unreachable]; + _10 = (_5.0: u32); + StorageLive(_11); + _11 = ::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind unreachable]; } bb4: { - _4 = move _9; - StorageDead(_9); - _7 = Option::::Some(_8); + (_5.0: u32) = move _11; + StorageDead(_11); + _9 = Option::::Some(_10); goto -> bb5; } bb5: { - StorageDead(_6); StorageDead(_8); - _10 = discriminant(_7); - switchInt(move _10) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_10); + _12 = discriminant(_9); + switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_7); - StorageDead(_4); + StorageDead(_9); + StorageDead(_5); drop(_3) -> [return: bb7, unwind unreachable]; } @@ -94,18 +107,18 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb8: { - _11 = ((_7 as Some).0: u32); - StorageLive(_12); - _12 = &_3; - StorageLive(_13); - _13 = (_11,); - _14 = >::call(move _12, move _13) -> [return: bb9, unwind unreachable]; + _13 = ((_9 as Some).0: u32); + StorageLive(_14); + _14 = &_3; + StorageLive(_15); + _15 = (_13,); + _16 = >::call(move _14, move _15) -> [return: bb9, unwind unreachable]; } bb9: { - StorageDead(_13); - StorageDead(_12); - StorageDead(_7); + StorageDead(_15); + StorageDead(_14); + StorageDead(_9); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir index c4e56ea3b235..4d7c017dad40 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -5,87 +5,100 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { debug end => _2; debug f => _3; let mut _0: (); - let mut _4: u32; - let mut _7: std::option::Option; - let mut _10: isize; - let mut _12: &impl Fn(u32); - let mut _13: (u32,); - let _14: (); + let mut _4: std::ops::Range; + let mut _5: std::ops::Range; + let mut _9: std::option::Option; + let mut _12: isize; + let mut _14: &impl Fn(u32); + let mut _15: (u32,); + let _16: (); + let mut _17: &mut std::ops::Range; scope 1 { - debug iter => std::ops::Range{ .0 => _4, .1 => _2, }; - let _11: u32; + debug iter => _5; + let _13: u32; scope 2 { - debug x => _11; + debug x => _13; } scope 4 (inlined iter::range::>::next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _2, }; + debug self => _17; scope 5 (inlined as iter::range::RangeIteratorImpl>::spec_next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _2, }; - let mut _6: bool; - let _8: u32; - let mut _9: u32; + debug self => _17; + let mut _8: bool; + let _10: u32; + let mut _11: u32; + let mut _18: &u32; + let mut _19: &u32; scope 6 { - debug old => _8; + debug old => _10; scope 7 { } } scope 8 (inlined cmp::impls::::lt) { - debug self => &_4; - debug other => &_2; - let mut _5: u32; + debug self => _18; + debug other => _19; + let mut _6: u32; + let mut _7: u32; } } } } scope 3 (inlined as IntoIterator>::into_iter) { - debug self => std::ops::Range{ .0 => _1, .1 => _2, }; + debug self => _4; } bb0: { - StorageLive(_4); - _4 = _1; + _4 = std::ops::Range:: { start: _1, end: _2 }; + StorageLive(_5); + _5 = move _4; goto -> bb1; } bb1: { - StorageLive(_7); + StorageLive(_9); + StorageLive(_10); StorageLive(_8); + StorageLive(_18); + StorageLive(_19); StorageLive(_6); - StorageLive(_5); - _5 = _4; - _6 = Lt(move _5, _2); - StorageDead(_5); - switchInt(move _6) -> [0: bb2, otherwise: bb3]; + _6 = (_5.0: u32); + StorageLive(_7); + _7 = (_5.1: u32); + _8 = Lt(move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_19); + StorageDead(_18); + switchInt(move _8) -> [0: bb2, otherwise: bb3]; } bb2: { - _7 = Option::::None; + _9 = Option::::None; goto -> bb5; } bb3: { - _8 = _4; - StorageLive(_9); - _9 = ::forward_unchecked(_8, const 1_usize) -> [return: bb4, unwind: bb11]; + _10 = (_5.0: u32); + StorageLive(_11); + _11 = ::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind: bb11]; } bb4: { - _4 = move _9; - StorageDead(_9); - _7 = Option::::Some(_8); + (_5.0: u32) = move _11; + StorageDead(_11); + _9 = Option::::Some(_10); goto -> bb5; } bb5: { - StorageDead(_6); StorageDead(_8); - _10 = discriminant(_7); - switchInt(move _10) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_10); + _12 = discriminant(_9); + switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_7); - StorageDead(_4); + StorageDead(_9); + StorageDead(_5); drop(_3) -> [return: bb7, unwind continue]; } @@ -94,18 +107,18 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb8: { - _11 = ((_7 as Some).0: u32); - StorageLive(_12); - _12 = &_3; - StorageLive(_13); - _13 = (_11,); - _14 = >::call(move _12, move _13) -> [return: bb9, unwind: bb11]; + _13 = ((_9 as Some).0: u32); + StorageLive(_14); + _14 = &_3; + StorageLive(_15); + _15 = (_13,); + _16 = >::call(move _14, move _15) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_13); - StorageDead(_12); - StorageDead(_7); + StorageDead(_15); + StorageDead(_14); + StorageDead(_9); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir index 14fd049ede88..7360aa3e6982 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir @@ -10,14 +10,16 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { let mut _4: bool; let _5: u32; let mut _6: u32; + let mut _7: &u32; + let mut _8: &u32; scope 3 { debug old => _5; scope 4 { } } scope 5 (inlined cmp::impls::::lt) { - debug self => &((*_1).0: u32); - debug other => &((*_1).1: u32); + debug self => _7; + debug other => _8; let mut _2: u32; let mut _3: u32; } @@ -27,6 +29,8 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { bb0: { StorageLive(_5); StorageLive(_4); + StorageLive(_7); + StorageLive(_8); StorageLive(_2); _2 = ((*_1).0: u32); StorageLive(_3); @@ -34,6 +38,8 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { _4 = Lt(move _2, move _3); StorageDead(_3); StorageDead(_2); + StorageDead(_8); + StorageDead(_7); switchInt(move _4) -> [0: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir index 668a2ac1e205..61957082d8bb 100644 --- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir @@ -10,14 +10,16 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { let mut _4: bool; let _5: u32; let mut _6: u32; + let mut _7: &u32; + let mut _8: &u32; scope 3 { debug old => _5; scope 4 { } } scope 5 (inlined cmp::impls::::lt) { - debug self => &((*_1).0: u32); - debug other => &((*_1).1: u32); + debug self => _7; + debug other => _8; let mut _2: u32; let mut _3: u32; } @@ -27,6 +29,8 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { bb0: { StorageLive(_5); StorageLive(_4); + StorageLive(_7); + StorageLive(_8); StorageLive(_2); _2 = ((*_1).0: u32); StorageLive(_3); @@ -34,6 +38,8 @@ fn range_iter_next(_1: &mut std::ops::Range) -> Option { _4 = Lt(move _2, move _3); StorageDead(_3); StorageDead(_2); + StorageDead(_8); + StorageDead(_7); switchInt(move _4) -> [0: bb1, otherwise: bb2]; } diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index f9b0c85c8527..1488779f93b8 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -3,138 +3,206 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2: &&(usize, usize, usize, usize)) -> bool { let mut _0: bool; let mut _3: &(usize, usize, usize, usize); - let mut _4: &(usize, usize, usize, usize); + let _4: &usize; let mut _5: &(usize, usize, usize, usize); - let mut _6: &(usize, usize, usize, usize); - let mut _9: bool; - let mut _10: bool; - let mut _13: bool; + let _6: &usize; + let mut _7: &(usize, usize, usize, usize); + let _8: &usize; + let mut _9: &(usize, usize, usize, usize); + let _10: &usize; + let _11: &usize; let mut _16: bool; let mut _17: bool; - let mut _20: bool; + let _18: &usize; + let mut _23: bool; + let _24: &usize; + let mut _29: bool; + let mut _30: bool; + let _31: &usize; + let mut _36: bool; + let mut _37: &&usize; + let mut _38: &&usize; + let mut _39: &&usize; + let mut _40: &&usize; + let mut _41: &&usize; + let mut _42: &&usize; + let mut _43: &&usize; + let mut _44: &&usize; scope 1 { - debug a => &((*_3).0: usize); - debug b => &((*_4).1: usize); - debug c => &((*_5).2: usize); - debug d => &((*_6).3: usize); + debug a => _4; + debug b => _6; + debug c => _8; + debug d => _10; scope 2 (inlined cmp::impls::::le) { - debug self => &&((*_3).0: usize); - debug other => &&((*_5).2: usize); + debug self => _37; + debug other => _38; + let mut _12: &usize; + let mut _13: &usize; scope 3 (inlined cmp::impls::::le) { - debug self => &((*_3).0: usize); - debug other => &((*_5).2: usize); - let mut _7: usize; - let mut _8: usize; - } - } - scope 4 (inlined cmp::impls::::le) { - debug self => &&((*_5).2: usize); - debug other => &&((*_3).0: usize); - scope 5 (inlined cmp::impls::::le) { - debug self => &((*_5).2: usize); - debug other => &((*_3).0: usize); + debug self => _12; + debug other => _13; let mut _14: usize; let mut _15: usize; } } + scope 4 (inlined cmp::impls::::le) { + debug self => _41; + debug other => _42; + let mut _25: &usize; + let mut _26: &usize; + scope 5 (inlined cmp::impls::::le) { + debug self => _25; + debug other => _26; + let mut _27: usize; + let mut _28: usize; + } + } scope 6 (inlined cmp::impls::::le) { - debug self => &&((*_6).3: usize); - debug other => &&((*_4).1: usize); + debug self => _39; + debug other => _40; + let mut _19: &usize; + let mut _20: &usize; scope 7 (inlined cmp::impls::::le) { - debug self => &((*_6).3: usize); - debug other => &((*_4).1: usize); - let mut _11: usize; - let mut _12: usize; + debug self => _19; + debug other => _20; + let mut _21: usize; + let mut _22: usize; } } scope 8 (inlined cmp::impls::::le) { - debug self => &&((*_4).1: usize); - debug other => &&((*_6).3: usize); + debug self => _43; + debug other => _44; + let mut _32: &usize; + let mut _33: &usize; scope 9 (inlined cmp::impls::::le) { - debug self => &((*_4).1: usize); - debug other => &((*_6).3: usize); - let mut _18: usize; - let mut _19: usize; + debug self => _32; + debug other => _33; + let mut _34: usize; + let mut _35: usize; } } } bb0: { + StorageLive(_4); _3 = deref_copy (*_2); - _4 = deref_copy (*_2); + _4 = &((*_3).0: usize); + StorageLive(_6); _5 = deref_copy (*_2); - _6 = deref_copy (*_2); - StorageLive(_10); - StorageLive(_9); - StorageLive(_7); - _7 = ((*_3).0: usize); + _6 = &((*_5).1: usize); StorageLive(_8); - _8 = ((*_5).2: usize); - _9 = Le(move _7, move _8); - StorageDead(_8); - StorageDead(_7); - switchInt(move _9) -> [0: bb1, otherwise: bb2]; + _7 = deref_copy (*_2); + _8 = &((*_7).2: usize); + StorageLive(_10); + _9 = deref_copy (*_2); + _10 = &((*_9).3: usize); + StorageLive(_17); + StorageLive(_16); + StorageLive(_37); + StorageLive(_38); + StorageLive(_11); + _11 = _8; + _12 = deref_copy _4; + _13 = deref_copy _11; + StorageLive(_14); + _14 = (*_12); + StorageLive(_15); + _15 = (*_13); + _16 = Le(move _14, move _15); + StorageDead(_15); + StorageDead(_14); + StorageDead(_11); + StorageDead(_38); + StorageDead(_37); + switchInt(move _16) -> [0: bb1, otherwise: bb2]; } bb1: { - _10 = const false; + _17 = const false; goto -> bb3; } bb2: { - StorageLive(_13); - StorageLive(_11); - _11 = ((*_6).3: usize); - StorageLive(_12); - _12 = ((*_4).1: usize); - _13 = Le(move _11, move _12); - StorageDead(_12); - StorageDead(_11); - _10 = move _13; + StorageLive(_23); + StorageLive(_39); + StorageLive(_40); + StorageLive(_18); + _18 = _6; + _19 = deref_copy _10; + _20 = deref_copy _18; + StorageLive(_21); + _21 = (*_19); + StorageLive(_22); + _22 = (*_20); + _23 = Le(move _21, move _22); + StorageDead(_22); + StorageDead(_21); + StorageDead(_18); + StorageDead(_40); + StorageDead(_39); + _17 = move _23; goto -> bb3; } bb3: { - StorageDead(_13); - StorageDead(_9); - switchInt(move _10) -> [0: bb4, otherwise: bb8]; + StorageDead(_23); + StorageDead(_16); + switchInt(move _17) -> [0: bb4, otherwise: bb8]; } bb4: { - StorageLive(_17); - StorageLive(_16); - StorageLive(_14); - _14 = ((*_5).2: usize); - StorageLive(_15); - _15 = ((*_3).0: usize); - _16 = Le(move _14, move _15); - StorageDead(_15); - StorageDead(_14); - switchInt(move _16) -> [0: bb5, otherwise: bb6]; + StorageLive(_30); + StorageLive(_29); + StorageLive(_41); + StorageLive(_42); + StorageLive(_24); + _24 = _4; + _25 = deref_copy _8; + _26 = deref_copy _24; + StorageLive(_27); + _27 = (*_25); + StorageLive(_28); + _28 = (*_26); + _29 = Le(move _27, move _28); + StorageDead(_28); + StorageDead(_27); + StorageDead(_24); + StorageDead(_42); + StorageDead(_41); + switchInt(move _29) -> [0: bb5, otherwise: bb6]; } bb5: { - _17 = const false; + _30 = const false; goto -> bb7; } bb6: { - StorageLive(_20); - StorageLive(_18); - _18 = ((*_4).1: usize); - StorageLive(_19); - _19 = ((*_6).3: usize); - _20 = Le(move _18, move _19); - StorageDead(_19); - StorageDead(_18); - _17 = move _20; + StorageLive(_36); + StorageLive(_43); + StorageLive(_44); + StorageLive(_31); + _31 = _10; + _32 = deref_copy _6; + _33 = deref_copy _31; + StorageLive(_34); + _34 = (*_32); + StorageLive(_35); + _35 = (*_33); + _36 = Le(move _34, move _35); + StorageDead(_35); + StorageDead(_34); + StorageDead(_31); + StorageDead(_44); + StorageDead(_43); + _30 = move _36; goto -> bb7; } bb7: { - StorageDead(_20); - StorageDead(_16); - _0 = move _17; + StorageDead(_36); + StorageDead(_29); + _0 = move _30; goto -> bb9; } @@ -144,8 +212,12 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:7:25: 7:39], _2 } bb9: { + StorageDead(_30); StorageDead(_17); StorageDead(_10); + StorageDead(_8); + StorageDead(_6); + StorageDead(_4); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index 901381f070b9..4edf4b4fb444 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -5,95 +5,109 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug f => _2; let mut _0: (); let mut _3: usize; - let mut _4: usize; - let mut _7: std::option::Option; - let mut _10: isize; - let mut _12: usize; - let mut _13: bool; - let mut _15: &impl Fn(usize, &T); - let mut _16: (usize, &T); - let _17: (); - let mut _18: usize; + let mut _4: std::ops::Range; + let mut _5: std::ops::Range; + let mut _9: std::option::Option; + let mut _12: isize; + let mut _14: usize; + let mut _15: bool; + let mut _17: &impl Fn(usize, &T); + let mut _18: (usize, &T); + let _19: (); + let mut _20: &mut std::ops::Range; scope 1 { - debug iter => std::ops::Range{ .0 => _4, .1 => _3, }; - let _11: usize; + debug iter => _5; + let _13: usize; scope 2 { - debug i => _11; - let _14: &T; + debug i => _13; + let _16: &T; scope 3 { - debug x => _14; + debug x => _16; } } scope 5 (inlined iter::range::>::next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _3, }; + debug self => _20; scope 6 (inlined as iter::range::RangeIteratorImpl>::spec_next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _3, }; - let mut _6: bool; - let _8: usize; - let mut _9: usize; + debug self => _20; + let mut _8: bool; + let _10: usize; + let mut _11: usize; + let mut _21: &usize; + let mut _22: &usize; scope 7 { - debug old => _8; + debug old => _10; scope 8 { } } scope 9 (inlined cmp::impls::::lt) { - debug self => &_4; - debug other => &_3; - let mut _5: usize; + debug self => _21; + debug other => _22; + let mut _6: usize; + let mut _7: usize; } } } } scope 4 (inlined as IntoIterator>::into_iter) { - debug self => std::ops::Range{ .0 => _18, .1 => _3, }; + debug self => _4; } bb0: { + StorageLive(_3); _3 = Len((*_1)); - StorageLive(_4); - _4 = const 0_usize; + _4 = std::ops::Range:: { start: const 0_usize, end: move _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = move _4; goto -> bb1; } bb1: { - StorageLive(_7); + StorageLive(_9); + StorageLive(_10); StorageLive(_8); + StorageLive(_21); + StorageLive(_22); StorageLive(_6); - StorageLive(_5); - _5 = _4; - _6 = Lt(move _5, _3); - StorageDead(_5); - switchInt(move _6) -> [0: bb2, otherwise: bb3]; + _6 = (_5.0: usize); + StorageLive(_7); + _7 = (_5.1: usize); + _8 = Lt(move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_22); + StorageDead(_21); + switchInt(move _8) -> [0: bb2, otherwise: bb3]; } bb2: { - _7 = Option::::None; + _9 = Option::::None; goto -> bb5; } bb3: { - _8 = _4; - StorageLive(_9); - _9 = ::forward_unchecked(_8, const 1_usize) -> [return: bb4, unwind unreachable]; + _10 = (_5.0: usize); + StorageLive(_11); + _11 = ::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind unreachable]; } bb4: { - _4 = move _9; - StorageDead(_9); - _7 = Option::::Some(_8); + (_5.0: usize) = move _11; + StorageDead(_11); + _9 = Option::::Some(_10); goto -> bb5; } bb5: { - StorageDead(_6); StorageDead(_8); - _10 = discriminant(_7); - switchInt(move _10) -> [0: bb6, 1: bb8, otherwise: bb11]; + StorageDead(_10); + _12 = discriminant(_9); + switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb11]; } bb6: { - StorageDead(_7); - StorageDead(_4); + StorageDead(_9); + StorageDead(_5); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -102,25 +116,25 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _11 = ((_7 as Some).0: usize); - _12 = Len((*_1)); - _13 = Lt(_11, _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb9, unwind unreachable]; + _13 = ((_9 as Some).0: usize); + _14 = Len((*_1)); + _15 = Lt(_13, _14); + assert(move _15, "index out of bounds: the length is {} but the index is {}", move _14, _13) -> [success: bb9, unwind unreachable]; } bb9: { - _14 = &(*_1)[_11]; - StorageLive(_15); - _15 = &_2; - StorageLive(_16); - _16 = (_11, _14); - _17 = >::call(move _15, move _16) -> [return: bb10, unwind unreachable]; + _16 = &(*_1)[_13]; + StorageLive(_17); + _17 = &_2; + StorageLive(_18); + _18 = (_13, _16); + _19 = >::call(move _17, move _18) -> [return: bb10, unwind unreachable]; } bb10: { - StorageDead(_16); - StorageDead(_15); - StorageDead(_7); + StorageDead(_18); + StorageDead(_17); + StorageDead(_9); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index a47a73395cf2..f7b19e80e448 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -5,95 +5,109 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug f => _2; let mut _0: (); let mut _3: usize; - let mut _4: usize; - let mut _7: std::option::Option; - let mut _10: isize; - let mut _12: usize; - let mut _13: bool; - let mut _15: &impl Fn(usize, &T); - let mut _16: (usize, &T); - let _17: (); - let mut _18: usize; + let mut _4: std::ops::Range; + let mut _5: std::ops::Range; + let mut _9: std::option::Option; + let mut _12: isize; + let mut _14: usize; + let mut _15: bool; + let mut _17: &impl Fn(usize, &T); + let mut _18: (usize, &T); + let _19: (); + let mut _20: &mut std::ops::Range; scope 1 { - debug iter => std::ops::Range{ .0 => _4, .1 => _3, }; - let _11: usize; + debug iter => _5; + let _13: usize; scope 2 { - debug i => _11; - let _14: &T; + debug i => _13; + let _16: &T; scope 3 { - debug x => _14; + debug x => _16; } } scope 5 (inlined iter::range::>::next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _3, }; + debug self => _20; scope 6 (inlined as iter::range::RangeIteratorImpl>::spec_next) { - debug self => &std::ops::Range{ .0 => _4, .1 => _3, }; - let mut _6: bool; - let _8: usize; - let mut _9: usize; + debug self => _20; + let mut _8: bool; + let _10: usize; + let mut _11: usize; + let mut _21: &usize; + let mut _22: &usize; scope 7 { - debug old => _8; + debug old => _10; scope 8 { } } scope 9 (inlined cmp::impls::::lt) { - debug self => &_4; - debug other => &_3; - let mut _5: usize; + debug self => _21; + debug other => _22; + let mut _6: usize; + let mut _7: usize; } } } } scope 4 (inlined as IntoIterator>::into_iter) { - debug self => std::ops::Range{ .0 => _18, .1 => _3, }; + debug self => _4; } bb0: { + StorageLive(_3); _3 = Len((*_1)); - StorageLive(_4); - _4 = const 0_usize; + _4 = std::ops::Range:: { start: const 0_usize, end: move _3 }; + StorageDead(_3); + StorageLive(_5); + _5 = move _4; goto -> bb1; } bb1: { - StorageLive(_7); + StorageLive(_9); + StorageLive(_10); StorageLive(_8); + StorageLive(_21); + StorageLive(_22); StorageLive(_6); - StorageLive(_5); - _5 = _4; - _6 = Lt(move _5, _3); - StorageDead(_5); - switchInt(move _6) -> [0: bb2, otherwise: bb3]; + _6 = (_5.0: usize); + StorageLive(_7); + _7 = (_5.1: usize); + _8 = Lt(move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_22); + StorageDead(_21); + switchInt(move _8) -> [0: bb2, otherwise: bb3]; } bb2: { - _7 = Option::::None; + _9 = Option::::None; goto -> bb5; } bb3: { - _8 = _4; - StorageLive(_9); - _9 = ::forward_unchecked(_8, const 1_usize) -> [return: bb4, unwind: bb12]; + _10 = (_5.0: usize); + StorageLive(_11); + _11 = ::forward_unchecked(_10, const 1_usize) -> [return: bb4, unwind: bb12]; } bb4: { - _4 = move _9; - StorageDead(_9); - _7 = Option::::Some(_8); + (_5.0: usize) = move _11; + StorageDead(_11); + _9 = Option::::Some(_10); goto -> bb5; } bb5: { - StorageDead(_6); StorageDead(_8); - _10 = discriminant(_7); - switchInt(move _10) -> [0: bb6, 1: bb8, otherwise: bb11]; + StorageDead(_10); + _12 = discriminant(_9); + switchInt(move _12) -> [0: bb6, 1: bb8, otherwise: bb11]; } bb6: { - StorageDead(_7); - StorageDead(_4); + StorageDead(_9); + StorageDead(_5); drop(_2) -> [return: bb7, unwind continue]; } @@ -102,25 +116,25 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _11 = ((_7 as Some).0: usize); - _12 = Len((*_1)); - _13 = Lt(_11, _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb9, unwind: bb12]; + _13 = ((_9 as Some).0: usize); + _14 = Len((*_1)); + _15 = Lt(_13, _14); + assert(move _15, "index out of bounds: the length is {} but the index is {}", move _14, _13) -> [success: bb9, unwind: bb12]; } bb9: { - _14 = &(*_1)[_11]; - StorageLive(_15); - _15 = &_2; - StorageLive(_16); - _16 = (_11, _14); - _17 = >::call(move _15, move _16) -> [return: bb10, unwind: bb12]; + _16 = &(*_1)[_13]; + StorageLive(_17); + _17 = &_2; + StorageLive(_18); + _18 = (_13, _16); + _19 = >::call(move _17, move _18) -> [return: bb10, unwind: bb12]; } bb10: { - StorageDead(_16); - StorageDead(_15); - StorageDead(_7); + StorageDead(_18); + StorageDead(_17); + StorageDead(_9); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index a5df36ca3889..549cb4f46a0e 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -12,6 +12,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _20: &impl Fn(&T); let mut _21: (&T,); let _22: (); + let mut _23: &mut std::iter::Rev>; scope 1 { debug iter => _15; let _19: &T; @@ -19,7 +20,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug x => _19; } scope 25 (inlined > as Iterator>::next) { - debug self => &_15; + debug self => _23; let mut _16: &mut std::slice::Iter<'_, T>; } } @@ -48,15 +49,15 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug ptr => _9; scope 16 (inlined ptr::mut_ptr::::is_null) { debug self => _9; - let mut _23: *mut u8; + let mut _24: *mut u8; scope 17 { scope 18 (inlined ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _23; + debug ptr => _24; scope 19 (inlined ptr::mut_ptr::::addr) { - debug self => _23; + debug self => _24; scope 20 { scope 21 (inlined ptr::mut_ptr::::cast::<()>) { - debug self => _23; + debug self => _24; } } } @@ -131,10 +132,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_9); _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); - StorageLive(_23); + StorageLive(_24); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; - StorageDead(_23); + StorageDead(_24); StorageDead(_10); StorageDead(_9); StorageLive(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index f681da4d275d..43f8806e165a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -12,6 +12,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _20: &impl Fn(&T); let mut _21: (&T,); let _22: (); + let mut _23: &mut std::iter::Rev>; scope 1 { debug iter => _15; let _19: &T; @@ -19,7 +20,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug x => _19; } scope 25 (inlined > as Iterator>::next) { - debug self => &_15; + debug self => _23; let mut _16: &mut std::slice::Iter<'_, T>; } } @@ -48,15 +49,15 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug ptr => _9; scope 16 (inlined ptr::mut_ptr::::is_null) { debug self => _9; - let mut _23: *mut u8; + let mut _24: *mut u8; scope 17 { scope 18 (inlined ptr::mut_ptr::::is_null::runtime_impl) { - debug ptr => _23; + debug ptr => _24; scope 19 (inlined ptr::mut_ptr::::addr) { - debug self => _23; + debug self => _24; scope 20 { scope 21 (inlined ptr::mut_ptr::::cast::<()>) { - debug self => _23; + debug self => _24; } } } @@ -131,10 +132,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_9); _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); - StorageLive(_23); + StorageLive(_24); _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; - StorageDead(_23); + StorageDead(_24); StorageDead(_10); StorageDead(_9); StorageLive(_12); From 3798bca60546712afdc673eb73783c784442b340 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 17 Aug 2023 18:28:33 +0000 Subject: [PATCH 085/169] Bless codegen tests. --- tests/codegen/slice-ref-equality.rs | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs index 4d0dce7b0743..afbdf66ce0aa 100644 --- a/tests/codegen/slice-ref-equality.rs +++ b/tests/codegen/slice-ref-equality.rs @@ -44,48 +44,48 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool { // equality for non-byte types also just emit a `bcmp`, not a loop. // CHECK-LABEL: @eq_slice_of_nested_u8( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 #[no_mangle] fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %x.1, 3 + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %1, 3 // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) x == y } // CHECK-LABEL: @eq_slice_of_i32( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 #[no_mangle] fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2 + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2 // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) x == y } // CHECK-LABEL: @eq_slice_of_nonzero( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 #[no_mangle] fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2 + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2 // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) x == y } // CHECK-LABEL: @eq_slice_of_option_of_nonzero( -// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1 -// CHECK-SAME: [[USIZE]] noundef %y.1 +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 #[no_mangle] fn eq_slice_of_option_of_nonzero(x: &[Option], y: &[Option]) -> bool { - // CHECK: icmp eq [[USIZE]] %x.1, %y.1 - // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 1 + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 1 // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}(ptr // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) x == y From df3819bd96365ae03d64c33f2785a23cc334ccd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 17 Aug 2023 19:48:22 +0000 Subject: [PATCH 086/169] update `thsiserror` to release >= 1.0.46 this version is the one containing the workaround for the provider API changes on nightly --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d707067bb92..47d6b3c44a8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5126,9 +5126,9 @@ checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] @@ -5155,9 +5155,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", From 20c648c5827a2a774f4b6aeb36804c845130659b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 17 Aug 2023 14:33:24 -0700 Subject: [PATCH 087/169] Normalize before checking if local is freeze in deduced_param_attrs --- .../src/deduce_param_attrs.rs | 7 +- .../ui/async-await/deep-futures-are-freeze.rs | 179 ++++++++++++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 tests/ui/async-await/deep-futures-are-freeze.rs diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 60ca3dfb2dab..79645310a398 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -203,7 +203,12 @@ pub fn deduced_param_attrs<'tcx>( body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map( |(arg_index, local_decl)| DeducedParamAttrs { read_only: !deduce_read_only.mutable_args.contains(arg_index) - && local_decl.ty.is_freeze(tcx, param_env), + // We must normalize here to reveal opaques and normalize + // their substs, otherwise we'll see exponential blow-up in + // compile times: #113372 + && tcx + .normalize_erasing_regions(param_env, local_decl.ty) + .is_freeze(tcx, param_env), }, ), ); diff --git a/tests/ui/async-await/deep-futures-are-freeze.rs b/tests/ui/async-await/deep-futures-are-freeze.rs new file mode 100644 index 000000000000..dd676d5e18c0 --- /dev/null +++ b/tests/ui/async-await/deep-futures-are-freeze.rs @@ -0,0 +1,179 @@ +// build-pass +// compile-flags: -Copt-level=s -Clto=fat +// no-prefer-dynamic +// edition: 2021 + +#![recursion_limit = "256"] + +fn main() { + spawn(move || main0()) +} + +fn spawn(future: impl FnOnce() -> F) { + future(); +} + +async fn main0() { + main1().await; + main2().await; +} +async fn main1() { + main2().await; + main3().await; +} +async fn main2() { + main3().await; + main4().await; +} +async fn main3() { + main4().await; + main5().await; +} +async fn main4() { + main5().await; + main6().await; +} +async fn main5() { + main6().await; + main7().await; +} +async fn main6() { + main7().await; + main8().await; +} +async fn main7() { + main8().await; + main9().await; +} +async fn main8() { + main9().await; + main10().await; +} +async fn main9() { + main10().await; + main11().await; +} +async fn main10() { + main11().await; + main12().await; +} +async fn main11() { + main12().await; + main13().await; +} +async fn main12() { + main13().await; + main14().await; +} +async fn main13() { + main14().await; + main15().await; +} +async fn main14() { + main15().await; + main16().await; +} +async fn main15() { + main16().await; + main17().await; +} +async fn main16() { + main17().await; + main18().await; +} +async fn main17() { + main18().await; + main19().await; +} +async fn main18() { + main19().await; + main20().await; +} +async fn main19() { + main20().await; + main21().await; +} +async fn main20() { + main21().await; + main22().await; +} +async fn main21() { + main22().await; + main23().await; +} +async fn main22() { + main23().await; + main24().await; +} +async fn main23() { + main24().await; + main25().await; +} +async fn main24() { + main25().await; + main26().await; +} +async fn main25() { + main26().await; + main27().await; +} +async fn main26() { + main27().await; + main28().await; +} +async fn main27() { + main28().await; + main29().await; +} +async fn main28() { + main29().await; + main30().await; +} +async fn main29() { + main30().await; + main31().await; +} +async fn main30() { + main31().await; + main32().await; +} +async fn main31() { + main32().await; + main33().await; +} +async fn main32() { + main33().await; + main34().await; +} +async fn main33() { + main34().await; + main35().await; +} +async fn main34() { + main35().await; + main36().await; +} +async fn main35() { + main36().await; + main37().await; +} +async fn main36() { + main37().await; + main38().await; +} +async fn main37() { + main38().await; + main39().await; +} +async fn main38() { + main39().await; + main40().await; +} +async fn main39() { + main40().await; +} +async fn main40() { + boom(&mut ()).await; +} + +async fn boom(f: &mut ()) {} From 54bd826d567d588b6ac4ff2bff1f7fbba7229463 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Fri, 18 Aug 2023 04:00:43 +0400 Subject: [PATCH 088/169] Add waffle back to review rotation --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 2c71b650f68c..a06195cc3340 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -489,7 +489,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "WaffleLapkin", "clubby789", "oli-obk"] +users_on_vacation = ["jyn514", "clubby789", "oli-obk"] [assign.adhoc_groups] compiler-team = [ From dee6c9241f7402b5122266f8f59f6b731678b50a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Aug 2023 09:01:22 +1000 Subject: [PATCH 089/169] Refactor `interpolated_or_expr_span`. It's much more complicated than it needs to be, and it doesn't modify the expression. We can do the `Result` handling outside of it, and change it to just return a span. Also fix an errant comma that makes the comment hard to read. --- compiler/rustc_parse/src/parser/expr.rs | 32 ++++++++++--------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e409c7c67817..d17f2f0261b9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -626,8 +626,8 @@ impl<'a> Parser<'a> { fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P)> { self.bump(); - let expr = self.parse_expr_prefix(None); - let (span, expr) = self.interpolated_or_expr_span(expr)?; + let expr = self.parse_expr_prefix(None)?; + let span = self.interpolated_or_expr_span(&expr); Ok((lo.to(span), expr)) } @@ -702,20 +702,12 @@ impl<'a> Parser<'a> { self.parse_expr_unary(lo, UnOp::Not) } - /// Returns the span of expr, if it was not interpolated or the span of the interpolated token. - fn interpolated_or_expr_span( - &self, - expr: PResult<'a, P>, - ) -> PResult<'a, (Span, P)> { - expr.map(|e| { - ( - match self.prev_token.kind { - TokenKind::Interpolated(..) => self.prev_token.span, - _ => e.span, - }, - e, - ) - }) + /// Returns the span of expr if it was not interpolated, or the span of the interpolated token. + fn interpolated_or_expr_span(&self, expr: &Expr) -> Span { + match self.prev_token.kind { + TokenKind::Interpolated(..) => self.prev_token.span, + _ => expr.span, + } } fn parse_assoc_op_cast( @@ -898,8 +890,8 @@ impl<'a> Parser<'a> { self.parse_expr_prefix_range(None) } else { self.parse_expr_prefix(None) - }; - let (hi, expr) = self.interpolated_or_expr_span(expr)?; + }?; + let hi = self.interpolated_or_expr_span(&expr); let span = lo.to(hi); if let Some(lt) = lifetime { self.error_remove_borrow_lifetime(span, lt.ident.span); @@ -930,8 +922,8 @@ impl<'a> Parser<'a> { fn parse_expr_dot_or_call(&mut self, attrs: Option) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(attrs)?; self.collect_tokens_for_expr(attrs, |this, attrs| { - let base = this.parse_expr_bottom(); - let (span, base) = this.interpolated_or_expr_span(base)?; + let base = this.parse_expr_bottom()?; + let span = this.interpolated_or_expr_span(&base); this.parse_expr_dot_or_call_with(base, span, attrs) }) } From 9167eea553d00a790c10ebc0a821e3fa1b13d93c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 15 Aug 2023 10:35:42 +1000 Subject: [PATCH 090/169] Use `interpolated_or_expr_span` in one suitable place. --- compiler/rustc_parse/src/parser/expr.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d17f2f0261b9..e308e5b34207 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -193,13 +193,7 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Operator); while let Some(op) = self.check_assoc_op() { - // Adjust the span for interpolated LHS to point to the `$lhs` token - // and not to what it refers to. - let lhs_span = match self.prev_token.kind { - TokenKind::Interpolated(..) => self.prev_token.span, - _ => lhs.span, - }; - + let lhs_span = self.interpolated_or_expr_span(&lhs); let cur_op_span = self.token.span; let restrictions = if op.node.is_assign_like() { self.restrictions & Restrictions::NO_STRUCT_LITERAL From 34493047226477272354cd7ac413720d1a446f43 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 17 Aug 2023 08:51:52 +1000 Subject: [PATCH 091/169] Make enum decoding errors more informative. By printing the actual value, as long as the expected range. I found this helpful when I encountered one of these errors. --- compiler/rustc_macros/src/serialize.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index f1e7b8eb6c74..ba75517d7a66 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -59,14 +59,14 @@ fn decodable_body( }) .collect(); let message = format!( - "invalid enum variant tag while decoding `{}`, expected 0..{}", + "invalid enum variant tag while decoding `{}`, expected 0..{}, actual {{}}", ty_name, variants.len() ); quote! { match ::rustc_serialize::Decoder::read_usize(__decoder) { #match_inner - _ => panic!(#message), + n => panic!(#message, n), } } } From 9e22351c74a9b87f452590638c6c3997f206cb72 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Aug 2023 16:43:05 +1000 Subject: [PATCH 092/169] Rename `NtOrTt` as `ParseNtResult`. It's more descriptive, and future-proofs it if/when additional variants get added. --- compiler/rustc_expand/src/mbe/macro_parser.rs | 6 +++--- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/nonterminal.rs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 05c0cd952b8b..7e85beaadcbc 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -81,7 +81,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; -use rustc_parse::parser::{NtOrTt, Parser}; +use rustc_parse::parser::{ParseNtResult, Parser}; use rustc_span::symbol::Ident; use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; @@ -692,8 +692,8 @@ impl TtParser { Ok(nt) => nt, }; let m = match nt { - NtOrTt::Nt(nt) => MatchedNonterminal(Lrc::new(nt)), - NtOrTt::Tt(tt) => MatchedTokenTree(tt), + ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new(nt)), + ParseNtResult::Tt(tt) => MatchedTokenTree(tt), }; mp.push_match(next_metavar, seq_depth, m); mp.idx += 1; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3c3872f2706f..77c59bb38814 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1491,7 +1491,7 @@ pub enum FlatToken { } #[derive(Debug)] -pub enum NtOrTt { +pub enum ParseNtResult { Nt(Nonterminal), Tt(TokenTree), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 882ecc2a7ea8..ff059a7e865a 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::{kw, Ident}; use crate::errors::UnexpectedNonterminal; use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; -use crate::parser::{FollowedByType, ForceCollect, NtOrTt, Parser, PathStyle}; +use crate::parser::{FollowedByType, ForceCollect, ParseNtResult, Parser, PathStyle}; impl<'a> Parser<'a> { /// Checks whether a non-terminal may begin with a particular token. @@ -103,14 +103,14 @@ impl<'a> Parser<'a> { /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call /// site. #[inline] - pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt> { + pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> { // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, // which requires having captured tokens available. Since we cannot determine // in advance whether or not a proc-macro will be (transitively) invoked, // we always capture tokens for any `Nonterminal` which needs them. let mut nt = match kind { // Note that TT is treated differently to all the others. - NonterminalKind::TT => return Ok(NtOrTt::Tt(self.parse_token_tree())), + NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { Some(item) => NtItem(item), None => { @@ -197,7 +197,7 @@ impl<'a> Parser<'a> { ); } - Ok(NtOrTt::Nt(nt)) + Ok(ParseNtResult::Nt(nt)) } } From b1d232a6da800b26f18d79a0340436fa4aec7327 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Thu, 29 Jun 2023 12:07:24 +0800 Subject: [PATCH 093/169] rework link parsing loop --- src/librustdoc/html/markdown.rs | 89 ++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 0ba2d992392e..b5ab8a7b12ac 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -50,7 +50,7 @@ use crate::html::render::small_url_encode; use crate::html::toc::TocBuilder; use pulldown_cmark::{ - html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, + html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag, }; #[cfg(test)] @@ -1240,6 +1240,7 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin pub(crate) struct MarkdownLink { pub kind: LinkType, pub link: String, + pub display_text: String, pub range: MarkdownLinkRange, } @@ -1263,8 +1264,8 @@ impl MarkdownLinkRange { } } -pub(crate) fn markdown_links( - md: &str, +pub(crate) fn markdown_links<'md, R>( + md: &'md str, preprocess_link: impl Fn(MarkdownLink) -> Option, ) -> Vec { if md.is_empty() { @@ -1375,32 +1376,72 @@ pub(crate) fn markdown_links( MarkdownLinkRange::Destination(range.clone()) }; - Parser::new_with_broken_link_callback( + let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into())); + let mut event_iter = Parser::new_with_broken_link_callback( md, main_body_opts(), - Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))), + Some(&mut broken_link_callback), ) - .into_offset_iter() - .filter_map(|(event, span)| match event { - Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { - let range = match link_type { - // Link is pulled from the link itself. - LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => { - span_for_offset_backward(span, b'[', b']') + .into_offset_iter(); + let mut links = Vec::new(); + + while let Some((event, span)) = event_iter.next() { + match event { + Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + let range = match link_type { + // Link is pulled from the link itself. + LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => { + span_for_offset_backward(span, b'[', b']') + } + LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'), + LinkType::Inline => span_for_offset_backward(span, b'(', b')'), + // Link is pulled from elsewhere in the document. + LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => { + span_for_link(&dest, span) + } + LinkType::Autolink | LinkType::Email => unreachable!(), + }; + + let display_text = + collect_link_data(&mut event_iter).map_or(String::new(), CowStr::into_string); + + if let Some(link) = preprocess_link(MarkdownLink { + kind: link_type, + display_text, + link: dest.into_string(), + range, + }) { + links.push(link); } - LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'), - LinkType::Inline => span_for_offset_backward(span, b'(', b')'), - // Link is pulled from elsewhere in the document. - LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => { - span_for_link(&dest, span) - } - LinkType::Autolink | LinkType::Email => unreachable!(), - }; - preprocess_link(MarkdownLink { kind: link_type, range, link: dest.into_string() }) + } + _ => {} } - _ => None, - }) - .collect() + } + + links +} + +fn collect_link_data<'input, 'callback>( + event_iter: &mut OffsetIter<'input, 'callback>, +) -> Option> { + let mut display_text = None; + + while let Some((event, _span)) = event_iter.next() { + match event { + Event::Text(code) => { + display_text = Some(code); + } + Event::Code(code) => { + display_text = Some(code); + } + Event::End(_) => { + break; + } + _ => {} + } + } + + display_text } #[derive(Debug)] From da582a71d2c19a2ded0c45f464cb64c9544c26eb Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Thu, 29 Jun 2023 13:24:09 +0800 Subject: [PATCH 094/169] Add warn level lint `redundant_explicit_links` - Currently it will panic due to the resolution's caching issue --- src/doc/rustdoc/src/lints.md | 22 ++++ src/librustdoc/lint.rs | 12 +++ .../passes/collect_intra_doc_links.rs | 101 ++++++++++++++++-- .../lints/redundant_explicit_links.rs | 6 ++ 4 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc-ui/lints/redundant_explicit_links.rs diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index fd57b0796448..fe06b303e72f 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -412,3 +412,25 @@ help: if you meant to use a literal backtick, escape it warning: 1 warning emitted ``` + +## `redundant_explicit_links` + +This lint is **warned by default**. It detects explicit links that are same +as computed automatic links. +This usually means the explicit links is removeable. For example: + +```rust +#![warn(rustdoc::redundant_explicit_links)] + +pub fn dummy_target() {} // note: unnecessary - warns by default. + +/// [`dummy_target`](dummy_target) +/// [dummy_target](dummy_target) +pub fn c() {} +``` + +Which will give: + +```text + +``` diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 749c1ff51bfc..d45040e348a2 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -185,6 +185,17 @@ declare_rustdoc_lint! { "detects unescaped backticks in doc comments" } +declare_rustdoc_lint! { + /// This lint is **warned by default**. It detects explicit links that are same + /// as computed automatic links. This usually means the explicit links is removeable. + /// This is a `rustdoc` only lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#redundant_explicit_links + REDUNDANT_EXPLICIT_LINKS, + Warn, + "detects redundant explicit links in doc comments" +} + pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { vec![ BROKEN_INTRA_DOC_LINKS, @@ -197,6 +208,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { BARE_URLS, MISSING_CRATE_LEVEL_DOCS, UNESCAPED_BACKTICKS, + REDUNDANT_EXPLICIT_LINKS, ] }); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 26ff64f06a32..78b86cdfa824 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -994,7 +994,15 @@ impl LinkCollector<'_, '_> { _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), }; for md_link in preprocessed_markdown_links(&doc) { - let link = self.resolve_link(item, item_id, module_id, &doc, &md_link); + let PreprocessedMarkdownLink(_pp_link, ori_link) = &md_link; + let diag_info = DiagnosticInfo { + item, + dox: &doc, + ori_link: &ori_link.link, + link_range: ori_link.range.clone(), + }; + + let link = self.resolve_link(item, item_id, module_id, &md_link, &diag_info); if let Some(link) = link { self.cx.cache.intra_doc_links.entry(item.item_id).or_default().insert(link); } @@ -1010,19 +1018,11 @@ impl LinkCollector<'_, '_> { item: &Item, item_id: DefId, module_id: DefId, - dox: &str, - link: &PreprocessedMarkdownLink, + PreprocessedMarkdownLink(pp_link, ori_link): &PreprocessedMarkdownLink, + diag_info: &DiagnosticInfo<'_>, ) -> Option { - let PreprocessedMarkdownLink(pp_link, ori_link) = link; trace!("considering link '{}'", ori_link.link); - let diag_info = DiagnosticInfo { - item, - dox, - ori_link: &ori_link.link, - link_range: ori_link.range.clone(), - }; - let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?; let disambiguator = *disambiguator; @@ -1042,6 +1042,17 @@ impl LinkCollector<'_, '_> { matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), )?; + self.check_redundant_explicit_link( + &res, + path_str, + item_id, + module_id, + disambiguator, + &ori_link, + extra_fragment, + &diag_info, + ); + // Check for a primitive which might conflict with a module // Report the ambiguity and require that the user specify which one they meant. // FIXME: could there ever be a primitive not in the type namespace? @@ -1372,6 +1383,74 @@ impl LinkCollector<'_, '_> { } } } + + fn check_redundant_explicit_link( + &mut self, + ex_res: &Res, + ex: &Box, + item_id: DefId, + module_id: DefId, + dis: Option, + ori_link: &MarkdownLink, + extra_fragment: &Option, + diag_info: &DiagnosticInfo<'_>, + ) { + // Check if explicit resolution's path is same as resolution of original link's display text path, e.g. + // [target](target) + // [`target`](target) + // [target](path::to::target) + // [`target`](path::to::target) + // [path::to::target](path::to::target) + // [`path::to::target`](path::to::target) + // + // To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated + // into explicit path. + if ori_link.kind != LinkType::Inline { + return; + } + + let di_text = &ori_link.display_text; + let di_len = di_text.len(); + let ex_len = ex.len(); + + let intra_doc_links = std::mem::take(&mut self.cx.cache.intra_doc_links); + + if ex_len >= di_len && &ex[(ex_len - di_len)..] == di_text { + let Some((di_res, _)) = self.resolve_with_disambiguator_cached( + ResolutionInfo { + item_id, + module_id, + dis, + path_str: di_text.clone().into_boxed_str(), + extra_fragment: extra_fragment.clone(), + }, + diag_info.clone(), // this struct should really be Copy, but Range is not :( + // For reference-style links we want to report only one error so unsuccessful + // resolutions are cached, for other links we want to report an error every + // time so they are not cached. + matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), + ) else { + return; + }; + + if &di_res == ex_res { + use crate::lint::REDUNDANT_EXPLICIT_LINKS; + + report_diagnostic( + self.cx.tcx, + REDUNDANT_EXPLICIT_LINKS, + "redundant explicit rustdoc link", + &diag_info, + |diag, sp, _link_range| { + if let Some(sp) = sp { + diag.note("Explicit link does not affect the original link") + .span_suggestion(sp, "Remove explicit link instead", format!("[{}]", ori_link.link), Applicability::MachineApplicable); + } + } + ); + } + } + } } /// Get the section of a link between the backticks, diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.rs b/tests/rustdoc-ui/lints/redundant_explicit_links.rs new file mode 100644 index 000000000000..e794388476be --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.rs @@ -0,0 +1,6 @@ +#![deny(rustdoc::redundant_explicit_links)] + +pub fn dummy_target() {} + +/// [`Vec`](std::vec::Vec) +pub fn c() {} From e94ba4ae78bbca55b14967c05639a7bdf18bab26 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Fri, 18 Aug 2023 00:09:03 +0200 Subject: [PATCH 095/169] Inline strlen_rt in CStr::from_ptr This enables LLVM to optimize this function as if it was strlen without having to enable std-aware LTO. --- library/core/src/ffi/c_str.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 92e38df40498..163a65c909e4 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -253,7 +253,7 @@ impl CStr { /// ``` /// /// [valid]: core::ptr#safety - #[inline] + #[inline] // inline is necessary for codegen to see strlen. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")] @@ -280,6 +280,8 @@ impl CStr { len } + // `inline` is necessary for codegen to see strlen. + #[inline] fn strlen_rt(s: *const c_char) -> usize { extern "C" { /// Provided by libc or compiler_builtins. From 65e24a57bbd510e79d667d5c6e18507895e36447 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 30 Jun 2023 02:01:21 +0800 Subject: [PATCH 096/169] Fix resolution caching --- compiler/rustc_resolve/src/rustdoc.rs | 57 +++++++++-- src/doc/rustdoc/src/lints.md | 26 +++-- src/librustdoc/html/markdown.rs | 1 + .../passes/collect_intra_doc_links.rs | 72 +++++++------- .../lints/redundant_explicit_links.rs | 17 +++- .../lints/redundant_explicit_links.stderr | 97 +++++++++++++++++++ 6 files changed, 217 insertions(+), 53 deletions(-) create mode 100644 tests/rustdoc-ui/lints/redundant_explicit_links.stderr diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index d433391f272e..083d16d3b047 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -392,16 +392,57 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec(doc: &'md str) -> Vec> { + let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into())); + let mut event_iter = Parser::new_with_broken_link_callback( &doc, main_body_opts(), - Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))), + Some(&mut broken_link_callback), ) - .filter_map(|event| match event { - Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { - Some(preprocess_link(&dest)) + .into_iter(); + let mut links = Vec::new(); + + while let Some(event) = event_iter.next() { + match event { + Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + if let Some(display_text) = collect_link_data(&mut event_iter) { + links.push(display_text); + } + + links.push(preprocess_link(&dest)); + } + _ => {} } - _ => None, - }) - .collect() + } + + links +} + +/// Collects additional data of link. +fn collect_link_data<'input, 'callback>( + event_iter: &mut Parser<'input, 'callback>, +) -> Option> { + let mut display_text = None; + + while let Some(event) = event_iter.next() { + match event { + Event::Text(code) => { + display_text = Some(code.to_string().into_boxed_str()); + } + Event::Code(code) => { + display_text = Some(code.to_string().into_boxed_str()); + } + Event::End(_) => { + break; + } + _ => {} + } + } + + display_text } diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index fe06b303e72f..f15e6e451e75 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -420,17 +420,29 @@ as computed automatic links. This usually means the explicit links is removeable. For example: ```rust -#![warn(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::redundant_explicit_links)] // note: unnecessary - warns by default. -pub fn dummy_target() {} // note: unnecessary - warns by default. - -/// [`dummy_target`](dummy_target) -/// [dummy_target](dummy_target) -pub fn c() {} +/// add takes 2 [`usize`](usize) and performs addition +/// on them, then returns result. +pub fn add(left: usize, right: usize) -> usize { + left + right +} ``` Which will give: ```text - +error: redundant explicit rustdoc link + --> src/lib.rs:3:27 + | +3 | /// add takes 2 [`usize`](usize) and performs addition + | ^^^^^ + | + = note: Explicit link does not affect the original link +note: the lint level is defined here + --> src/lib.rs:1:9 + | +1 | #![deny(rustdoc::redundant_explicit_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: Remove explicit link instead ``` diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b5ab8a7b12ac..2fe052283a99 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1421,6 +1421,7 @@ pub(crate) fn markdown_links<'md, R>( links } +/// Collects additional data of link. fn collect_link_data<'input, 'callback>( event_iter: &mut OffsetIter<'input, 'callback>, ) -> Option> { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 78b86cdfa824..2ed0077c3d56 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -994,15 +994,7 @@ impl LinkCollector<'_, '_> { _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), }; for md_link in preprocessed_markdown_links(&doc) { - let PreprocessedMarkdownLink(_pp_link, ori_link) = &md_link; - let diag_info = DiagnosticInfo { - item, - dox: &doc, - ori_link: &ori_link.link, - link_range: ori_link.range.clone(), - }; - - let link = self.resolve_link(item, item_id, module_id, &md_link, &diag_info); + let link = self.resolve_link(&doc, item, item_id, module_id, &md_link); if let Some(link) = link { self.cx.cache.intra_doc_links.entry(item.item_id).or_default().insert(link); } @@ -1015,14 +1007,20 @@ impl LinkCollector<'_, '_> { /// FIXME(jynelson): this is way too many arguments fn resolve_link( &mut self, + dox: &String, item: &Item, item_id: DefId, module_id: DefId, PreprocessedMarkdownLink(pp_link, ori_link): &PreprocessedMarkdownLink, - diag_info: &DiagnosticInfo<'_>, ) -> Option { trace!("considering link '{}'", ori_link.link); + let diag_info = DiagnosticInfo { + item, + dox, + ori_link: &ori_link.link, + link_range: ori_link.range.clone(), + }; let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?; let disambiguator = *disambiguator; @@ -1045,11 +1043,14 @@ impl LinkCollector<'_, '_> { self.check_redundant_explicit_link( &res, path_str, - item_id, - module_id, - disambiguator, + ResolutionInfo { + item_id, + module_id, + dis: disambiguator, + path_str: ori_link.display_text.clone().into_boxed_str(), + extra_fragment: extra_fragment.clone(), + }, &ori_link, - extra_fragment, &diag_info, ); @@ -1384,15 +1385,13 @@ impl LinkCollector<'_, '_> { } } + /// Check if resolution of inline link's display text and explicit link are same. fn check_redundant_explicit_link( &mut self, - ex_res: &Res, - ex: &Box, - item_id: DefId, - module_id: DefId, - dis: Option, + explicit_res: &Res, + explicit_link: &Box, + display_res_info: ResolutionInfo, ori_link: &MarkdownLink, - extra_fragment: &Option, diag_info: &DiagnosticInfo<'_>, ) { // Check if explicit resolution's path is same as resolution of original link's display text path, e.g. @@ -1409,21 +1408,15 @@ impl LinkCollector<'_, '_> { return; } - let di_text = &ori_link.display_text; - let di_len = di_text.len(); - let ex_len = ex.len(); + let display_text = &ori_link.display_text; + let display_len = display_text.len(); + let explicit_len = explicit_link.len(); - let intra_doc_links = std::mem::take(&mut self.cx.cache.intra_doc_links); - - if ex_len >= di_len && &ex[(ex_len - di_len)..] == di_text { - let Some((di_res, _)) = self.resolve_with_disambiguator_cached( - ResolutionInfo { - item_id, - module_id, - dis, - path_str: di_text.clone().into_boxed_str(), - extra_fragment: extra_fragment.clone(), - }, + if explicit_len >= display_len + && &explicit_link[(explicit_len - display_len)..] == display_text + { + let Some((display_res, _)) = self.resolve_with_disambiguator_cached( + display_res_info, diag_info.clone(), // this struct should really be Copy, but Range is not :( // For reference-style links we want to report only one error so unsuccessful // resolutions are cached, for other links we want to report an error every @@ -1433,7 +1426,7 @@ impl LinkCollector<'_, '_> { return; }; - if &di_res == ex_res { + if &display_res == explicit_res { use crate::lint::REDUNDANT_EXPLICIT_LINKS; report_diagnostic( @@ -1444,9 +1437,14 @@ impl LinkCollector<'_, '_> { |diag, sp, _link_range| { if let Some(sp) = sp { diag.note("Explicit link does not affect the original link") - .span_suggestion(sp, "Remove explicit link instead", format!("[{}]", ori_link.link), Applicability::MachineApplicable); + .span_suggestion_hidden( + sp, + "Remove explicit link instead", + format!(""), + Applicability::MachineApplicable, + ); } - } + }, ); } } diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.rs b/tests/rustdoc-ui/lints/redundant_explicit_links.rs index e794388476be..d33396f68109 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.rs @@ -2,5 +2,20 @@ pub fn dummy_target() {} +/// [dummy_target](dummy_target) +/// [`dummy_target`](dummy_target) +/// [Vec](Vec) +/// [`Vec`](Vec) +/// [Vec](std::vec::Vec) /// [`Vec`](std::vec::Vec) -pub fn c() {} +/// [std::vec::Vec](std::vec::Vec) +/// [`std::vec::Vec`](std::vec::Vec) +/// [usize](usize) +/// [`usize`](usize) +/// [std::primitive::usize](usize) +/// [`std::primitive::usize`](usize) +pub fn should_warn() {} + +/// [`Vec`](Vec) +/// [`Vec`](std::vec::Vec) +pub fn should_not_warn() {} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr new file mode 100644 index 000000000000..4ca427d62ce1 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr @@ -0,0 +1,97 @@ +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:5:20 + | +LL | /// [dummy_target](dummy_target) + | ^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link +note: the lint level is defined here + --> $DIR/redundant_explicit_links.rs:1:9 + | +LL | #![deny(rustdoc::redundant_explicit_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:6:22 + | +LL | /// [`dummy_target`](dummy_target) + | ^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:7:11 + | +LL | /// [Vec](Vec) + | ^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:8:13 + | +LL | /// [`Vec`](Vec) + | ^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:9:11 + | +LL | /// [Vec](std::vec::Vec) + | ^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:10:13 + | +LL | /// [`Vec`](std::vec::Vec) + | ^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:11:21 + | +LL | /// [std::vec::Vec](std::vec::Vec) + | ^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:12:23 + | +LL | /// [`std::vec::Vec`](std::vec::Vec) + | ^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:13:13 + | +LL | /// [usize](usize) + | ^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:14:15 + | +LL | /// [`usize`](usize) + | ^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: aborting due to 10 previous errors + From 1c6b237f9e360356f2b0b3712f83e91a53ddbe86 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 30 Jun 2023 02:08:37 +0800 Subject: [PATCH 097/169] add more tests --- src/librustdoc/passes/collect_intra_doc_links.rs | 2 +- tests/rustdoc-ui/lints/redundant_explicit_links.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 2ed0077c3d56..d78fec2cb0ab 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1421,7 +1421,7 @@ impl LinkCollector<'_, '_> { // For reference-style links we want to report only one error so unsuccessful // resolutions are cached, for other links we want to report an error every // time so they are not cached. - matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), + matches!(ori_link.kind, LinkType::Reference), ) else { return; }; diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.rs b/tests/rustdoc-ui/lints/redundant_explicit_links.rs index d33396f68109..a78b4837b26a 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.rs @@ -4,16 +4,24 @@ pub fn dummy_target() {} /// [dummy_target](dummy_target) /// [`dummy_target`](dummy_target) +/// /// [Vec](Vec) /// [`Vec`](Vec) /// [Vec](std::vec::Vec) /// [`Vec`](std::vec::Vec) +/// [std::vec::Vec](Vec) +/// [`std::vec::Vec`](Vec) /// [std::vec::Vec](std::vec::Vec) /// [`std::vec::Vec`](std::vec::Vec) +/// /// [usize](usize) /// [`usize`](usize) +/// [usize](std::primitive::usize) +/// [`usize`](std::primitive::usize) /// [std::primitive::usize](usize) /// [`std::primitive::usize`](usize) +/// [std::primitive::usize](std::primitive::usize) +/// [`std::primitive::usize`](std::primitive::usize) pub fn should_warn() {} /// [`Vec`](Vec) From f1b23f29db326292e8f61f63b69725c79a328bac Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 30 Jun 2023 02:10:55 +0800 Subject: [PATCH 098/169] bless test output --- .../lints/redundant_explicit_links.stderr | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr index 4ca427d62ce1..e72105f394f5 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.stderr +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr @@ -22,7 +22,7 @@ LL | /// [`dummy_target`](dummy_target) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:7:11 + --> $DIR/redundant_explicit_links.rs:8:11 | LL | /// [Vec](Vec) | ^^^ @@ -31,7 +31,7 @@ LL | /// [Vec](Vec) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:8:13 + --> $DIR/redundant_explicit_links.rs:9:13 | LL | /// [`Vec`](Vec) | ^^^ @@ -40,7 +40,7 @@ LL | /// [`Vec`](Vec) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:9:11 + --> $DIR/redundant_explicit_links.rs:10:11 | LL | /// [Vec](std::vec::Vec) | ^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | /// [Vec](std::vec::Vec) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:10:13 + --> $DIR/redundant_explicit_links.rs:11:13 | LL | /// [`Vec`](std::vec::Vec) | ^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | /// [`Vec`](std::vec::Vec) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:11:21 + --> $DIR/redundant_explicit_links.rs:14:21 | LL | /// [std::vec::Vec](std::vec::Vec) | ^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL | /// [std::vec::Vec](std::vec::Vec) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:12:23 + --> $DIR/redundant_explicit_links.rs:15:23 | LL | /// [`std::vec::Vec`](std::vec::Vec) | ^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | /// [`std::vec::Vec`](std::vec::Vec) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:13:13 + --> $DIR/redundant_explicit_links.rs:17:13 | LL | /// [usize](usize) | ^^^^^ @@ -85,7 +85,7 @@ LL | /// [usize](usize) = help: Remove explicit link instead error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:14:15 + --> $DIR/redundant_explicit_links.rs:18:15 | LL | /// [`usize`](usize) | ^^^^^ @@ -93,5 +93,41 @@ LL | /// [`usize`](usize) = note: Explicit link does not affect the original link = help: Remove explicit link instead -error: aborting due to 10 previous errors +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:19:13 + | +LL | /// [usize](std::primitive::usize) + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:20:15 + | +LL | /// [`usize`](std::primitive::usize) + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:23:29 + | +LL | /// [std::primitive::usize](std::primitive::usize) + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: redundant explicit rustdoc link + --> $DIR/redundant_explicit_links.rs:24:31 + | +LL | /// [`std::primitive::usize`](std::primitive::usize) + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: Explicit link does not affect the original link + = help: Remove explicit link instead + +error: aborting due to 14 previous errors From e583318aa864ce0a3d53c339600d51a70d7b6440 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 30 Jun 2023 02:35:44 +0800 Subject: [PATCH 099/169] fix trailing whitespace --- tests/rustdoc-ui/lints/redundant_explicit_links.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.rs b/tests/rustdoc-ui/lints/redundant_explicit_links.rs index a78b4837b26a..b3203a2690f0 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.rs @@ -4,7 +4,7 @@ pub fn dummy_target() {} /// [dummy_target](dummy_target) /// [`dummy_target`](dummy_target) -/// +/// /// [Vec](Vec) /// [`Vec`](Vec) /// [Vec](std::vec::Vec) @@ -13,7 +13,7 @@ pub fn dummy_target() {} /// [`std::vec::Vec`](Vec) /// [std::vec::Vec](std::vec::Vec) /// [`std::vec::Vec`](std::vec::Vec) -/// +/// /// [usize](usize) /// [`usize`](usize) /// [usize](std::primitive::usize) From c7369891ba3265e47346bf44d6f5b5bf4451f3ca Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 30 Jun 2023 18:10:01 +0800 Subject: [PATCH 100/169] Refactor lint from rustc to rustdoc --- .../passes/collect_intra_doc_links.rs | 30 +- src/librustdoc/passes/lint.rs | 2 + .../passes/lint/redundant_explicit_links.rs | 188 +++++++++++ .../lints/redundant_explicit_links.fixed | 54 +++ .../lints/redundant_explicit_links.rs | 29 +- .../lints/redundant_explicit_links.stderr | 318 ++++++++++++++---- 6 files changed, 519 insertions(+), 102 deletions(-) create mode 100644 src/librustdoc/passes/lint/redundant_explicit_links.rs create mode 100644 tests/rustdoc-ui/lints/redundant_explicit_links.fixed diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d78fec2cb0ab..0432bd40c903 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1041,7 +1041,6 @@ impl LinkCollector<'_, '_> { )?; self.check_redundant_explicit_link( - &res, path_str, ResolutionInfo { item_id, @@ -1388,7 +1387,6 @@ impl LinkCollector<'_, '_> { /// Check if resolution of inline link's display text and explicit link are same. fn check_redundant_explicit_link( &mut self, - explicit_res: &Res, explicit_link: &Box, display_res_info: ResolutionInfo, ori_link: &MarkdownLink, @@ -1415,38 +1413,14 @@ impl LinkCollector<'_, '_> { if explicit_len >= display_len && &explicit_link[(explicit_len - display_len)..] == display_text { - let Some((display_res, _)) = self.resolve_with_disambiguator_cached( + self.resolve_with_disambiguator_cached( display_res_info, diag_info.clone(), // this struct should really be Copy, but Range is not :( // For reference-style links we want to report only one error so unsuccessful // resolutions are cached, for other links we want to report an error every // time so they are not cached. matches!(ori_link.kind, LinkType::Reference), - ) else { - return; - }; - - if &display_res == explicit_res { - use crate::lint::REDUNDANT_EXPLICIT_LINKS; - - report_diagnostic( - self.cx.tcx, - REDUNDANT_EXPLICIT_LINKS, - "redundant explicit rustdoc link", - &diag_info, - |diag, sp, _link_range| { - if let Some(sp) = sp { - diag.note("Explicit link does not affect the original link") - .span_suggestion_hidden( - sp, - "Remove explicit link instead", - format!(""), - Applicability::MachineApplicable, - ); - } - }, - ); - } + ); } } } diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs index e653207b9b6d..c6d5b7bd346d 100644 --- a/src/librustdoc/passes/lint.rs +++ b/src/librustdoc/passes/lint.rs @@ -4,6 +4,7 @@ mod bare_urls; mod check_code_block_syntax; mod html_tags; +mod redundant_explicit_links; mod unescaped_backticks; use super::Pass; @@ -29,6 +30,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> { check_code_block_syntax::visit_item(self.cx, item); html_tags::visit_item(self.cx, item); unescaped_backticks::visit_item(self.cx, item); + redundant_explicit_links::visit_item(self.cx, item); self.visit_item_recur(item) } diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs new file mode 100644 index 000000000000..1bccedde92a2 --- /dev/null +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -0,0 +1,188 @@ +use std::ops::Range; + +use pulldown_cmark::{Parser, BrokenLink, Event, Tag, LinkType, OffsetIter}; +use rustc_ast::NodeId; +use rustc_errors::SuggestionStyle; +use rustc_hir::HirId; +use rustc_hir::def::{Namespace, DefKind, DocLinkResMap, Res}; +use rustc_lint_defs::Applicability; +use rustc_span::Symbol; + +use crate::clean::Item; +use crate::clean::utils::find_nearest_parent_module; +use crate::core::DocContext; +use crate::html::markdown::main_body_opts; +use crate::passes::source_span_for_markdown_range; + +struct LinkData { + resolvable_link: Option, + resolvable_link_range: Option>, + display_link: String, +} + +pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { + let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) else { + // If non-local, no need to check anything. + return; + }; + + let doc = item.doc_value(); + if doc.is_empty() { + return; + } + + check_redundant_explicit_link(cx, item, hir_id, &doc); +} + +fn check_redundant_explicit_link<'md>(cx: &DocContext<'_>, item: &Item, hir_id: HirId, doc: &'md str) { + let mut broken_line_callback = |link: BrokenLink<'md>| Some((link.reference, "".into())); + let mut offset_iter = Parser::new_with_broken_link_callback(&doc, main_body_opts(), Some(&mut broken_line_callback)).into_offset_iter(); + + while let Some((event, link_range)) = offset_iter.next() { + match event { + Event::Start(Tag::Link(link_type, dest, _)) => { + let link_data = collect_link_data(&mut offset_iter); + let dest = dest.to_string(); + + if link_type == LinkType::Inline { + check_inline_link_redundancy(cx, item, hir_id, doc, link_range, dest, link_data); + } + } + _ => {} + } + } +} + +fn check_inline_link_redundancy(cx: &DocContext<'_>, item: &Item, hir_id: HirId, doc: &str, link_range: Range, dest: String, link_data: LinkData) -> Option<()> { + let item_id = item.def_id()?; + let module_id = match cx.tcx.def_kind(item_id) { + DefKind::Mod if item.inner_docs(cx.tcx) => item_id, + _ => find_nearest_parent_module(cx.tcx, item_id).unwrap(), + }; + let resolutions = cx.tcx.doc_link_resolutions(module_id); + + let (resolvable_link, resolvable_link_range) = (&link_data.resolvable_link?, &link_data.resolvable_link_range?); + let (dest_res, display_res) = (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); + + if dest_res == display_res { + let link_span = source_span_for_markdown_range( + cx.tcx, + &doc, + &link_range, + &item.attrs, + ).unwrap_or(item.attr_span(cx.tcx)); + let explicit_span = source_span_for_markdown_range( + cx.tcx, + &doc, + &offset_explicit_range(doc, &link_range, b'(', b')'), + &item.attrs + )?; + let display_span = source_span_for_markdown_range( + cx.tcx, + &doc, + &resolvable_link_range, + &item.attrs + )?; + + + cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { + lint.span_label(explicit_span, "explicit target is redundant") + .span_label(display_span, "because label contains path that resolves to same destination") + .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") + .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); + + lint + }); + } + + None +} + +fn find_resolution<'tcx>(resolutions: &'tcx DocLinkResMap, path: &str) -> Option<&'tcx Res> { + for ns in [Namespace::TypeNS, Namespace::ValueNS, Namespace::MacroNS] { + let Some(Some(res)) = resolutions.get(&(Symbol::intern(path), ns)) + else { + continue; + }; + + return Some(res); + } + + None +} + +/// Collects all neccessary data of link. +fn collect_link_data(offset_iter: &mut OffsetIter<'_, '_>) -> LinkData { + let mut resolvable_link = None; + let mut resolvable_link_range = None; + let mut display_link = String::new(); + + while let Some((event, range)) = offset_iter.next() { + match event { + Event::Text(code) => { + let code = code.to_string(); + display_link.push_str(&code); + resolvable_link = Some(code); + resolvable_link_range = Some(range); + } + Event::Code(code) => { + let code = code.to_string(); + display_link.push('`'); + display_link.push_str(&code); + display_link.push('`'); + resolvable_link = Some(code); + resolvable_link_range = Some(range); + } + Event::End(_) => { + break; + } + _ => {} + } + } + + LinkData { + resolvable_link, + resolvable_link_range, + display_link, + } +} + +fn offset_explicit_range(md: &str, link_range: &Range, open: u8, close: u8) -> Range { + let mut open_brace = !0; + let mut close_brace = !0; + for (i, b) in md.as_bytes()[link_range.clone()].iter().copied().enumerate().rev() { + let i = i + link_range.start; + if b == close { + close_brace = i; + break; + } + } + + if close_brace < link_range.start || close_brace >= link_range.end { + return link_range.clone(); + } + + let mut nesting = 1; + + for (i, b) in md.as_bytes()[link_range.start..close_brace].iter().copied().enumerate().rev() { + let i = i + link_range.start; + if b == close { + nesting += 1; + } + if b == open { + nesting -= 1; + } + if nesting == 0 { + open_brace = i; + break; + } + } + + assert!(open_brace != close_brace); + + if open_brace < link_range.start || open_brace >= link_range.end { + return link_range.clone(); + } + // do not actually include braces in the span + (open_brace + 1)..close_brace +} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.fixed b/tests/rustdoc-ui/lints/redundant_explicit_links.fixed new file mode 100644 index 000000000000..6759ee100491 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.fixed @@ -0,0 +1,54 @@ +// run-rustfix + +#![deny(rustdoc::redundant_explicit_links)] + +pub fn dummy_target() {} + +/// [dummy_target] +//~^ ERROR redundant explicit link target +/// [`dummy_target`] +//~^ ERROR redundant explicit link target +/// +/// [Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`] +//~^ ERROR redundant explicit link target +/// [Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`] +//~^ ERROR redundant explicit link target +/// +/// [usize] +//~^ ERROR redundant explicit link target +/// [`usize`] +//~^ ERROR redundant explicit link target +/// [usize] +//~^ ERROR redundant explicit link target +/// [`usize`] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`] +//~^ ERROR redundant explicit link target +/// +/// [dummy_target] TEXT +//~^ ERROR redundant explicit link target +/// [`dummy_target`] TEXT +//~^ ERROR redundant explicit link target +pub fn should_warn_inline() {} + +/// [`Vec`](Vec) +/// [`Vec`](std::vec::Vec) +pub fn should_not_warn_inline() {} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.rs b/tests/rustdoc-ui/lints/redundant_explicit_links.rs index b3203a2690f0..7c30b15d993d 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.rs @@ -1,29 +1,54 @@ +// run-rustfix + #![deny(rustdoc::redundant_explicit_links)] pub fn dummy_target() {} /// [dummy_target](dummy_target) +//~^ ERROR redundant explicit link target /// [`dummy_target`](dummy_target) +//~^ ERROR redundant explicit link target /// /// [Vec](Vec) +//~^ ERROR redundant explicit link target /// [`Vec`](Vec) +//~^ ERROR redundant explicit link target /// [Vec](std::vec::Vec) +//~^ ERROR redundant explicit link target /// [`Vec`](std::vec::Vec) +//~^ ERROR redundant explicit link target /// [std::vec::Vec](Vec) +//~^ ERROR redundant explicit link target /// [`std::vec::Vec`](Vec) +//~^ ERROR redundant explicit link target /// [std::vec::Vec](std::vec::Vec) +//~^ ERROR redundant explicit link target /// [`std::vec::Vec`](std::vec::Vec) +//~^ ERROR redundant explicit link target /// /// [usize](usize) +//~^ ERROR redundant explicit link target /// [`usize`](usize) +//~^ ERROR redundant explicit link target /// [usize](std::primitive::usize) +//~^ ERROR redundant explicit link target /// [`usize`](std::primitive::usize) +//~^ ERROR redundant explicit link target /// [std::primitive::usize](usize) +//~^ ERROR redundant explicit link target /// [`std::primitive::usize`](usize) +//~^ ERROR redundant explicit link target /// [std::primitive::usize](std::primitive::usize) +//~^ ERROR redundant explicit link target /// [`std::primitive::usize`](std::primitive::usize) -pub fn should_warn() {} +//~^ ERROR redundant explicit link target +/// +/// [dummy_target](dummy_target) TEXT +//~^ ERROR redundant explicit link target +/// [`dummy_target`](dummy_target) TEXT +//~^ ERROR redundant explicit link target +pub fn should_warn_inline() {} /// [`Vec`](Vec) /// [`Vec`](std::vec::Vec) -pub fn should_not_warn() {} +pub fn should_not_warn_inline() {} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr index e72105f394f5..3f10a2e662d6 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.stderr +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr @@ -1,133 +1,307 @@ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:5:20 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:7:20 | LL | /// [dummy_target](dummy_target) - | ^^^^^^^^^^^^ + | ------------ ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links note: the lint level is defined here - --> $DIR/redundant_explicit_links.rs:1:9 + --> $DIR/redundant_explicit_links.rs:3:9 | LL | #![deny(rustdoc::redundant_explicit_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: Remove explicit link instead +help: remove explicit link target + | +LL | /// [dummy_target] + | ~~~~~~~~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:6:22 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:9:22 | LL | /// [`dummy_target`](dummy_target) - | ^^^^^^^^^^^^ + | -------------- ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`dummy_target`] + | ~~~~~~~~~~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:8:11 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:12:11 | LL | /// [Vec](Vec) - | ^^^ + | --- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [Vec] + | ~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:9:13 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:14:13 | LL | /// [`Vec`](Vec) - | ^^^ + | ----- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`Vec`] + | ~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:10:11 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:16:11 | LL | /// [Vec](std::vec::Vec) - | ^^^^^^^^^^^^^ + | --- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [Vec] + | ~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:11:13 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:18:13 | LL | /// [`Vec`](std::vec::Vec) - | ^^^^^^^^^^^^^ + | ----- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`Vec`] + | ~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:14:21 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:20:21 + | +LL | /// [std::vec::Vec](Vec) + | ------------- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::vec::Vec] + | ~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:22:23 + | +LL | /// [`std::vec::Vec`](Vec) + | --------------- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::vec::Vec`] + | ~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:24:21 | LL | /// [std::vec::Vec](std::vec::Vec) - | ^^^^^^^^^^^^^ + | ------------- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::vec::Vec] + | ~~~~~~~~~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:15:23 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:26:23 | LL | /// [`std::vec::Vec`](std::vec::Vec) - | ^^^^^^^^^^^^^ + | --------------- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::vec::Vec`] + | ~~~~~~~~~~~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:17:13 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:29:13 | LL | /// [usize](usize) - | ^^^^^ + | ----- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [usize] + | ~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:18:15 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:31:15 | LL | /// [`usize`](usize) - | ^^^^^ + | ------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`usize`] + | ~~~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:19:13 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:33:13 | LL | /// [usize](std::primitive::usize) - | ^^^^^^^^^^^^^^^^^^^^^ + | ----- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [usize] + | ~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:20:15 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:35:15 | LL | /// [`usize`](std::primitive::usize) - | ^^^^^^^^^^^^^^^^^^^^^ + | ------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`usize`] + | ~~~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:23:29 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:37:29 + | +LL | /// [std::primitive::usize](usize) + | --------------------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::primitive::usize] + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:39:31 + | +LL | /// [`std::primitive::usize`](usize) + | ----------------------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::primitive::usize`] + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:41:29 | LL | /// [std::primitive::usize](std::primitive::usize) - | ^^^^^^^^^^^^^^^^^^^^^ + | --------------------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::primitive::usize] + | ~~~~~~~~~~~~~~~~~~~~~~~ -error: redundant explicit rustdoc link - --> $DIR/redundant_explicit_links.rs:24:31 +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:43:31 | LL | /// [`std::primitive::usize`](std::primitive::usize) - | ^^^^^^^^^^^^^^^^^^^^^ + | ----------------------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination | - = note: Explicit link does not affect the original link - = help: Remove explicit link instead + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::primitive::usize`] + | ~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 14 previous errors +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:46:20 + | +LL | /// [dummy_target](dummy_target) TEXT + | ------------ ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [dummy_target] TEXT + | ~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:48:22 + | +LL | /// [`dummy_target`](dummy_target) TEXT + | -------------- ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`dummy_target`] TEXT + | ~~~~~~~~~~~~~~~~ + +error: aborting due to 20 previous errors From 46df95817d2f9700f0c5a69ea8b05b1c83d9ee35 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 30 Jun 2023 22:48:20 +0800 Subject: [PATCH 101/169] Support Reference & ReferenceUnknown link lint --- .../passes/collect_intra_doc_links.rs | 71 +- .../passes/lint/redundant_explicit_links.rs | 221 ++++-- .../lints/redundant_explicit_links.fixed | 104 +++ .../lints/redundant_explicit_links.rs | 104 +++ .../lints/redundant_explicit_links.stderr | 702 +++++++++++++++++- 5 files changed, 1135 insertions(+), 67 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0432bd40c903..0a0ffcb5b1ec 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1040,7 +1040,7 @@ impl LinkCollector<'_, '_> { matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), )?; - self.check_redundant_explicit_link( + self.resolve_display_text( path_str, ResolutionInfo { item_id, @@ -1384,8 +1384,12 @@ impl LinkCollector<'_, '_> { } } - /// Check if resolution of inline link's display text and explicit link are same. - fn check_redundant_explicit_link( + /// Resolve display text if the provided link has separated parts of links. + /// + /// For example: + /// Inline link `[display_text](dest_link)` and reference link `[display_text][reference_link]` has + /// separated parts of links. + fn resolve_display_text( &mut self, explicit_link: &Box, display_res_info: ResolutionInfo, @@ -1393,33 +1397,80 @@ impl LinkCollector<'_, '_> { diag_info: &DiagnosticInfo<'_>, ) { // Check if explicit resolution's path is same as resolution of original link's display text path, e.g. + // + // LinkType::Inline: + // // [target](target) // [`target`](target) // [target](path::to::target) // [`target`](path::to::target) + // [path::to::target](target) + // [`path::to::target`](target) // [path::to::target](path::to::target) // [`path::to::target`](path::to::target) // + // LinkType::ReferenceUnknown + // + // [target][target] + // [`target`][target] + // [target][path::to::target] + // [`target`][path::to::target] + // [path::to::target][target] + // [`path::to::target`][target] + // [path::to::target][path::to::target] + // [`path::to::target`][path::to::target] + // + // LinkType::Reference + // + // [target][target] + // [`target`][target] + // [target][path::to::target] + // [`target`][path::to::target] + // [path::to::target][target] + // [`path::to::target`][target] + // [path::to::target][path::to::target] + // [`path::to::target`][path::to::target] + // + // [target]: target // or [target]: path::to::target + // [path::to::target]: path::to::target // or [path::to::target]: target + // // To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated // into explicit path. - if ori_link.kind != LinkType::Inline { + if !matches!( + ori_link.kind, + LinkType::Inline | LinkType::Reference | LinkType::ReferenceUnknown + ) { return; } + // Algorithm to check if display text could possibly be the explicit link: + // + // Consider 2 links which are display text and explicit link, pick the shorter + // one as symbol and longer one as full qualified path, and tries to match symbol + // to the full qualified path's last symbol. + // + // Otherwise, check if 2 links are same, if so, skip the resolve process. + // + // Notice that this algorithm is passive, might possibly miss actual redudant cases. + let explicit_link = &explicit_link.to_string(); let display_text = &ori_link.display_text; let display_len = display_text.len(); let explicit_len = explicit_link.len(); - if explicit_len >= display_len - && &explicit_link[(explicit_len - display_len)..] == display_text + if display_len == explicit_len { + // Whether they are same or not, skip the resolve process. + return; + } + + if (explicit_len >= display_len + && &explicit_link[(explicit_len - display_len)..] == display_text) + || (display_len >= explicit_len + && &display_text[(display_len - explicit_len)..] == explicit_link) { self.resolve_with_disambiguator_cached( display_res_info, diag_info.clone(), // this struct should really be Copy, but Range is not :( - // For reference-style links we want to report only one error so unsuccessful - // resolutions are cached, for other links we want to report an error every - // time so they are not cached. - matches!(ori_link.kind, LinkType::Reference), + false, ); } } diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 1bccedde92a2..722088eb79aa 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -1,19 +1,20 @@ use std::ops::Range; -use pulldown_cmark::{Parser, BrokenLink, Event, Tag, LinkType, OffsetIter}; +use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, OffsetIter, Parser, Tag}; use rustc_ast::NodeId; use rustc_errors::SuggestionStyle; +use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; use rustc_hir::HirId; -use rustc_hir::def::{Namespace, DefKind, DocLinkResMap, Res}; use rustc_lint_defs::Applicability; use rustc_span::Symbol; -use crate::clean::Item; use crate::clean::utils::find_nearest_parent_module; +use crate::clean::Item; use crate::core::DocContext; use crate::html::markdown::main_body_opts; use crate::passes::source_span_for_markdown_range; +#[derive(Debug)] struct LinkData { resolvable_link: Option, resolvable_link_range: Option>, @@ -34,56 +35,91 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { check_redundant_explicit_link(cx, item, hir_id, &doc); } -fn check_redundant_explicit_link<'md>(cx: &DocContext<'_>, item: &Item, hir_id: HirId, doc: &'md str) { +fn check_redundant_explicit_link<'md>( + cx: &DocContext<'_>, + item: &Item, + hir_id: HirId, + doc: &'md str, +) -> Option<()> { let mut broken_line_callback = |link: BrokenLink<'md>| Some((link.reference, "".into())); - let mut offset_iter = Parser::new_with_broken_link_callback(&doc, main_body_opts(), Some(&mut broken_line_callback)).into_offset_iter(); - - while let Some((event, link_range)) = offset_iter.next() { - match event { - Event::Start(Tag::Link(link_type, dest, _)) => { - let link_data = collect_link_data(&mut offset_iter); - let dest = dest.to_string(); - - if link_type == LinkType::Inline { - check_inline_link_redundancy(cx, item, hir_id, doc, link_range, dest, link_data); - } - } - _ => {} - } - } -} - -fn check_inline_link_redundancy(cx: &DocContext<'_>, item: &Item, hir_id: HirId, doc: &str, link_range: Range, dest: String, link_data: LinkData) -> Option<()> { + let mut offset_iter = Parser::new_with_broken_link_callback( + &doc, + main_body_opts(), + Some(&mut broken_line_callback), + ) + .into_offset_iter(); let item_id = item.def_id()?; let module_id = match cx.tcx.def_kind(item_id) { DefKind::Mod if item.inner_docs(cx.tcx) => item_id, _ => find_nearest_parent_module(cx.tcx, item_id).unwrap(), }; let resolutions = cx.tcx.doc_link_resolutions(module_id); - - let (resolvable_link, resolvable_link_range) = (&link_data.resolvable_link?, &link_data.resolvable_link_range?); - let (dest_res, display_res) = (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); + + while let Some((event, link_range)) = offset_iter.next() { + match event { + Event::Start(Tag::Link(link_type, dest, _)) => match link_type { + LinkType::Inline | LinkType::ReferenceUnknown => { + check_inline_or_reference_unknown_redundancy( + cx, + item, + hir_id, + doc, + resolutions, + link_range, + dest.to_string(), + collect_link_data(&mut offset_iter), + if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') }, + ); + } + LinkType::Reference => { + check_reference_redundancy( + cx, + item, + hir_id, + doc, + resolutions, + link_range, + &dest, + collect_link_data(&mut offset_iter), + ); + } + _ => {} + }, + _ => {} + } + } + + None +} + +/// FIXME(ChAoSUnItY): Too many arguments. +fn check_inline_or_reference_unknown_redundancy( + cx: &DocContext<'_>, + item: &Item, + hir_id: HirId, + doc: &str, + resolutions: &DocLinkResMap, + link_range: Range, + dest: String, + link_data: LinkData, + (open, close): (u8, u8), +) -> Option<()> { + let (resolvable_link, resolvable_link_range) = + (&link_data.resolvable_link?, &link_data.resolvable_link_range?); + let (dest_res, display_res) = + (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); if dest_res == display_res { - let link_span = source_span_for_markdown_range( - cx.tcx, - &doc, - &link_range, - &item.attrs, - ).unwrap_or(item.attr_span(cx.tcx)); + let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs) + .unwrap_or(item.attr_span(cx.tcx)); let explicit_span = source_span_for_markdown_range( cx.tcx, &doc, - &offset_explicit_range(doc, &link_range, b'(', b')'), - &item.attrs + &offset_explicit_range(doc, link_range, open, close), + &item.attrs, )?; - let display_span = source_span_for_markdown_range( - cx.tcx, - &doc, - &resolvable_link_range, - &item.attrs - )?; - + let display_span = + source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?; cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { lint.span_label(explicit_span, "explicit target is redundant") @@ -98,25 +134,66 @@ fn check_inline_link_redundancy(cx: &DocContext<'_>, item: &Item, hir_id: HirId, None } -fn find_resolution<'tcx>(resolutions: &'tcx DocLinkResMap, path: &str) -> Option<&'tcx Res> { - for ns in [Namespace::TypeNS, Namespace::ValueNS, Namespace::MacroNS] { - let Some(Some(res)) = resolutions.get(&(Symbol::intern(path), ns)) - else { - continue; - }; +/// FIXME(ChAoSUnItY): Too many arguments. +fn check_reference_redundancy( + cx: &DocContext<'_>, + item: &Item, + hir_id: HirId, + doc: &str, + resolutions: &DocLinkResMap, + link_range: Range, + dest: &CowStr<'_>, + link_data: LinkData, +) -> Option<()> { + let (resolvable_link, resolvable_link_range) = + (&link_data.resolvable_link?, &link_data.resolvable_link_range?); + let (dest_res, display_res) = + (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); - return Some(res); + if dest_res == display_res { + let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs) + .unwrap_or(item.attr_span(cx.tcx)); + let explicit_span = source_span_for_markdown_range( + cx.tcx, + &doc, + &offset_explicit_range(doc, link_range.clone(), b'[', b']'), + &item.attrs, + )?; + let display_span = + source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?; + let def_span = source_span_for_markdown_range( + cx.tcx, + &doc, + &offset_reference_def_range(doc, dest, link_range), + &item.attrs, + )?; + + cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { + lint.span_label(explicit_span, "explicit target is redundant") + .span_label(display_span, "because label contains path that resolves to same destination") + .span_note(def_span, "referenced explicit link target defined here") + .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") + .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); + + lint + }); } None } +fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option> { + [Namespace::TypeNS, Namespace::ValueNS, Namespace::MacroNS] + .into_iter() + .find_map(|ns| resolutions.get(&(Symbol::intern(path), ns)).copied().flatten()) +} + /// Collects all neccessary data of link. fn collect_link_data(offset_iter: &mut OffsetIter<'_, '_>) -> LinkData { let mut resolvable_link = None; let mut resolvable_link_range = None; let mut display_link = String::new(); - + while let Some((event, range)) = offset_iter.next() { match event { Event::Text(code) => { @@ -140,14 +217,10 @@ fn collect_link_data(offset_iter: &mut OffsetIter<'_, '_>) -> LinkData { } } - LinkData { - resolvable_link, - resolvable_link_range, - display_link, - } + LinkData { resolvable_link, resolvable_link_range, display_link } } -fn offset_explicit_range(md: &str, link_range: &Range, open: u8, close: u8) -> Range { +fn offset_explicit_range(md: &str, link_range: Range, open: u8, close: u8) -> Range { let mut open_brace = !0; let mut close_brace = !0; for (i, b) in md.as_bytes()[link_range.clone()].iter().copied().enumerate().rev() { @@ -159,7 +232,7 @@ fn offset_explicit_range(md: &str, link_range: &Range, open: u8, close: u } if close_brace < link_range.start || close_brace >= link_range.end { - return link_range.clone(); + return link_range; } let mut nesting = 1; @@ -181,8 +254,44 @@ fn offset_explicit_range(md: &str, link_range: &Range, open: u8, close: u assert!(open_brace != close_brace); if open_brace < link_range.start || open_brace >= link_range.end { - return link_range.clone(); + return link_range; } // do not actually include braces in the span (open_brace + 1)..close_brace } + +fn offset_reference_def_range( + md: &str, + dest: &CowStr<'_>, + link_range: Range, +) -> Range { + // For diagnostics, we want to underline the link's definition but `span` will point at + // where the link is used. This is a problem for reference-style links, where the definition + // is separate from the usage. + + match dest { + // `Borrowed` variant means the string (the link's destination) may come directly from + // the markdown text and we can locate the original link destination. + // NOTE: LinkReplacer also provides `Borrowed` but possibly from other sources, + // so `locate()` can fall back to use `span`. + CowStr::Borrowed(s) => { + // FIXME: remove this function once pulldown_cmark can provide spans for link definitions. + unsafe { + let s_start = dest.as_ptr(); + let s_end = s_start.add(s.len()); + let md_start = md.as_ptr(); + let md_end = md_start.add(md.len()); + if md_start <= s_start && s_end <= md_end { + let start = s_start.offset_from(md_start) as usize; + let end = s_end.offset_from(md_start) as usize; + start..end + } else { + link_range + } + } + } + + // For anything else, we can only use the provided range. + CowStr::Boxed(_) | CowStr::Inlined(_) => link_range, + } +} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.fixed b/tests/rustdoc-ui/lints/redundant_explicit_links.fixed index 6759ee100491..4745da879a35 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.fixed +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.fixed @@ -52,3 +52,107 @@ pub fn should_warn_inline() {} /// [`Vec`](Vec) /// [`Vec`](std::vec::Vec) pub fn should_not_warn_inline() {} + +/// [dummy_target] +//~^ ERROR redundant explicit link target +/// [`dummy_target`] +//~^ ERROR redundant explicit link target +/// +/// [Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`] +//~^ ERROR redundant explicit link target +/// [Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`] +//~^ ERROR redundant explicit link target +/// +/// [usize] +//~^ ERROR redundant explicit link target +/// [`usize`] +//~^ ERROR redundant explicit link target +/// [usize] +//~^ ERROR redundant explicit link target +/// [`usize`] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`] +//~^ ERROR redundant explicit link target +/// +/// [dummy_target] TEXT +//~^ ERROR redundant explicit link target +/// [`dummy_target`] TEXT +//~^ ERROR redundant explicit link target +pub fn should_warn_reference_unknown() {} + +/// [`Vec`][Vec] +/// [`Vec`][std::vec::Vec] +pub fn should_not_warn_reference_unknown() {} + +/// [dummy_target] +//~^ ERROR redundant explicit link target +/// [`dummy_target`] +//~^ ERROR redundant explicit link target +/// +/// [Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`] +//~^ ERROR redundant explicit link target +/// [Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`] +//~^ ERROR redundant explicit link target +/// +/// [usize] +//~^ ERROR redundant explicit link target +/// [`usize`] +//~^ ERROR redundant explicit link target +/// [usize] +//~^ ERROR redundant explicit link target +/// [`usize`] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`] +//~^ ERROR redundant explicit link target +/// +/// [dummy_target] TEXT +//~^ ERROR redundant explicit link target +/// [`dummy_target`] TEXT +//~^ ERROR redundant explicit link target +/// +/// [dummy_target]: dummy_target +/// [Vec]: Vec +/// [std::vec::Vec]: Vec +/// [usize]: usize +/// [std::primitive::usize]: usize +pub fn should_warn_reference() {} + +/// [`Vec`]: Vec +/// [`Vec`]: std::vec::Vec +pub fn should_not_warn_reference() {} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.rs b/tests/rustdoc-ui/lints/redundant_explicit_links.rs index 7c30b15d993d..7dd8eba5a5e3 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.rs @@ -52,3 +52,107 @@ pub fn should_warn_inline() {} /// [`Vec`](Vec) /// [`Vec`](std::vec::Vec) pub fn should_not_warn_inline() {} + +/// [dummy_target][dummy_target] +//~^ ERROR redundant explicit link target +/// [`dummy_target`][dummy_target] +//~^ ERROR redundant explicit link target +/// +/// [Vec][Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`][Vec] +//~^ ERROR redundant explicit link target +/// [Vec][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec][Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`][Vec] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// +/// [usize][usize] +//~^ ERROR redundant explicit link target +/// [`usize`][usize] +//~^ ERROR redundant explicit link target +/// [usize][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`usize`][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize][usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`][usize] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// +/// [dummy_target][dummy_target] TEXT +//~^ ERROR redundant explicit link target +/// [`dummy_target`][dummy_target] TEXT +//~^ ERROR redundant explicit link target +pub fn should_warn_reference_unknown() {} + +/// [`Vec`][Vec] +/// [`Vec`][std::vec::Vec] +pub fn should_not_warn_reference_unknown() {} + +/// [dummy_target][dummy_target] +//~^ ERROR redundant explicit link target +/// [`dummy_target`][dummy_target] +//~^ ERROR redundant explicit link target +/// +/// [Vec][Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`][Vec] +//~^ ERROR redundant explicit link target +/// [Vec][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`Vec`][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec][Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`][Vec] +//~^ ERROR redundant explicit link target +/// [std::vec::Vec][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// [`std::vec::Vec`][std::vec::Vec] +//~^ ERROR redundant explicit link target +/// +/// [usize][usize] +//~^ ERROR redundant explicit link target +/// [`usize`][usize] +//~^ ERROR redundant explicit link target +/// [usize][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`usize`][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize][usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`][usize] +//~^ ERROR redundant explicit link target +/// [std::primitive::usize][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// [`std::primitive::usize`][std::primitive::usize] +//~^ ERROR redundant explicit link target +/// +/// [dummy_target][dummy_target] TEXT +//~^ ERROR redundant explicit link target +/// [`dummy_target`][dummy_target] TEXT +//~^ ERROR redundant explicit link target +/// +/// [dummy_target]: dummy_target +/// [Vec]: Vec +/// [std::vec::Vec]: Vec +/// [usize]: usize +/// [std::primitive::usize]: usize +pub fn should_warn_reference() {} + +/// [`Vec`]: Vec +/// [`Vec`]: std::vec::Vec +pub fn should_not_warn_reference() {} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr index 3f10a2e662d6..34ec9be6646c 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.stderr +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.stderr @@ -303,5 +303,705 @@ help: remove explicit link target LL | /// [`dummy_target`] TEXT | ~~~~~~~~~~~~~~~~ -error: aborting due to 20 previous errors +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:56:20 + | +LL | /// [dummy_target][dummy_target] + | ------------ ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [dummy_target] + | ~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:58:22 + | +LL | /// [`dummy_target`][dummy_target] + | -------------- ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`dummy_target`] + | ~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:61:11 + | +LL | /// [Vec][Vec] + | --- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [Vec] + | ~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:63:13 + | +LL | /// [`Vec`][Vec] + | ----- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`Vec`] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:65:11 + | +LL | /// [Vec][std::vec::Vec] + | --- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [Vec] + | ~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:67:13 + | +LL | /// [`Vec`][std::vec::Vec] + | ----- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`Vec`] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:69:21 + | +LL | /// [std::vec::Vec][Vec] + | ------------- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::vec::Vec] + | ~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:71:23 + | +LL | /// [`std::vec::Vec`][Vec] + | --------------- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::vec::Vec`] + | ~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:73:21 + | +LL | /// [std::vec::Vec][std::vec::Vec] + | ------------- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::vec::Vec] + | ~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:75:23 + | +LL | /// [`std::vec::Vec`][std::vec::Vec] + | --------------- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::vec::Vec`] + | ~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:78:13 + | +LL | /// [usize][usize] + | ----- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [usize] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:80:15 + | +LL | /// [`usize`][usize] + | ------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`usize`] + | ~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:82:13 + | +LL | /// [usize][std::primitive::usize] + | ----- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [usize] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:84:15 + | +LL | /// [`usize`][std::primitive::usize] + | ------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`usize`] + | ~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:86:29 + | +LL | /// [std::primitive::usize][usize] + | --------------------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::primitive::usize] + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:88:31 + | +LL | /// [`std::primitive::usize`][usize] + | ----------------------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::primitive::usize`] + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:90:29 + | +LL | /// [std::primitive::usize][std::primitive::usize] + | --------------------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::primitive::usize] + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:92:31 + | +LL | /// [`std::primitive::usize`][std::primitive::usize] + | ----------------------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::primitive::usize`] + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:95:20 + | +LL | /// [dummy_target][dummy_target] TEXT + | ------------ ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [dummy_target] TEXT + | ~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:97:22 + | +LL | /// [`dummy_target`][dummy_target] TEXT + | -------------- ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`dummy_target`] TEXT + | ~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:105:20 + | +LL | /// [dummy_target][dummy_target] + | ------------ ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:149:21 + | +LL | /// [dummy_target]: dummy_target + | ^^^^^^^^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [dummy_target] + | ~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:107:22 + | +LL | /// [`dummy_target`][dummy_target] + | -------------- ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:149:21 + | +LL | /// [dummy_target]: dummy_target + | ^^^^^^^^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`dummy_target`] + | ~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:110:11 + | +LL | /// [Vec][Vec] + | --- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:150:12 + | +LL | /// [Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [Vec] + | ~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:112:13 + | +LL | /// [`Vec`][Vec] + | ----- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:150:12 + | +LL | /// [Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`Vec`] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:114:11 + | +LL | /// [Vec][std::vec::Vec] + | --- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:151:22 + | +LL | /// [std::vec::Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [Vec] + | ~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:116:13 + | +LL | /// [`Vec`][std::vec::Vec] + | ----- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:151:22 + | +LL | /// [std::vec::Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`Vec`] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:118:21 + | +LL | /// [std::vec::Vec][Vec] + | ------------- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:150:12 + | +LL | /// [Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::vec::Vec] + | ~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:120:23 + | +LL | /// [`std::vec::Vec`][Vec] + | --------------- ^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:150:12 + | +LL | /// [Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::vec::Vec`] + | ~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:122:21 + | +LL | /// [std::vec::Vec][std::vec::Vec] + | ------------- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:151:22 + | +LL | /// [std::vec::Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::vec::Vec] + | ~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:124:23 + | +LL | /// [`std::vec::Vec`][std::vec::Vec] + | --------------- ^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:151:22 + | +LL | /// [std::vec::Vec]: Vec + | ^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::vec::Vec`] + | ~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:127:13 + | +LL | /// [usize][usize] + | ----- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:152:14 + | +LL | /// [usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [usize] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:129:15 + | +LL | /// [`usize`][usize] + | ------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:152:14 + | +LL | /// [usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`usize`] + | ~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:131:13 + | +LL | /// [usize][std::primitive::usize] + | ----- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:153:30 + | +LL | /// [std::primitive::usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [usize] + | ~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:133:15 + | +LL | /// [`usize`][std::primitive::usize] + | ------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:153:30 + | +LL | /// [std::primitive::usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`usize`] + | ~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:135:29 + | +LL | /// [std::primitive::usize][usize] + | --------------------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:152:14 + | +LL | /// [usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::primitive::usize] + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:137:31 + | +LL | /// [`std::primitive::usize`][usize] + | ----------------------- ^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:152:14 + | +LL | /// [usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::primitive::usize`] + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:139:29 + | +LL | /// [std::primitive::usize][std::primitive::usize] + | --------------------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:153:30 + | +LL | /// [std::primitive::usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [std::primitive::usize] + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:141:31 + | +LL | /// [`std::primitive::usize`][std::primitive::usize] + | ----------------------- ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:153:30 + | +LL | /// [std::primitive::usize]: usize + | ^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`std::primitive::usize`] + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:144:20 + | +LL | /// [dummy_target][dummy_target] TEXT + | ------------ ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:149:21 + | +LL | /// [dummy_target]: dummy_target + | ^^^^^^^^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [dummy_target] TEXT + | ~~~~~~~~~~~~~~ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links.rs:146:22 + | +LL | /// [`dummy_target`][dummy_target] TEXT + | -------------- ^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | +note: referenced explicit link target defined here + --> $DIR/redundant_explicit_links.rs:149:21 + | +LL | /// [dummy_target]: dummy_target + | ^^^^^^^^^^^^ + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL | /// [`dummy_target`] TEXT + | ~~~~~~~~~~~~~~~~ + +error: aborting due to 60 previous errors From 5ce6cc7df3175519219c091059dd663313438c97 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Sat, 1 Jul 2023 00:55:37 +0800 Subject: [PATCH 102/169] Still resolving rustdoc resolution panicking --- compiler/rustc_resolve/src/rustdoc.rs | 6 +- .../passes/collect_intra_doc_links.rs | 69 ++++++----------- .../passes/lint/redundant_explicit_links.rs | 76 +++++++++++++------ .../lints/redundant_explicit_links.fixed | 6 +- .../lints/redundant_explicit_links.rs | 6 +- tests/rustdoc-ui/unescaped_backticks.rs | 1 + tests/rustdoc/description.rs | 2 +- tests/rustdoc/intra-doc/basic.rs | 2 + tests/rustdoc/intra-doc/generic-params.rs | 1 + tests/rustdoc/intra-doc/issue-108459.rs | 1 + 10 files changed, 90 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 083d16d3b047..f7275bed59c1 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -410,8 +410,10 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { while let Some(event) = event_iter.next() { match event { Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { - if let Some(display_text) = collect_link_data(&mut event_iter) { - links.push(display_text); + if matches!(link_type, LinkType::Inline | LinkType::ReferenceUnknown | LinkType::Reference) { + if let Some(display_text) = collect_link_data(&mut event_iter) { + links.push(display_text); + } } links.push(preprocess_link(&dest)); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0a0ffcb5b1ec..4c40363ac1d6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1038,6 +1038,7 @@ impl LinkCollector<'_, '_> { // resolutions are cached, for other links we want to report an error every // time so they are not cached. matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), + false, )?; self.resolve_display_text( @@ -1232,6 +1233,9 @@ impl LinkCollector<'_, '_> { // If errors are cached then they are only reported on first occurrence // which we want in some cases but not in others. cache_errors: bool, + // If this call is intended to be recoverable, then pass true to silence. + // This is only recoverable when path is failed to resolved. + recoverable: bool, ) -> Option<(Res, Option)> { if let Some(res) = self.visited_links.get(&key) { if res.is_some() || cache_errors { @@ -1239,7 +1243,7 @@ impl LinkCollector<'_, '_> { } } - let mut candidates = self.resolve_with_disambiguator(&key, diag.clone()); + let mut candidates = self.resolve_with_disambiguator(&key, diag.clone(), recoverable); // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether. // However I'm not sure how to check that across crates. @@ -1290,6 +1294,9 @@ impl LinkCollector<'_, '_> { &mut self, key: &ResolutionInfo, diag: DiagnosticInfo<'_>, + // If this call is intended to be recoverable, then pass true to silence. + // This is only recoverable when path is failed to resolved. + recoverable: bool, ) -> Vec<(Res, Option)> { let disambiguator = key.dis; let path_str = &key.path_str; @@ -1319,7 +1326,9 @@ impl LinkCollector<'_, '_> { } } } - resolution_failure(self, diag, path_str, disambiguator, smallvec![err]); + if !recoverable { + resolution_failure(self, diag, path_str, disambiguator, smallvec![err]); + } return vec![]; } } @@ -1356,13 +1365,15 @@ impl LinkCollector<'_, '_> { .fold(0, |acc, res| if let Ok(res) = res { acc + res.len() } else { acc }); if len == 0 { - resolution_failure( - self, - diag, - path_str, - disambiguator, - candidates.into_iter().filter_map(|res| res.err()).collect(), - ); + if !recoverable { + resolution_failure( + self, + diag, + path_str, + disambiguator, + candidates.into_iter().filter_map(|res| res.err()).collect(), + ); + } return vec![]; } else if len == 1 { candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::>() @@ -1396,43 +1407,8 @@ impl LinkCollector<'_, '_> { ori_link: &MarkdownLink, diag_info: &DiagnosticInfo<'_>, ) { - // Check if explicit resolution's path is same as resolution of original link's display text path, e.g. - // - // LinkType::Inline: - // - // [target](target) - // [`target`](target) - // [target](path::to::target) - // [`target`](path::to::target) - // [path::to::target](target) - // [`path::to::target`](target) - // [path::to::target](path::to::target) - // [`path::to::target`](path::to::target) - // - // LinkType::ReferenceUnknown - // - // [target][target] - // [`target`][target] - // [target][path::to::target] - // [`target`][path::to::target] - // [path::to::target][target] - // [`path::to::target`][target] - // [path::to::target][path::to::target] - // [`path::to::target`][path::to::target] - // - // LinkType::Reference - // - // [target][target] - // [`target`][target] - // [target][path::to::target] - // [`target`][path::to::target] - // [path::to::target][target] - // [`path::to::target`][target] - // [path::to::target][path::to::target] - // [`path::to::target`][path::to::target] - // - // [target]: target // or [target]: path::to::target - // [path::to::target]: path::to::target // or [path::to::target]: target + // Check if explicit resolution's path is same as resolution of original link's display text path, see + // tests/rustdoc-ui/lint/redundant_explicit_links.rs for more cases. // // To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated // into explicit path. @@ -1471,6 +1447,7 @@ impl LinkCollector<'_, '_> { display_res_info, diag_info.clone(), // this struct should really be Copy, but Range is not :( false, + true, ); } } diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 722088eb79aa..da8a73be60b2 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -32,6 +32,13 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { return; } + if item.link_names(&cx.cache).is_empty() { + // If there's no link names in this item, + // then we skip resolution querying to + // avoid from panicking. + return; + } + check_redundant_explicit_link(cx, item, hir_id, &doc); } @@ -57,33 +64,52 @@ fn check_redundant_explicit_link<'md>( while let Some((event, link_range)) = offset_iter.next() { match event { - Event::Start(Tag::Link(link_type, dest, _)) => match link_type { - LinkType::Inline | LinkType::ReferenceUnknown => { - check_inline_or_reference_unknown_redundancy( - cx, - item, - hir_id, - doc, - resolutions, - link_range, - dest.to_string(), - collect_link_data(&mut offset_iter), - if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') }, - ); + Event::Start(Tag::Link(link_type, dest, _)) => { + let link_data = collect_link_data(&mut offset_iter); + + let explicit_link = dest.to_string(); + let display_link = link_data.resolvable_link.clone()?; + let explicit_len = explicit_link.len(); + let display_len = display_link.len(); + + if explicit_len == display_len && explicit_link != display_link { + // Skips if they possibly have no relativity. + continue; } - LinkType::Reference => { - check_reference_redundancy( - cx, - item, - hir_id, - doc, - resolutions, - link_range, - &dest, - collect_link_data(&mut offset_iter), - ); + + if (explicit_len >= display_len + && &explicit_link[(explicit_len - display_len)..] == display_link) + || (display_len >= explicit_len + && &display_link[(display_len - explicit_len)..] == explicit_link) { + match link_type { + LinkType::Inline | LinkType::ReferenceUnknown => { + check_inline_or_reference_unknown_redundancy( + cx, + item, + hir_id, + doc, + resolutions, + link_range, + dest.to_string(), + link_data, + if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') }, + ); + } + LinkType::Reference => { + check_reference_redundancy( + cx, + item, + hir_id, + doc, + resolutions, + link_range, + &dest, + link_data, + ); + } + _ => {} + } } - _ => {} }, _ => {} } diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.fixed b/tests/rustdoc-ui/lints/redundant_explicit_links.fixed index 4745da879a35..900234e31e98 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.fixed +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.fixed @@ -42,7 +42,7 @@ pub fn dummy_target() {} //~^ ERROR redundant explicit link target /// [`std::primitive::usize`] //~^ ERROR redundant explicit link target -/// +/// /// [dummy_target] TEXT //~^ ERROR redundant explicit link target /// [`dummy_target`] TEXT @@ -91,7 +91,7 @@ pub fn should_not_warn_inline() {} //~^ ERROR redundant explicit link target /// [`std::primitive::usize`] //~^ ERROR redundant explicit link target -/// +/// /// [dummy_target] TEXT //~^ ERROR redundant explicit link target /// [`dummy_target`] TEXT @@ -140,7 +140,7 @@ pub fn should_not_warn_reference_unknown() {} //~^ ERROR redundant explicit link target /// [`std::primitive::usize`] //~^ ERROR redundant explicit link target -/// +/// /// [dummy_target] TEXT //~^ ERROR redundant explicit link target /// [`dummy_target`] TEXT diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links.rs b/tests/rustdoc-ui/lints/redundant_explicit_links.rs index 7dd8eba5a5e3..13feb85e0517 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links.rs @@ -42,7 +42,7 @@ pub fn dummy_target() {} //~^ ERROR redundant explicit link target /// [`std::primitive::usize`](std::primitive::usize) //~^ ERROR redundant explicit link target -/// +/// /// [dummy_target](dummy_target) TEXT //~^ ERROR redundant explicit link target /// [`dummy_target`](dummy_target) TEXT @@ -91,7 +91,7 @@ pub fn should_not_warn_inline() {} //~^ ERROR redundant explicit link target /// [`std::primitive::usize`][std::primitive::usize] //~^ ERROR redundant explicit link target -/// +/// /// [dummy_target][dummy_target] TEXT //~^ ERROR redundant explicit link target /// [`dummy_target`][dummy_target] TEXT @@ -140,7 +140,7 @@ pub fn should_not_warn_reference_unknown() {} //~^ ERROR redundant explicit link target /// [`std::primitive::usize`][std::primitive::usize] //~^ ERROR redundant explicit link target -/// +/// /// [dummy_target][dummy_target] TEXT //~^ ERROR redundant explicit link target /// [`dummy_target`][dummy_target] TEXT diff --git a/tests/rustdoc-ui/unescaped_backticks.rs b/tests/rustdoc-ui/unescaped_backticks.rs index e99cd1f3d58f..e960e9f59e9c 100644 --- a/tests/rustdoc-ui/unescaped_backticks.rs +++ b/tests/rustdoc-ui/unescaped_backticks.rs @@ -1,6 +1,7 @@ #![deny(rustdoc::unescaped_backticks)] #![allow(rustdoc::broken_intra_doc_links)] #![allow(rustdoc::invalid_html_tags)] +#![allow(rustdoc::redundant_explicit_links)] /// pub fn empty() {} diff --git a/tests/rustdoc/description.rs b/tests/rustdoc/description.rs index 43cd59ebd092..918ccd639683 100644 --- a/tests/rustdoc/description.rs +++ b/tests/rustdoc/description.rs @@ -26,5 +26,5 @@ pub fn foo_fn() {} // @has 'foo/fn.bar_fn.html' '//meta[@name="description"]/@content' \ // 'Description with intra-doc link to foo_fn and [nonexistent_item] and foo_fn.' #[allow(rustdoc::broken_intra_doc_links)] -/// Description with intra-doc link to [foo_fn] and [nonexistent_item] and [foo_fn](self::foo_fn). +/// Description with intra-doc link to [foo_fn] and [nonexistent_item] and [foo_fn]. pub fn bar_fn() {} diff --git a/tests/rustdoc/intra-doc/basic.rs b/tests/rustdoc/intra-doc/basic.rs index 96e21137b2dc..c88a7887f11e 100644 --- a/tests/rustdoc/intra-doc/basic.rs +++ b/tests/rustdoc/intra-doc/basic.rs @@ -1,3 +1,5 @@ +#![allow(rustdoc::redundant_explicit_links)] + // @has basic/index.html // @has - '//a/@href' 'struct.ThisType.html' // @has - '//a/@title' 'struct basic::ThisType' diff --git a/tests/rustdoc/intra-doc/generic-params.rs b/tests/rustdoc/intra-doc/generic-params.rs index fbc9fc6a9bc2..359f775f97fd 100644 --- a/tests/rustdoc/intra-doc/generic-params.rs +++ b/tests/rustdoc/intra-doc/generic-params.rs @@ -1,6 +1,7 @@ // ignore-tidy-linelength #![crate_name = "foo"] +#![allow(rustdoc::redundant_explicit_links)] //! Here's a link to [`Vec`] and one to [`Box>>`]. //! Here's a link to [`Iterator>::Item`]. diff --git a/tests/rustdoc/intra-doc/issue-108459.rs b/tests/rustdoc/intra-doc/issue-108459.rs index eb1c7a05e540..b8cd478b4df6 100644 --- a/tests/rustdoc/intra-doc/issue-108459.rs +++ b/tests/rustdoc/intra-doc/issue-108459.rs @@ -1,4 +1,5 @@ #![deny(rustdoc::broken_intra_doc_links)] +#![allow(rustdoc::redundant_explicit_links)] pub struct S; pub mod char {} From 0e2f2cccd748028a39603e46afc56d7c20bcc7c8 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Sat, 1 Jul 2023 01:20:33 +0800 Subject: [PATCH 103/169] Add check-pass tests and fix test behavior --- tests/rustdoc-ui/lints/no-redundancy.rs | 4 ++++ tests/rustdoc/description.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc-ui/lints/no-redundancy.rs diff --git a/tests/rustdoc-ui/lints/no-redundancy.rs b/tests/rustdoc-ui/lints/no-redundancy.rs new file mode 100644 index 000000000000..17582dff6c80 --- /dev/null +++ b/tests/rustdoc-ui/lints/no-redundancy.rs @@ -0,0 +1,4 @@ +// check-pass + +/// [Vec][std::vec::Vec#examples] should not warn, because it's not actually redundant! +pub fn func() {} diff --git a/tests/rustdoc/description.rs b/tests/rustdoc/description.rs index 918ccd639683..aabbb4c4c8f6 100644 --- a/tests/rustdoc/description.rs +++ b/tests/rustdoc/description.rs @@ -1,4 +1,5 @@ #![crate_name = "foo"] +#![allow(rustdoc::redundant_explicit_links)] //! # Description test crate //! //! This is the contents of the test crate docstring. @@ -26,5 +27,5 @@ pub fn foo_fn() {} // @has 'foo/fn.bar_fn.html' '//meta[@name="description"]/@content' \ // 'Description with intra-doc link to foo_fn and [nonexistent_item] and foo_fn.' #[allow(rustdoc::broken_intra_doc_links)] -/// Description with intra-doc link to [foo_fn] and [nonexistent_item] and [foo_fn]. +/// Description with intra-doc link to [foo_fn] and [nonexistent_item] and [foo_fn](self::foo_fn). pub fn bar_fn() {} From fe17ae3af6e1ff42b81a5309dc88b36dacfc8577 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Sat, 1 Jul 2023 01:23:20 +0800 Subject: [PATCH 104/169] add missing deny lint --- tests/rustdoc-ui/lints/no-redundancy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/rustdoc-ui/lints/no-redundancy.rs b/tests/rustdoc-ui/lints/no-redundancy.rs index 17582dff6c80..f9c5e17a5f39 100644 --- a/tests/rustdoc-ui/lints/no-redundancy.rs +++ b/tests/rustdoc-ui/lints/no-redundancy.rs @@ -1,4 +1,6 @@ // check-pass +#![deny(rustdoc::redundant_explicit_links)] + /// [Vec][std::vec::Vec#examples] should not warn, because it's not actually redundant! pub fn func() {} From 78c85f439f04f2aa484a9f1be3133d74bda87c7d Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Sat, 1 Jul 2023 01:29:40 +0800 Subject: [PATCH 105/169] fomar files --- compiler/rustc_resolve/src/rustdoc.rs | 9 ++++++++- .../passes/lint/redundant_explicit_links.rs | 13 +++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index f7275bed59c1..cbda0535c899 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -410,7 +410,14 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { while let Some(event) = event_iter.next() { match event { Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { - if matches!(link_type, LinkType::Inline | LinkType::ReferenceUnknown | LinkType::Reference) { + if matches!( + link_type, + LinkType::Inline + | LinkType::ReferenceUnknown + | LinkType::Reference + | LinkType::Shortcut + | LinkType::ShortcutUnknown + ) { if let Some(display_text) = collect_link_data(&mut event_iter) { links.push(display_text); } diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index da8a73be60b2..a41e278fd816 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -34,7 +34,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { if item.link_names(&cx.cache).is_empty() { // If there's no link names in this item, - // then we skip resolution querying to + // then we skip resolution querying to // avoid from panicking. return; } @@ -80,7 +80,8 @@ fn check_redundant_explicit_link<'md>( if (explicit_len >= display_len && &explicit_link[(explicit_len - display_len)..] == display_link) || (display_len >= explicit_len - && &display_link[(display_len - explicit_len)..] == explicit_link) { + && &display_link[(display_len - explicit_len)..] == explicit_link) + { match link_type { LinkType::Inline | LinkType::ReferenceUnknown => { check_inline_or_reference_unknown_redundancy( @@ -92,7 +93,11 @@ fn check_redundant_explicit_link<'md>( link_range, dest.to_string(), link_data, - if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') }, + if link_type == LinkType::Inline { + (b'(', b')') + } else { + (b'[', b']') + }, ); } LinkType::Reference => { @@ -110,7 +115,7 @@ fn check_redundant_explicit_link<'md>( _ => {} } } - }, + } _ => {} } } From ecb26376e5d4a03bc5f536b315161d5450bd914e Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Sun, 2 Jul 2023 23:32:46 +0800 Subject: [PATCH 106/169] narrow down the lint trigger constraint --- compiler/rustc_resolve/src/rustdoc.rs | 19 ++++++---- src/librustdoc/html/markdown.rs | 35 ++++++++++++++----- .../passes/collect_intra_doc_links.rs | 28 ++++++++------- .../passes/lint/redundant_explicit_links.rs | 10 ++++++ tests/rustdoc-ui/lints/no-redundancy.rs | 1 + 5 files changed, 65 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index cbda0535c899..ba7417b6ddaf 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -1,4 +1,4 @@ -use pulldown_cmark::{BrokenLink, Event, LinkType, Options, Parser, Tag}; +use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag}; use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxHashMap; @@ -436,15 +436,22 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { fn collect_link_data<'input, 'callback>( event_iter: &mut Parser<'input, 'callback>, ) -> Option> { - let mut display_text = None; + let mut display_text: Option = None; + let mut append_text = |text: CowStr<'_>| { + if let Some(display_text) = &mut display_text { + display_text.push_str(&text); + } else { + display_text = Some(text.to_string()); + } + }; while let Some(event) = event_iter.next() { match event { - Event::Text(code) => { - display_text = Some(code.to_string().into_boxed_str()); + Event::Text(text) => { + append_text(text); } Event::Code(code) => { - display_text = Some(code.to_string().into_boxed_str()); + append_text(code); } Event::End(_) => { break; @@ -453,5 +460,5 @@ fn collect_link_data<'input, 'callback>( } } - display_text + display_text.map(String::into_boxed_str) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 2fe052283a99..98cc38a10d44 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1240,7 +1240,7 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin pub(crate) struct MarkdownLink { pub kind: LinkType, pub link: String, - pub display_text: String, + pub display_text: Option, pub range: MarkdownLinkRange, } @@ -1402,13 +1402,23 @@ pub(crate) fn markdown_links<'md, R>( LinkType::Autolink | LinkType::Email => unreachable!(), }; - let display_text = - collect_link_data(&mut event_iter).map_or(String::new(), CowStr::into_string); + let display_text = if matches!( + link_type, + LinkType::Inline + | LinkType::ReferenceUnknown + | LinkType::Reference + | LinkType::Shortcut + | LinkType::ShortcutUnknown + ) { + collect_link_data(&mut event_iter) + } else { + None + }; if let Some(link) = preprocess_link(MarkdownLink { kind: link_type, - display_text, link: dest.into_string(), + display_text, range, }) { links.push(link); @@ -1424,16 +1434,23 @@ pub(crate) fn markdown_links<'md, R>( /// Collects additional data of link. fn collect_link_data<'input, 'callback>( event_iter: &mut OffsetIter<'input, 'callback>, -) -> Option> { - let mut display_text = None; +) -> Option { + let mut display_text: Option = None; + let mut append_text = |text: CowStr<'_>| { + if let Some(display_text) = &mut display_text { + display_text.push_str(&text); + } else { + display_text = Some(text.to_string()); + } + }; while let Some((event, _span)) = event_iter.next() { match event { - Event::Text(code) => { - display_text = Some(code); + Event::Text(text) => { + append_text(text); } Event::Code(code) => { - display_text = Some(code); + append_text(code); } Event::End(_) => { break; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4c40363ac1d6..36872266ee12 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1041,18 +1041,20 @@ impl LinkCollector<'_, '_> { false, )?; - self.resolve_display_text( - path_str, - ResolutionInfo { - item_id, - module_id, - dis: disambiguator, - path_str: ori_link.display_text.clone().into_boxed_str(), - extra_fragment: extra_fragment.clone(), - }, - &ori_link, - &diag_info, - ); + if ori_link.display_text.is_some() { + self.resolve_display_text( + path_str, + ResolutionInfo { + item_id, + module_id, + dis: disambiguator, + path_str: ori_link.display_text.clone()?.into_boxed_str(), + extra_fragment: extra_fragment.clone(), + }, + &ori_link, + &diag_info, + ); + } // Check for a primitive which might conflict with a module // Report the ambiguity and require that the user specify which one they meant. @@ -1429,7 +1431,7 @@ impl LinkCollector<'_, '_> { // // Notice that this algorithm is passive, might possibly miss actual redudant cases. let explicit_link = &explicit_link.to_string(); - let display_text = &ori_link.display_text; + let display_text = ori_link.display_text.as_ref().unwrap(); let display_len = display_text.len(); let explicit_len = explicit_link.len(); diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index a41e278fd816..da71e537f684 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -67,6 +67,16 @@ fn check_redundant_explicit_link<'md>( Event::Start(Tag::Link(link_type, dest, _)) => { let link_data = collect_link_data(&mut offset_iter); + if let Some(resolvable_link) = link_data.resolvable_link.as_ref() { + if &link_data.display_link != resolvable_link { + // Skips if display link does not match to actual + // resolvable link, usually happens if display link + // has several segments, e.g. + // [this is just an `Option`](Option) + continue; + } + } + let explicit_link = dest.to_string(); let display_link = link_data.resolvable_link.clone()?; let explicit_len = explicit_link.len(); diff --git a/tests/rustdoc-ui/lints/no-redundancy.rs b/tests/rustdoc-ui/lints/no-redundancy.rs index f9c5e17a5f39..e3358728b1b1 100644 --- a/tests/rustdoc-ui/lints/no-redundancy.rs +++ b/tests/rustdoc-ui/lints/no-redundancy.rs @@ -3,4 +3,5 @@ #![deny(rustdoc::redundant_explicit_links)] /// [Vec][std::vec::Vec#examples] should not warn, because it's not actually redundant! +/// [This is just an `Option`][std::option::Option] has different display content to actual link! pub fn func() {} From f0b2cca185555ba20d7b95d073eedd03cda99ce9 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Mon, 3 Jul 2023 08:39:44 +0800 Subject: [PATCH 107/169] lint links --- compiler/rustc_errors/src/lib.rs | 6 +++--- library/std/src/primitive_docs.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 7d660d2dbaa9..bbbe21a5893d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -452,11 +452,11 @@ struct HandlerInner { /// have been converted. check_unstable_expect_diagnostics: bool, - /// Expected [`Diagnostic`][diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of + /// Expected [`Diagnostic`][struct@diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of /// the lint level. [`LintExpectationId`]s created early during the compilation /// (before `HirId`s have been defined) are not stable and can therefore not be /// stored on disk. This buffer stores these diagnostics until the ID has been - /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][diagnostic::Diagnostic]s are the + /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][struct@diagnostic::Diagnostic]s are the /// submitted for storage and added to the list of fulfilled expectations. unstable_expect_diagnostics: Vec, @@ -1384,7 +1384,7 @@ impl HandlerInner { !self.emitted_diagnostics.insert(diagnostic_hash) }; - diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); + diagnostic.children.extract_from(already_emitted_sub).for_each(|_| {}); self.emitter.emit_diagnostic(diagnostic); if diagnostic.is_error() { diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 80289ca08c3f..7180236fb222 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -624,7 +624,7 @@ mod prim_pointer {} /// array implementations) succeed if the input slice length is the same as the result /// array length. They optimize especially well when the optimizer can easily determine /// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements -/// [TryFrom](crate::convert::TryFrom) returning: +/// [TryFrom] returning: /// /// - `[T; N]` copies from the slice's elements /// - `&[T; N]` references the original slice's elements From 713e78cdd8d24cbefbc6b1ff97b15bf4c30b6567 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Mon, 3 Jul 2023 08:40:34 +0800 Subject: [PATCH 108/169] fix --- compiler/rustc_errors/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bbbe21a5893d..34518b53759d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1384,7 +1384,7 @@ impl HandlerInner { !self.emitted_diagnostics.insert(diagnostic_hash) }; - diagnostic.children.extract_from(already_emitted_sub).for_each(|_| {}); + diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); self.emitter.emit_diagnostic(diagnostic); if diagnostic.is_error() { From 2ec3e297ab054054d428d7d28666b95484b57fc0 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Mon, 3 Jul 2023 08:46:33 +0800 Subject: [PATCH 109/169] tidy doc link --- library/core/src/primitive_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 80289ca08c3f..7180236fb222 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -624,7 +624,7 @@ mod prim_pointer {} /// array implementations) succeed if the input slice length is the same as the result /// array length. They optimize especially well when the optimizer can easily determine /// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements -/// [TryFrom](crate::convert::TryFrom) returning: +/// [TryFrom] returning: /// /// - `[T; N]` copies from the slice's elements /// - `&[T; N]` references the original slice's elements From c4afb8a8684aceabf54030c7e2648494d3c9bbe2 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Mon, 3 Jul 2023 10:30:29 +0800 Subject: [PATCH 110/169] resolve conflicts --- library/core/src/lib.rs | 2 ++ library/core/src/primitive_docs.rs | 2 +- library/std/src/primitive_docs.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 48c3c1f21234..a2729b3743cc 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -97,6 +97,8 @@ #![allow(incomplete_features)] #![warn(multiple_supertrait_upcastable)] #![cfg_attr(not(bootstrap), allow(internal_features))] +// Do not check link redundancy on bootstraping phase +#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))] // // Library features: // tidy-alphabetical-start diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 7180236fb222..80289ca08c3f 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -624,7 +624,7 @@ mod prim_pointer {} /// array implementations) succeed if the input slice length is the same as the result /// array length. They optimize especially well when the optimizer can easily determine /// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements -/// [TryFrom] returning: +/// [TryFrom](crate::convert::TryFrom) returning: /// /// - `[T; N]` copies from the slice's elements /// - `&[T; N]` references the original slice's elements diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 7180236fb222..80289ca08c3f 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -624,7 +624,7 @@ mod prim_pointer {} /// array implementations) succeed if the input slice length is the same as the result /// array length. They optimize especially well when the optimizer can easily determine /// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements -/// [TryFrom] returning: +/// [TryFrom](crate::convert::TryFrom) returning: /// /// - `[T; N]` copies from the slice's elements /// - `&[T; N]` references the original slice's elements From 4896fc0f5919d7facee3ce77e089495cc133dc74 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Mon, 3 Jul 2023 23:34:38 +0800 Subject: [PATCH 111/169] resolve conflicts --- library/std/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ac4ce222fbaa..58684ffe500a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -223,6 +223,7 @@ #![cfg_attr(not(bootstrap), allow(internal_features))] #![deny(rustc::existing_doc_keyword)] #![deny(fuzzy_provenance_casts)] +#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` #![deny(ffi_unwind_calls)] // std may use features in a platform-specific way From 15ece93e34be62b383c5b67744d8ad68678fb954 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Tue, 4 Jul 2023 01:51:31 +0800 Subject: [PATCH 112/169] relax redundancy constraint --- library/alloc/src/sync.rs | 6 ++---- src/librustdoc/passes/lint/redundant_explicit_links.rs | 7 +------ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index e2a2fe932ab2..476a4fea54f8 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -153,7 +153,7 @@ macro_rules! acquire { /// /// ## `Deref` behavior /// -/// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), +/// `Arc` automatically dereferences to `T` (via the [`Deref`] trait), /// so you can call `T`'s methods on a value of type `Arc`. To avoid name /// clashes with `T`'s methods, the methods of `Arc` itself are associated /// functions, called using [fully qualified syntax]: @@ -187,7 +187,6 @@ macro_rules! acquire { /// [mutex]: ../../std/sync/struct.Mutex.html /// [rwlock]: ../../std/sync/struct.RwLock.html /// [atomic]: core::sync::atomic -/// [deref]: core::ops::Deref /// [downgrade]: Arc::downgrade /// [upgrade]: Weak::upgrade /// [RefCell\]: core::cell::RefCell @@ -1495,7 +1494,7 @@ impl Arc { /// alignment as `T`. This is trivially true if `U` is `T`. /// Note that if `U` is not `T` but has the same size and alignment, this is /// basically like transmuting references of different types. See - /// [`mem::transmute`][transmute] for more information on what + /// [`mem::transmute`] for more information on what /// restrictions apply in this case. /// /// The raw pointer must point to a block of memory allocated by `alloc` @@ -1507,7 +1506,6 @@ impl Arc { /// even if the returned `Arc` is never accessed. /// /// [into_raw]: Arc::into_raw - /// [transmute]: core::mem::transmute /// /// # Examples /// diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index da71e537f684..94d07ec034d7 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -68,7 +68,7 @@ fn check_redundant_explicit_link<'md>( let link_data = collect_link_data(&mut offset_iter); if let Some(resolvable_link) = link_data.resolvable_link.as_ref() { - if &link_data.display_link != resolvable_link { + if &link_data.display_link.replace("`", "") != resolvable_link { // Skips if display link does not match to actual // resolvable link, usually happens if display link // has several segments, e.g. @@ -82,11 +82,6 @@ fn check_redundant_explicit_link<'md>( let explicit_len = explicit_link.len(); let display_len = display_link.len(); - if explicit_len == display_len && explicit_link != display_link { - // Skips if they possibly have no relativity. - continue; - } - if (explicit_len >= display_len && &explicit_link[(explicit_len - display_len)..] == display_link) || (display_len >= explicit_len From 62113f6657d91ba294abe96852c25c1c4eb4c501 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Tue, 4 Jul 2023 02:40:05 +0800 Subject: [PATCH 113/169] fix `unescaped_backticks` error --- tests/rustdoc-ui/unescaped_backticks.stderr | 128 ++++++++++---------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr index bf1f18889c40..83822f778d0f 100644 --- a/tests/rustdoc-ui/unescaped_backticks.stderr +++ b/tests/rustdoc-ui/unescaped_backticks.stderr @@ -1,5 +1,5 @@ error: unescaped backtick - --> $DIR/unescaped_backticks.rs:186:70 + --> $DIR/unescaped_backticks.rs:187:70 | LL | /// if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect = | ^ @@ -19,7 +19,7 @@ LL | /// if you want your MIR to be modified by the full MIR pipeline, or \`#![c | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:231:13 + --> $DIR/unescaped_backticks.rs:232:13 | LL | //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")] | ^ @@ -34,7 +34,7 @@ LL | //! \`#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kin | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:236:13 + --> $DIR/unescaped_backticks.rs:237:13 | LL | /// `cfg=... | ^ @@ -49,7 +49,7 @@ LL | /// \`cfg=... | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:240:42 + --> $DIR/unescaped_backticks.rs:241:42 | LL | /// `cfg=... and not `#[cfg_attr]` | ^ @@ -64,7 +64,7 @@ LL | /// `cfg=... and not `#[cfg_attr]\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:192:91 + --> $DIR/unescaped_backticks.rs:193:91 | LL | /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to | ^ @@ -79,7 +79,7 @@ LL | /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:201:34 + --> $DIR/unescaped_backticks.rs:202:34 | LL | /// in `nt_to_tokenstream` | ^ @@ -94,7 +94,7 @@ LL | /// in `nt_to_tokenstream\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:207:62 + --> $DIR/unescaped_backticks.rs:208:62 | LL | /// that `Option` only takes up 4 bytes, because `newtype_index! reserves | ^ @@ -109,7 +109,7 @@ LL | /// that `Option` only takes up 4 bytes, because \`newtype_inde | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:215:52 + --> $DIR/unescaped_backticks.rs:216:52 | LL | /// also avoids the need to import `OpenOptions`. | ^ @@ -124,7 +124,7 @@ LL | /// also avoids the need to import `OpenOptions\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:220:46 + --> $DIR/unescaped_backticks.rs:221:46 | LL | /// `HybridBitSet`. Has no effect if `row` does not exist. | ^ @@ -139,7 +139,7 @@ LL | /// `HybridBitSet`. Has no effect if `row\` does not exist. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:246:12 + --> $DIR/unescaped_backticks.rs:247:12 | LL | /// RWU`s can get very large, so it uses a more compact representation. | ^ @@ -154,7 +154,7 @@ LL | /// RWU\`s can get very large, so it uses a more compact representation | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:253:15 + --> $DIR/unescaped_backticks.rs:254:15 | LL | /// in `U2`. | ^ @@ -169,7 +169,7 @@ LL | /// in `U2\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:270:42 + --> $DIR/unescaped_backticks.rs:271:42 | LL | /// because it contains `[type error]`. Yuck! (See issue #29857 for | ^ @@ -184,7 +184,7 @@ LL | /// because it contains `[type error]\`. Yuck! (See issue #29857 for | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:280:53 + --> $DIR/unescaped_backticks.rs:281:53 | LL | /// well as the second instance of `A: AutoTrait`) to suppress | ^ @@ -199,7 +199,7 @@ LL | /// well as the second instance of `A: AutoTrait\`) to suppress | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:290:40 + --> $DIR/unescaped_backticks.rs:291:40 | LL | /// `'a` with `'b` and not `'static`. But it will have to do for | ^ @@ -211,7 +211,7 @@ LL | /// `'a` with `'b` and not `'static\`. But it will have to do for | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:299:54 + --> $DIR/unescaped_backticks.rs:300:54 | LL | /// `None`. Otherwise, it will return `Some(Dispatch)`. | ^ @@ -226,7 +226,7 @@ LL | /// `None`. Otherwise, it will return `Some(Dispatch)\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:303:13 + --> $DIR/unescaped_backticks.rs:304:13 | LL | /// or `None` if it isn't. | ^ @@ -238,7 +238,7 @@ LL | /// or `None\` if it isn't. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:307:14 + --> $DIR/unescaped_backticks.rs:308:14 | LL | /// `on_event` should be called. | ^ @@ -253,7 +253,7 @@ LL | /// `on_event\` should be called. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:312:29 + --> $DIR/unescaped_backticks.rs:313:29 | LL | /// [`rebuild_interest_cache`][rebuild] is called after the value of the max | ^ @@ -268,7 +268,7 @@ LL | /// [`rebuild_interest_cache\`][rebuild] is called after the value of the m | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:322:5 + --> $DIR/unescaped_backticks.rs:323:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], LL | | @@ -287,7 +287,7 @@ LL | | /// level changes. to this: `None`. Otherwise, it will return `Some(Dispatch)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:322:5 + --> $DIR/unescaped_backticks.rs:323:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], LL | | @@ -304,7 +304,7 @@ LL | | /// level changes. to this: or `None\` if it isn't. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:322:5 + --> $DIR/unescaped_backticks.rs:323:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], LL | | @@ -323,7 +323,7 @@ LL | | /// level changes. to this: `on_event\` should be called. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:322:5 + --> $DIR/unescaped_backticks.rs:323:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], LL | | @@ -342,7 +342,7 @@ LL | | /// level changes. to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max error: unescaped backtick - --> $DIR/unescaped_backticks.rs:348:56 + --> $DIR/unescaped_backticks.rs:349:56 | LL | /// instead and use [`CloneCounterObserver::counter`] to increment. | ^ @@ -354,7 +354,7 @@ LL | /// instead and use [`CloneCounterObserver::counter\`] to increment. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:11:5 + --> $DIR/unescaped_backticks.rs:12:5 | LL | /// ` | ^ @@ -366,7 +366,7 @@ LL | /// \` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:18:7 + --> $DIR/unescaped_backticks.rs:19:7 | LL | /// \` | ^ @@ -381,7 +381,7 @@ LL | /// \\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:25:6 + --> $DIR/unescaped_backticks.rs:26:6 | LL | /// [`link1] | ^ @@ -396,7 +396,7 @@ LL | /// [\`link1] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:29:11 + --> $DIR/unescaped_backticks.rs:30:11 | LL | /// [link2`] | ^ @@ -411,7 +411,7 @@ LL | /// [link2\`] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:33:6 + --> $DIR/unescaped_backticks.rs:34:6 | LL | /// [`link_long](link_long) | ^ @@ -426,7 +426,7 @@ LL | /// [\`link_long](link_long) | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:37:6 + --> $DIR/unescaped_backticks.rs:38:6 | LL | /// [`broken-link] | ^ @@ -441,7 +441,7 @@ LL | /// [\`broken-link] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:44:8 + --> $DIR/unescaped_backticks.rs:45:8 | LL | /// | ^ @@ -456,7 +456,7 @@ LL | /// | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:54:6 + --> $DIR/unescaped_backticks.rs:55:6 | LL | /// 🦀`🦀 | ^ @@ -475,7 +475,7 @@ LL | /// 🦀\`🦀 | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:58:5 + --> $DIR/unescaped_backticks.rs:59:5 | LL | /// `foo( | ^ @@ -490,7 +490,7 @@ LL | /// \`foo( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:64:14 + --> $DIR/unescaped_backticks.rs:65:14 | LL | /// `foo `bar` | ^ @@ -505,7 +505,7 @@ LL | /// `foo `bar\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:70:5 + --> $DIR/unescaped_backticks.rs:71:5 | LL | /// `foo( | ^ @@ -520,7 +520,7 @@ LL | /// \`foo( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:75:83 + --> $DIR/unescaped_backticks.rs:76:83 | LL | /// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`. | ^ @@ -535,7 +535,7 @@ LL | /// Addition is commutative, which means that add(a, b)` is the same as `ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:79:51 + --> $DIR/unescaped_backticks.rs:80:51 | LL | /// or even to add a number `n` to 42 (`add(42, b)`)! | ^ @@ -550,7 +550,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, b)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:83:83 + --> $DIR/unescaped_backticks.rs:84:83 | LL | /// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`. | ^ @@ -565,7 +565,7 @@ LL | /// Addition is commutative, which means that `add(a, b) is the same as `ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:87:51 + --> $DIR/unescaped_backticks.rs:88:51 | LL | /// or even to add a number `n` to 42 (`add(42, n)`)! | ^ @@ -580,7 +580,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:91:83 + --> $DIR/unescaped_backticks.rs:92:83 | LL | /// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`. | ^ @@ -595,7 +595,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:95:50 + --> $DIR/unescaped_backticks.rs:96:50 | LL | /// or even to add a number `n` to 42 (add(42, n)`)! | ^ @@ -610,7 +610,7 @@ LL | /// or even to add a number `n` to 42 (add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:99:74 + --> $DIR/unescaped_backticks.rs:100:74 | LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a). | ^ @@ -625,7 +625,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as \` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:103:51 + --> $DIR/unescaped_backticks.rs:104:51 | LL | /// or even to add a number `n` to 42 (`add(42, n)`)! | ^ @@ -640,7 +640,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:107:1 + --> $DIR/unescaped_backticks.rs:108:1 | LL | #[doc = "`"] | ^^^^^^^^^^^^ @@ -651,7 +651,7 @@ LL | #[doc = "`"] to this: \` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:114:1 + --> $DIR/unescaped_backticks.rs:115:1 | LL | #[doc = concat!("\\", "`")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -664,7 +664,7 @@ LL | #[doc = concat!("\\", "`")] to this: \\` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:118:1 + --> $DIR/unescaped_backticks.rs:119:1 | LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -677,7 +677,7 @@ LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same a to this: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:122:1 + --> $DIR/unescaped_backticks.rs:123:1 | LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -690,7 +690,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same a to this: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:126:1 + --> $DIR/unescaped_backticks.rs:127:1 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -703,7 +703,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same to this: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:130:1 + --> $DIR/unescaped_backticks.rs:131:1 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -716,7 +716,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same to this: Addition is commutative, which means that `add(a, b)` is the same as \`add(b, a). error: unescaped backtick - --> $DIR/unescaped_backticks.rs:135:5 + --> $DIR/unescaped_backticks.rs:136:5 | LL | /// `foo | ^ @@ -731,7 +731,7 @@ LL | /// \`foo | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:139:7 + --> $DIR/unescaped_backticks.rs:140:7 | LL | /// # `(heading | ^ @@ -746,7 +746,7 @@ LL | /// # \`(heading | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:141:17 + --> $DIR/unescaped_backticks.rs:142:17 | LL | /// ## heading2)` | ^ @@ -761,7 +761,7 @@ LL | /// ## heading2)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:144:11 + --> $DIR/unescaped_backticks.rs:145:11 | LL | /// multi `( | ^ @@ -776,7 +776,7 @@ LL | /// multi \`( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:150:10 + --> $DIR/unescaped_backticks.rs:151:10 | LL | /// para)`(graph | ^ @@ -795,7 +795,7 @@ LL | /// para)\`(graph | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:153:10 + --> $DIR/unescaped_backticks.rs:154:10 | LL | /// para)`(graph2 | ^ @@ -814,7 +814,7 @@ LL | /// para)\`(graph2 | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:156:12 + --> $DIR/unescaped_backticks.rs:157:12 | LL | /// 1. foo)` | ^ @@ -829,7 +829,7 @@ LL | /// 1. foo)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:158:8 + --> $DIR/unescaped_backticks.rs:159:8 | LL | /// 2. `(bar | ^ @@ -844,7 +844,7 @@ LL | /// 2. \`(bar | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:160:11 + --> $DIR/unescaped_backticks.rs:161:11 | LL | /// * baz)` | ^ @@ -859,7 +859,7 @@ LL | /// * baz)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:162:7 + --> $DIR/unescaped_backticks.rs:163:7 | LL | /// * `(quux | ^ @@ -874,7 +874,7 @@ LL | /// * \`(quux | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:165:5 + --> $DIR/unescaped_backticks.rs:166:5 | LL | /// `#![this_is_actually_an_image(and(not), an = "attribute")] | ^ @@ -889,7 +889,7 @@ LL | /// \`#![this_is_actually_an_image(and(not), an = "attribute")] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:168:62 + --> $DIR/unescaped_backticks.rs:169:62 | LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]` | ^ @@ -904,7 +904,7 @@ LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:173:7 + --> $DIR/unescaped_backticks.rs:174:7 | LL | /// | `table( | )head` | | ^ @@ -919,7 +919,7 @@ LL | /// | \`table( | )head` | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:173:22 + --> $DIR/unescaped_backticks.rs:174:22 | LL | /// | `table( | )head` | | ^ @@ -934,7 +934,7 @@ LL | /// | `table( | )head\` | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:177:12 + --> $DIR/unescaped_backticks.rs:178:12 | LL | /// | table`( | )`body | | ^ @@ -949,7 +949,7 @@ LL | /// | table\`( | )`body | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:177:18 + --> $DIR/unescaped_backticks.rs:178:18 | LL | /// | table`( | )`body | | ^ From 1476b39faed28f3c5121611c16617b0080cde53a Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 21 Jul 2023 01:21:58 +0800 Subject: [PATCH 114/169] Skip lint check when item is not fully public --- .../passes/lint/redundant_explicit_links.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 94d07ec034d7..343cc3163fb1 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -13,6 +13,7 @@ use crate::clean::Item; use crate::core::DocContext; use crate::html::markdown::main_body_opts; use crate::passes::source_span_for_markdown_range; +use crate::visit_ast::inherits_doc_hidden; #[derive(Debug)] struct LinkData { @@ -39,6 +40,24 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { return; } + let Some(item_id) = item.def_id() else { + return; + }; + let Some(local_item_id) = item_id.as_local() else { + return; + }; + + let is_hidden = !cx.render_options.document_hidden + && (item.is_doc_hidden() || inherits_doc_hidden(cx.tcx, local_item_id, None)); + if is_hidden { + return; + } + let is_private = !cx.render_options.document_private + && !cx.cache.effective_visibilities.is_directly_public(cx.tcx, item_id); + if is_private { + return; + } + check_redundant_explicit_link(cx, item, hir_id, &doc); } From 25919b09a963e776b0c35aa965aa47a04828e194 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 21 Jul 2023 03:54:58 +0800 Subject: [PATCH 115/169] Add regression test for inline doc --- tests/rustdoc-ui/lints/inline-doc-link.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/rustdoc-ui/lints/inline-doc-link.rs diff --git a/tests/rustdoc-ui/lints/inline-doc-link.rs b/tests/rustdoc-ui/lints/inline-doc-link.rs new file mode 100644 index 000000000000..596f89be3d6d --- /dev/null +++ b/tests/rustdoc-ui/lints/inline-doc-link.rs @@ -0,0 +1,13 @@ +// Regression test for + +// check-pass +#![deny(rustdoc::redundant_explicit_links)] + +mod m { + pub enum ValueEnum {} +} +mod m2 { + /// [`ValueEnum`] + pub use crate::m::ValueEnum; +} +pub use m2::ValueEnum; From 23c9a4a1cab1bb0442fe77aae305eb2864958427 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 21 Jul 2023 16:06:34 +0800 Subject: [PATCH 116/169] resolve conflicts --- library/alloc/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 41aac02eaa97..ffe6d6373875 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -89,6 +89,7 @@ #![allow(explicit_outlives_requirements)] #![warn(multiple_supertrait_upcastable)] #![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))] // // Library features: // tidy-alphabetical-start From fb148f682eb2ebeb2fd332ea43c57c6a5dd14130 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Aug 2023 09:39:30 +0200 Subject: [PATCH 117/169] `ignore-cross-compile` on `optimization-remarks-dir-pgo` test --- tests/run-make/optimization-remarks-dir-pgo/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-make/optimization-remarks-dir-pgo/Makefile b/tests/run-make/optimization-remarks-dir-pgo/Makefile index c88ec1e6cb30..3bc3d7d14288 100644 --- a/tests/run-make/optimization-remarks-dir-pgo/Makefile +++ b/tests/run-make/optimization-remarks-dir-pgo/Makefile @@ -1,5 +1,6 @@ # needs-profiler-support # ignore-windows-gnu +# ignore-cross-compile # FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works # properly. Since we only have GCC on the CI ignore the test for now. From 8e34c68c636b618f98bd2e11b2cf04b04b964a3c Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 18 Aug 2023 15:47:51 +0800 Subject: [PATCH 118/169] Fix private function importing --- src/librustdoc/passes/lint/redundant_explicit_links.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 343cc3163fb1..d71384045e71 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -13,7 +13,7 @@ use crate::clean::Item; use crate::core::DocContext; use crate::html::markdown::main_body_opts; use crate::passes::source_span_for_markdown_range; -use crate::visit_ast::inherits_doc_hidden; +use crate::clean::utils::inherits_doc_hidden; #[derive(Debug)] struct LinkData { From e17d2da2fcdd915a631d3ff25b4462397453e0f1 Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Fri, 18 Aug 2023 15:56:40 +0800 Subject: [PATCH 119/169] Fix format --- src/librustdoc/passes/lint/redundant_explicit_links.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index d71384045e71..ef0f8716aa88 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -9,11 +9,11 @@ use rustc_lint_defs::Applicability; use rustc_span::Symbol; use crate::clean::utils::find_nearest_parent_module; +use crate::clean::utils::inherits_doc_hidden; use crate::clean::Item; use crate::core::DocContext; use crate::html::markdown::main_body_opts; use crate::passes::source_span_for_markdown_range; -use crate::clean::utils::inherits_doc_hidden; #[derive(Debug)] struct LinkData { From cfbf1bf7cd300ddbfd2826488469c0921738685a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 28 Jun 2023 15:16:11 +0100 Subject: [PATCH 120/169] Do not create new resume block if there isn't one already --- .../src/remove_noop_landing_pads.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 4941c9edce30..4e85c76fbc06 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -6,8 +6,8 @@ use rustc_middle::ty::TyCtxt; use rustc_target::spec::PanicStrategy; /// A pass that removes noop landing pads and replaces jumps to them with -/// `None`. This is important because otherwise LLVM generates terrible -/// code for these. +/// `UnwindAction::Continue`. This is important because otherwise LLVM generates +/// terrible code for these. pub struct RemoveNoopLandingPads; impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { @@ -84,7 +84,17 @@ impl RemoveNoopLandingPads { fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { debug!("body: {:#?}", body); - // make sure there's a resume block + // Skip the pass if there are no blocks with a resume terminator. + let has_resume = body + .basic_blocks + .iter_enumerated() + .any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::Resume)); + if !has_resume { + debug!("remove_noop_landing_pads: no resume block in MIR"); + return; + } + + // make sure there's a resume block without any statements let resume_block = { let mut patch = MirPatch::new(body); let resume_block = patch.resume_block(); From cec8e09edf55fbf474c4414e3fec26d85c7869ff Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 28 Jun 2023 16:05:17 +0100 Subject: [PATCH 121/169] Run `AbortUnwindingCalls` after generator transform --- compiler/rustc_mir_transform/src/generator.rs | 16 +++++++++++++ ...await.a-{closure#0}.generator_resume.0.mir | 2 +- ...await.b-{closure#0}.generator_resume.0.mir | 2 +- tests/run-make/panic-abort-eh_frame/Makefile | 2 +- tests/run-make/panic-abort-eh_frame/foo.rs | 24 +++++++++++++++++++ 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 797a1a86846f..2bd759ab1e5d 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -50,8 +50,10 @@ //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing. //! Otherwise it drops all the values in scope at the last suspension point. +use crate::abort_unwinding_calls; use crate::deref_separator::deref_finder; use crate::errors; +use crate::pass_manager as pm; use crate::simplify; use crate::MirPass; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -64,6 +66,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::dump_mir; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; +use rustc_middle::ty::InstanceDef; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_middle::ty::{GeneratorArgs, GenericArgsRef}; use rustc_mir_dataflow::impls::{ @@ -1147,6 +1150,17 @@ fn create_generator_drop_shim<'tcx>( // unrelated code from the resume part of the function simplify::remove_dead_blocks(tcx, &mut body); + // Update the body's def to become the drop glue. + let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); + body.source.instance = InstanceDef::DropGlue(drop_in_place, Some(gen_ty)); + + pm::run_passes_no_validate( + tcx, + &mut body, + &[&abort_unwinding_calls::AbortUnwindingCalls], + None, + ); + dump_mir(tcx, false, "generator_drop", &0, &body, |_, _| Ok(())); body @@ -1317,6 +1331,8 @@ fn create_generator_resume_function<'tcx>( // unrelated code from the drop part of the function simplify::remove_dead_blocks(tcx, body); + pm::run_passes_no_validate(tcx, body, &[&abort_unwinding_calls::AbortUnwindingCalls], None); + dump_mir(tcx, false, "generator_resume", &0, body, |_, _| Ok(())); } diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir index 074ebddf78bb..9be5b8509c72 100644 --- a/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir @@ -30,7 +30,7 @@ fn a::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:11:14: 11:16]> } bb2: { - assert(const false, "`async fn` resumed after completion") -> [success: bb2, unwind continue]; + assert(const false, "`async fn` resumed after completion") -> [success: bb2, unwind unreachable]; } bb3: { diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir index f774f32eb23e..80ac92d59f3c 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir @@ -310,7 +310,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>, } bb28: { - assert(const false, "`async fn` resumed after completion") -> [success: bb28, unwind continue]; + assert(const false, "`async fn` resumed after completion") -> [success: bb28, unwind unreachable]; } bb29: { diff --git a/tests/run-make/panic-abort-eh_frame/Makefile b/tests/run-make/panic-abort-eh_frame/Makefile index 1cb7bf575cbd..7020455b742d 100644 --- a/tests/run-make/panic-abort-eh_frame/Makefile +++ b/tests/run-make/panic-abort-eh_frame/Makefile @@ -6,5 +6,5 @@ include ../tools.mk all: - $(RUSTC) foo.rs --crate-type=lib --emit=obj=$(TMPDIR)/foo.o -Cpanic=abort + $(RUSTC) foo.rs --crate-type=lib --emit=obj=$(TMPDIR)/foo.o -Cpanic=abort --edition 2021 -Z validate-mir objdump --dwarf=frames $(TMPDIR)/foo.o | $(CGREP) -v 'DW_CFA' diff --git a/tests/run-make/panic-abort-eh_frame/foo.rs b/tests/run-make/panic-abort-eh_frame/foo.rs index e18535294553..e2274d469e73 100644 --- a/tests/run-make/panic-abort-eh_frame/foo.rs +++ b/tests/run-make/panic-abort-eh_frame/foo.rs @@ -1,5 +1,13 @@ #![no_std] +use core::future::Future; + +pub struct NeedsDrop; + +impl Drop for NeedsDrop { + fn drop(&mut self) {} +} + #[panic_handler] fn handler(_: &core::panic::PanicInfo<'_>) -> ! { loop {} @@ -8,3 +16,19 @@ fn handler(_: &core::panic::PanicInfo<'_>) -> ! { pub unsafe fn oops(x: *const u32) -> u32 { *x } + +pub async fn foo(_: NeedsDrop) { + async fn bar() {} + bar().await; +} + +pub fn poll_foo(x: &mut core::task::Context<'_>) { + let _g = NeedsDrop; + let mut p = core::pin::pin!(foo(NeedsDrop)); + let _ = p.as_mut().poll(x); + let _ = p.as_mut().poll(x); +} + +pub fn drop_foo() { + drop(foo(NeedsDrop)); +} From 56b933763e9799f9deef86153d60988571188b49 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 28 Jun 2023 15:15:34 +0100 Subject: [PATCH 122/169] Add MIR validation for unwind out from nounwind functions --- .../src/transform/validate.rs | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 33e73ad66535..50ae30711a65 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -18,6 +18,7 @@ use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; use rustc_target::abi::{Size, FIRST_VARIANT}; +use rustc_target::spec::abi::Abi; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { @@ -58,6 +59,25 @@ impl<'tcx> MirPass<'tcx> for Validator { .iterate_to_fixpoint() .into_results_cursor(body); + let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) { + // In this case `AbortUnwindingCalls` haven't yet been executed. + true + } else if !tcx.def_kind(def_id).is_fn_like() { + true + } else { + let body_ty = tcx.type_of(def_id).skip_binder(); + let body_abi = match body_ty.kind() { + ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), + ty::Closure(..) => Abi::RustCall, + ty::Generator(..) => Abi::Rust, + _ => { + span_bug!(body.span, "unexpected body ty: {:?} phase {:?}", body_ty, mir_phase) + } + }; + + ty::layout::fn_can_unwind(tcx, Some(def_id), body_abi) + }; + let mut cfg_checker = CfgChecker { when: &self.when, body, @@ -68,6 +88,7 @@ impl<'tcx> MirPass<'tcx> for Validator { storage_liveness, place_cache: FxHashSet::default(), value_cache: FxHashSet::default(), + can_unwind, }; cfg_checker.visit_body(body); cfg_checker.check_cleanup_control_flow(); @@ -99,6 +120,9 @@ struct CfgChecker<'a, 'tcx> { storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>, place_cache: FxHashSet>, value_cache: FxHashSet, + // If `false`, then the MIR must not contain `UnwindAction::Continue` or + // `TerminatorKind::Resume`. + can_unwind: bool, } impl<'a, 'tcx> CfgChecker<'a, 'tcx> { @@ -237,13 +261,17 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { match unwind { UnwindAction::Cleanup(unwind) => { if is_cleanup { - self.fail(location, "unwind on cleanup block"); + self.fail(location, "`UnwindAction::Cleanup` in cleanup block"); } self.check_edge(location, unwind, EdgeKind::Unwind); } UnwindAction::Continue => { if is_cleanup { - self.fail(location, "unwind on cleanup block"); + self.fail(location, "`UnwindAction::Continue` in cleanup block"); + } + + if !self.can_unwind { + self.fail(location, "`UnwindAction::Continue` in no-unwind function"); } } UnwindAction::Unreachable | UnwindAction::Terminate => (), @@ -464,13 +492,19 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { ); } } - TerminatorKind::Resume | TerminatorKind::Terminate => { + TerminatorKind::Resume => { let bb = location.block; if !self.body.basic_blocks[bb].is_cleanup { - self.fail( - location, - "Cannot `Resume` or `Terminate` from non-cleanup basic block", - ) + self.fail(location, "Cannot `Resume` from non-cleanup basic block") + } + if !self.can_unwind { + self.fail(location, "Cannot `Resume` in a function that cannot unwind") + } + } + TerminatorKind::Terminate => { + let bb = location.block; + if !self.body.basic_blocks[bb].is_cleanup { + self.fail(location, "Cannot `Terminate` from non-cleanup basic block") } } TerminatorKind::Return => { From 907e431f9318eb83dd5aaab6dee67a88a97df787 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 28 Jun 2023 15:29:16 +0100 Subject: [PATCH 123/169] Perform MIR validation on drop glue of generator --- compiler/rustc_mir_transform/src/shim.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 5e8ba4f544c9..223dc59c68d1 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -71,8 +71,17 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // of this function. Is this intentional? if let Some(ty::Generator(gen_def_id, args, _)) = ty.map(Ty::kind) { let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap(); - let body = EarlyBinder::bind(body.clone()).instantiate(tcx, args); + let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args); debug!("make_shim({:?}) = {:?}", instance, body); + + // Run empty passes to mark phase change and perform validation. + pm::run_passes( + tcx, + &mut body, + &[], + Some(MirPhase::Runtime(RuntimePhase::Optimized)), + ); + return body; } From a8a92f5131cf350d5f16a6eed766a24a168c09b0 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 1 Aug 2023 16:30:02 +0100 Subject: [PATCH 124/169] Fix ABI flags in RISC-V/LoongArch ELF file generated by rustc --- .../rustc_codegen_ssa/src/back/metadata.rs | 37 ++++++++++--------- compiler/rustc_span/src/symbol.rs | 1 + 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 0be84c9fa833..ff5f1c230e28 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -16,6 +16,7 @@ use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; +use rustc_span::sym; use rustc_target::abi::Endian; use rustc_target::spec::{ef_avr_arch, RelocModel, Target}; @@ -272,35 +273,37 @@ pub(crate) fn create_object_file(sess: &Session) -> Option { // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc let mut e_flags: u32 = 0x0; - let features = &sess.target.options.features; + // Check if compressed is enabled - if features.contains("+c") { + if sess.unstable_target_features.contains(&sym::c) { e_flags |= elf::EF_RISCV_RVC; } - // Select the appropriate floating-point ABI - if features.contains("+d") { - e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE; - } else if features.contains("+f") { - e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE; - } else { - e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT; + // Set the appropriate flag based on ABI + // This needs to match LLVM `RISCVELFStreamer.cpp` + match &*sess.target.llvm_abiname { + "ilp32" | "lp64" => (), + "ilp32f" | "lp64f" => e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE, + "ilp32d" | "lp64d" => e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE, + "ilp32e" => e_flags |= elf::EF_RISCV_RVE, + _ => bug!("unknown RISC-V ABI name"), } + e_flags } Architecture::LoongArch64 => { // Source: https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc#e_flags-identifies-abi-type-and-version let mut e_flags: u32 = elf::EF_LARCH_OBJABI_V1; - let features = &sess.target.options.features; - // Select the appropriate floating-point ABI - if features.contains("+d") { - e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT; - } else if features.contains("+f") { - e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT; - } else { - e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT; + // Set the appropriate flag based on ABI + // This needs to match LLVM `LoongArchELFStreamer.cpp` + match &*sess.target.llvm_abiname { + "ilp32s" | "lp64s" => e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT, + "ilp32f" | "lp64f" => e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT, + "ilp32d" | "lp64d" => e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT, + _ => bug!("unknown RISC-V ABI name"), } + e_flags } Architecture::Avr => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index edbf51e9b33a..c8b8ff90c086 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -445,6 +445,7 @@ symbols! { bridge, bswap, builtin_syntax, + c, c_str, c_str_literals, c_unwind, From 83c713bff022acabc4dab30510f35122e29d0f53 Mon Sep 17 00:00:00 2001 From: ShE3py <52315535+she3py@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:04:53 +0200 Subject: [PATCH 125/169] Fix UB in `std::sys::os::getenv()` --- library/std/src/sys/solid/os.rs | 30 +++++++++++++++++++----------- library/std/src/sys/unix/os.rs | 21 +++++++++++++-------- library/std/src/sys/wasi/os.rs | 23 +++++++++++++++-------- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs index 717c08434a89..9f4e66d628b4 100644 --- a/library/std/src/sys/solid/os.rs +++ b/library/std/src/sys/solid/os.rs @@ -81,6 +81,10 @@ pub fn current_exe() -> io::Result { static ENV_LOCK: RwLock<()> = RwLock::new(()); +pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) +} + pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, } @@ -134,7 +138,7 @@ pub fn env() -> Env { } unsafe { - let _guard = ENV_LOCK.read(); + let _guard = env_read_lock(); let mut result = Vec::new(); if !environ.is_null() { while !(*environ).is_null() { @@ -168,17 +172,21 @@ pub fn env() -> Env { pub fn getenv(k: &OsStr) -> Option { // environment variables with a nul byte can't be set, so their value is // always None as well - let s = run_with_cstr(k.as_bytes(), |k| { - let _guard = ENV_LOCK.read(); - Ok(unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char) - }) - .ok()?; + run_with_cstr(k.as_bytes(), |k| { + let _guard = env_read_lock(); + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; - if s.is_null() { - None - } else { - Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec())) - } + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } + }) + .ok() + .flatten() } pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 215f63d04f77..57e1a36dace9 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -594,16 +594,21 @@ pub fn env() -> Env { pub fn getenv(k: &OsStr) -> Option { // environment variables with a nul byte can't be set, so their value is // always None as well - let s = run_with_cstr(k.as_bytes(), |k| { + run_with_cstr(k.as_bytes(), |k| { let _guard = env_read_lock(); - Ok(unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char) + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } }) - .ok()?; - if s.is_null() { - None - } else { - Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec())) - } + .ok() + .flatten() } pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index e0de284c5e24..d53bddd8e9df 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -225,16 +225,23 @@ pub fn env() -> Env { } pub fn getenv(k: &OsStr) -> Option { - let s = run_with_cstr(k.as_bytes(), |k| unsafe { + // environment variables with a nul byte can't be set, so their value is + // always None as well + run_with_cstr(k.as_bytes(), |k| { let _guard = env_read_lock(); - Ok(libc::getenv(k.as_ptr()) as *const libc::c_char) + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } }) - .ok()?; - if s.is_null() { - None - } else { - Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec())) - } + .ok() + .flatten() } pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { From aaf1b1bc93034e09e7a669d8fd64fe10ff5cf995 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 1 Aug 2023 20:55:07 +0100 Subject: [PATCH 126/169] Bless test changes --- tests/ui/or-patterns/missing-bindings.stderr | 68 +++++++++---------- .../resolve/resolve-inconsistent-names.stderr | 18 ++--- tests/ui/span/issue-39698.stderr | 20 +++--- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/tests/ui/or-patterns/missing-bindings.stderr b/tests/ui/or-patterns/missing-bindings.stderr index 8fafa275b5c2..4457b7893d5d 100644 --- a/tests/ui/or-patterns/missing-bindings.stderr +++ b/tests/ui/or-patterns/missing-bindings.stderr @@ -79,6 +79,14 @@ LL | let (A(A(..) | B(a), _) | B(A(a, _) | B(a))) = Y; | | | pattern doesn't bind `a` +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/missing-bindings.rs:45:12 + | +LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; + | ^^^^^^^ - variable not in all patterns + | | + | pattern doesn't bind `c` + error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:45:22 | @@ -96,12 +104,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | variable not in all patterns error[E0408]: variable `c` is not bound in all patterns - --> $DIR/missing-bindings.rs:45:12 + --> $DIR/missing-bindings.rs:45:33 | LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; - | ^^^^^^^ - variable not in all patterns - | | - | pattern doesn't bind `c` + | - ^^^^ pattern doesn't bind `c` + | | + | variable not in all patterns error[E0408]: variable `d` is not bound in all patterns --> $DIR/missing-bindings.rs:45:33 @@ -135,14 +143,6 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | | | variable not in all patterns -error[E0408]: variable `c` is not bound in all patterns - --> $DIR/missing-bindings.rs:45:33 - | -LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; - | - ^^^^ pattern doesn't bind `c` - | | - | variable not in all patterns - error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:61:29 | @@ -185,6 +185,28 @@ LL | B(b), LL | B(_) | ^^^^ pattern doesn't bind `b` +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/missing-bindings.rs:57:13 + | +LL | / V1( +LL | | +LL | | +LL | | A( +... | +LL | | B(Ok(a) | Err(a)) +LL | | ) | + | |_____________^ pattern doesn't bind `c` +LL | / V2( +LL | | A( +LL | | A(_, a) | +LL | | B(b), +... | +LL | | +LL | | ) | + | |_____________^ pattern doesn't bind `c` +LL | V3(c), + | - variable not in all patterns + error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:76:13 | @@ -215,28 +237,6 @@ LL | B(b), LL | V3(c), | ^^^^^ pattern doesn't bind `b` -error[E0408]: variable `c` is not bound in all patterns - --> $DIR/missing-bindings.rs:57:13 - | -LL | / V1( -LL | | -LL | | -LL | | A( -... | -LL | | B(Ok(a) | Err(a)) -LL | | ) | - | |_____________^ pattern doesn't bind `c` -LL | / V2( -LL | | A( -LL | | A(_, a) | -LL | | B(b), -... | -LL | | -LL | | ) | - | |_____________^ pattern doesn't bind `c` -LL | V3(c), - | - variable not in all patterns - error: aborting due to 26 previous errors For more information about this error, try `rustc --explain E0408`. diff --git a/tests/ui/resolve/resolve-inconsistent-names.stderr b/tests/ui/resolve/resolve-inconsistent-names.stderr index 023db303dd0f..42b7281d7b06 100644 --- a/tests/ui/resolve/resolve-inconsistent-names.stderr +++ b/tests/ui/resolve/resolve-inconsistent-names.stderr @@ -14,6 +14,15 @@ LL | a | b => {} | | | pattern doesn't bind `b` +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/resolve-inconsistent-names.rs:19:9 + | +LL | (A, B) | (ref B, c) | (c, A) => () + | ^^^^^^ - - variable not in all patterns + | | | + | | variable not in all patterns + | pattern doesn't bind `c` + error[E0408]: variable `A` is not bound in all patterns --> $DIR/resolve-inconsistent-names.rs:19:18 | @@ -37,15 +46,6 @@ LL | (A, B) | (ref B, c) | (c, A) => () | | variable not in all patterns | variable not in all patterns -error[E0408]: variable `c` is not bound in all patterns - --> $DIR/resolve-inconsistent-names.rs:19:9 - | -LL | (A, B) | (ref B, c) | (c, A) => () - | ^^^^^^ - - variable not in all patterns - | | | - | | variable not in all patterns - | pattern doesn't bind `c` - error[E0409]: variable `B` is bound inconsistently across alternatives separated by `|` --> $DIR/resolve-inconsistent-names.rs:19:23 | diff --git a/tests/ui/span/issue-39698.stderr b/tests/ui/span/issue-39698.stderr index 25c35fd5479f..81211b20a013 100644 --- a/tests/ui/span/issue-39698.stderr +++ b/tests/ui/span/issue-39698.stderr @@ -1,3 +1,13 @@ +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/issue-39698.rs:10:9 + | +LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `c` + | | | | + | | | variable not in all patterns + | | pattern doesn't bind `c` + | pattern doesn't bind `c` + error[E0408]: variable `d` is not bound in all patterns --> $DIR/issue-39698.rs:10:37 | @@ -28,16 +38,6 @@ LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?} | | variable not in all patterns | pattern doesn't bind `b` -error[E0408]: variable `c` is not bound in all patterns - --> $DIR/issue-39698.rs:10:9 - | -LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `c` - | | | | - | | | variable not in all patterns - | | pattern doesn't bind `c` - | pattern doesn't bind `c` - error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0408`. From 5ed556e84afe5b51681da111941f0bf990e34532 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 2 Aug 2023 19:21:19 +0100 Subject: [PATCH 127/169] Add comment explanining unstable_target_features --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ff5f1c230e28..971fa1c7aa8e 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -275,6 +275,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option Date: Fri, 4 Aug 2023 15:56:01 +0100 Subject: [PATCH 128/169] Fix ELF flag for RISC-V targets without explicit ABI --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 971fa1c7aa8e..4c8547407531 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -283,7 +283,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option (), + "" | "ilp32" | "lp64" => (), "ilp32f" | "lp64f" => e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE, "ilp32d" | "lp64d" => e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE, "ilp32e" => e_flags |= elf::EF_RISCV_RVE, From 7bd5aa5c14be38c5f750ed5baadbeb78d4ec13d5 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 6 Aug 2023 17:47:14 -0400 Subject: [PATCH 129/169] Add release notes for 1.72.0 --- RELEASES.md | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index e8c79c573f97..722f7e5dd083 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,108 @@ +Version 1.72.0 (2023-08-24) +========================== + + + +Language +-------- + +- [Replace const eval limit by a lint and add an exponential backoff warning](https://github.com/rust-lang/rust/pull/103877/) +- [expand: Change how `#![cfg(FALSE)]` behaves on crate root](https://github.com/rust-lang/rust/pull/110141/) +- [Stabilize inline asm for LoongArch64](https://github.com/rust-lang/rust/pull/111235/) +- [Uplift `clippy::undropped_manually_drops` lint](https://github.com/rust-lang/rust/pull/111530/) +- [Uplift `clippy::invalid_utf8_in_unchecked` lint](https://github.com/rust-lang/rust/pull/111543/) +- [Uplift `clippy::cast_ref_to_mut` lint](https://github.com/rust-lang/rust/pull/111567/) +- [Uplift `clippy::cmp_nan` lint](https://github.com/rust-lang/rust/pull/111818/) +- [resolve: Remove artificial import ambiguity errors](https://github.com/rust-lang/rust/pull/112086/) +- [Don't require associated types with Self: Sized bounds in `dyn Trait` objects](https://github.com/rust-lang/rust/pull/112319/) + + + +Compiler +-------- + +- [Remember names of `cfg`-ed out items to mention them in diagnostics](https://github.com/rust-lang/rust/pull/109005/) +- [Support for native WASM exceptions](https://github.com/rust-lang/rust/pull/111322/) +- [Add support for NetBSD/aarch64-be (big-endian arm64).](https://github.com/rust-lang/rust/pull/111326/) +- [Write to stdout if `-` is given as output file](https://github.com/rust-lang/rust/pull/111626/) +- [Force all native libraries to be statically linked when linking a static binary](https://github.com/rust-lang/rust/pull/111698/) +- [Add Tier 3 support for `loongarch64-unknown-none*`](https://github.com/rust-lang/rust/pull/112310/) +- [Prevent `.eh_frame` from being emitted for `-C panic=abort`](https://github.com/rust-lang/rust/pull/112403/) +- [Support 128-bit enum variant in debuginfo codegen](https://github.com/rust-lang/rust/pull/112474/) +- [compiler: update solaris/illumos to enable tsan support.](https://github.com/rust-lang/rust/pull/112039/) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + + +Libraries +--------- + +- [Document memory orderings of `thread::{park, unpark}`](https://github.com/rust-lang/rust/pull/99587/) +- [io: soften ‘at most one write attempt’ requirement in io::Write::write](https://github.com/rust-lang/rust/pull/107200/) +- [Specify behavior of HashSet::insert](https://github.com/rust-lang/rust/pull/107619/) +- [Relax implicit `T: Sized` bounds on `BufReader`, `BufWriter` and `LineWriter`](https://github.com/rust-lang/rust/pull/111074/) +- [Update runtime guarantee for `select_nth_unstable`](https://github.com/rust-lang/rust/pull/111974/) +- [Return `Ok` on kill if process has already exited](https://github.com/rust-lang/rust/pull/112594/) +- [Implement PartialOrd for `Vec`s over different allocators](https://github.com/rust-lang/rust/pull/112632/) +- [Use 128 bits for TypeId hash](https://github.com/rust-lang/rust/pull/109953/) +- [Don't drain-on-drop in DrainFilter impls of various collections.](https://github.com/rust-lang/rust/pull/104455/) +- [Make `{Arc,Rc,Weak}::ptr_eq` ignore pointer metadata](https://github.com/rust-lang/rust/pull/106450/) + + + +Rustdoc +------- + +- [Allow whitespace as path separator like double colon](https://github.com/rust-lang/rust/pull/108537/) +- [Add search result item types after their name](https://github.com/rust-lang/rust/pull/110688/) +- [Search for slices and arrays by type with `[]`](https://github.com/rust-lang/rust/pull/111958/) +- [Clean up type unification and "unboxing"](https://github.com/rust-lang/rust/pull/112233/) + + + +Stabilized APIs +--------------- + +- [`impl Sync for mpsc::Sender`](https://doc.rust-lang.org/nightly/std/sync/mpsc/struct.Sender.html#impl-Sync-for-Sender%3CT%3E) +- [`impl TryFrom<&OsStr> for &str`](https://doc.rust-lang.org/nightly/std/primitive.str.html#impl-TryFrom%3C%26'a+OsStr%3E-for-%26'a+str) +- [`String::leak`](https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.leak) + +These APIs are now stable in const contexts: + +- [`CStr::from_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul) +- [`CStr::to_bytes`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul) +- [`CStr::to_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul) +- [`CStr::to_str`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul) + + + +Cargo +----- + +- Enable `-Zdoctest-in-workspace` by default. When running each documentation + test, the working directory is set to the root directory of the package the + test belongs to. + [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-test.html#working-directory-of-tests) + [#12221](https://github.com/rust-lang/cargo/pull/12221) + [#12288](https://github.com/rust-lang/cargo/pull/12288) +- Add support of the "default" keyword to reset previously set `build.jobs` + parallelism back to the default. + [#12222](https://github.com/rust-lang/cargo/pull/12222) + + + +Compatibility Notes +------------------- + +- [Alter `Display` for `Ipv6Addr` for IPv4-compatible addresses](https://github.com/rust-lang/rust/pull/112606/) +- Cargo changed feature name validation check to a hard error. The warning was + added in Rust 1.49. These extended characters aren't allowed on crates.io, so + this should only impact users of other registries, or people who don't publish + to a registry. + [#12291](https://github.com/rust-lang/cargo/pull/12291) + Version 1.71.0 (2023-07-13) ========================== From c353dbd57ffdfdbc0d896999b126f1db50dc2413 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 18 Aug 2023 07:52:57 -0700 Subject: [PATCH 130/169] Add doc aliases for trigonometry and other f32,f64 methods. These are common alternate names, usually a less-abbreviated form, for the operation; e.g. `arctan` instead of `atan`. Prompted by --- library/std/src/f32.rs | 9 +++++++++ library/std/src/f64.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index a53b85352136..d380d95b6e7f 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -61,6 +61,7 @@ impl f32 { /// assert_eq!(f.ceil(), 4.0); /// assert_eq!(g.ceil(), 4.0); /// ``` + #[doc(alias = "ceiling")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -135,6 +136,7 @@ impl f32 { /// assert_eq!(g.trunc(), 3.0); /// assert_eq!(h.trunc(), -3.0); /// ``` + #[doc(alias = "truncate")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -672,6 +674,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[doc(alias = "arcsin")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -694,6 +697,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[doc(alias = "arccos")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -715,6 +719,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[doc(alias = "arctan")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -772,6 +777,7 @@ impl f32 { /// assert!(abs_difference_0 <= f32::EPSILON); /// assert!(abs_difference_1 <= f32::EPSILON); /// ``` + #[doc(alias = "sincos")] #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -904,6 +910,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[doc(alias = "arcsinh")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -926,6 +933,7 @@ impl f32 { /// /// assert!(abs_difference <= f32::EPSILON); /// ``` + #[doc(alias = "arccosh")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -950,6 +958,7 @@ impl f32 { /// /// assert!(abs_difference <= 1e-5); /// ``` + #[doc(alias = "arctanh")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index a1cec22c97ae..1302782c5b07 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -61,6 +61,7 @@ impl f64 { /// assert_eq!(f.ceil(), 4.0); /// assert_eq!(g.ceil(), 4.0); /// ``` + #[doc(alias = "ceiling")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -135,6 +136,7 @@ impl f64 { /// assert_eq!(g.trunc(), 3.0); /// assert_eq!(h.trunc(), -3.0); /// ``` + #[doc(alias = "truncate")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -672,6 +674,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[doc(alias = "arcsin")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -694,6 +697,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[doc(alias = "arccos")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -715,6 +719,7 @@ impl f64 { /// /// assert!(abs_difference < 1e-10); /// ``` + #[doc(alias = "arctan")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -772,6 +777,7 @@ impl f64 { /// assert!(abs_difference_0 < 1e-10); /// assert!(abs_difference_1 < 1e-10); /// ``` + #[doc(alias = "sincos")] #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -904,6 +910,7 @@ impl f64 { /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[doc(alias = "arcsinh")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -926,6 +933,7 @@ impl f64 { /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[doc(alias = "arccosh")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -950,6 +958,7 @@ impl f64 { /// /// assert!(abs_difference < 1.0e-10); /// ``` + #[doc(alias = "arctanh")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] From eb4d6d9ff72d09eee908340d8d8726b5644ae86e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 18 Aug 2023 16:19:26 +0100 Subject: [PATCH 131/169] Add missing instantiation of generator ty in validator --- compiler/rustc_const_eval/src/transform/validate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 50ae30711a65..783b52d00402 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -699,7 +699,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { return; }; - f_ty.ty + ty::EarlyBinder::bind(f_ty.ty).instantiate(self.tcx, args) } else { let Some(&f_ty) = args.as_generator().prefix_tys().get(f.index()) else { From 0a7202d4769fe417988b7e74333e3014a51ad462 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 18 Aug 2023 16:36:22 +0100 Subject: [PATCH 132/169] Change generator_drop's instance to that of generator for dump_mir Otherwise the file name generated for generator_drop will become core.ptr-drop_in_place.[generator@_].generator_drop.0.mir instead of main-{closure#0}.generator_drop.0.mir which breaks a mir-opt test. --- compiler/rustc_mir_transform/src/generator.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 2bd759ab1e5d..ff4822f333f0 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1151,8 +1151,11 @@ fn create_generator_drop_shim<'tcx>( simplify::remove_dead_blocks(tcx, &mut body); // Update the body's def to become the drop glue. + // This needs to be updated before the AbortUnwindingCalls pass. + let gen_instance = body.source.instance; let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); - body.source.instance = InstanceDef::DropGlue(drop_in_place, Some(gen_ty)); + let drop_instance = InstanceDef::DropGlue(drop_in_place, Some(gen_ty)); + body.source.instance = drop_instance; pm::run_passes_no_validate( tcx, @@ -1161,7 +1164,11 @@ fn create_generator_drop_shim<'tcx>( None, ); + // Temporary change MirSource to generator's instance so that dump_mir produces more sensible + // filename. + body.source.instance = gen_instance; dump_mir(tcx, false, "generator_drop", &0, &body, |_, _| Ok(())); + body.source.instance = drop_instance; body } From 26fe88fedb19a4118d58a6e439709759f65c63c9 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 15 Nov 2022 23:06:53 +0000 Subject: [PATCH 133/169] Add a test to check that inline const is in required_consts Suggested in https://github.com/rust-lang/rust/issues/76001#issuecomment-1315975027 --- tests/ui/inline-const/required-const.rs | 13 +++++++++++++ tests/ui/inline-const/required-const.stderr | 11 +++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/ui/inline-const/required-const.rs create mode 100644 tests/ui/inline-const/required-const.stderr diff --git a/tests/ui/inline-const/required-const.rs b/tests/ui/inline-const/required-const.rs new file mode 100644 index 000000000000..0483410662bf --- /dev/null +++ b/tests/ui/inline-const/required-const.rs @@ -0,0 +1,13 @@ +// build-fail +// compile-flags: -Zmir-opt-level=3 +#![feature(inline_const)] + +fn foo() { + if false { + const { panic!() } //~ ERROR E0080 + } +} + +fn main() { + foo::(); +} diff --git a/tests/ui/inline-const/required-const.stderr b/tests/ui/inline-const/required-const.stderr new file mode 100644 index 000000000000..d6948e7acc03 --- /dev/null +++ b/tests/ui/inline-const/required-const.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of `foo::::{constant#0}` failed + --> $DIR/required-const.rs:7:17 + | +LL | const { panic!() } + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/required-const.rs:7:17 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From 74942daf712c0b8cbba50864f22ca5bd919ab1cb Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 18 Aug 2023 13:05:49 -0400 Subject: [PATCH 134/169] Expose core::error::request_value in std I think this was simply forgotten in #113464. --- library/std/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 7bc3af1793e3..375ff2d24504 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -10,7 +10,7 @@ use crate::fmt::{self, Write}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::error::Error; #[unstable(feature = "error_generic_member_access", issue = "99301")] -pub use core::error::{request_ref, Request}; +pub use core::error::{request_ref, request_value, Request}; mod private { // This is a hack to prevent `type_id` from being overridden by `Error` From c0394c8ac066b8c31cc114838bcb2507a349cf25 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Sat, 22 Jul 2023 17:16:18 +0200 Subject: [PATCH 135/169] Add the relocation_model to the cfg This way is possible to write inline assembly code aware of it. --- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_session/src/config.rs | 12 ++++- compiler/rustc_span/src/symbol.rs | 8 +++ compiler/rustc_target/src/spec/mod.rs | 50 +++++++++++++++---- tests/ui/abi/relocation_model_pic.rs | 9 ++++ .../feature-gate-cfg-relocation-model.rs | 4 ++ .../feature-gate-cfg-relocation-model.stderr | 12 +++++ 8 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 tests/ui/abi/relocation_model_pic.rs create mode 100644 tests/ui/feature-gates/feature-gate-cfg-relocation-model.rs create mode 100644 tests/ui/feature-gates/feature-gate-cfg-relocation-model.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 953ea1bf523d..f5708f933d50 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -352,6 +352,8 @@ declare_features! ( (active, c_variadic, "1.34.0", Some(44930), None), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. (active, cfg_overflow_checks, "1.71.0", Some(111466), None), + /// Provides the relocation model information as cfg entry + (active, cfg_relocation_model, "CURRENT_RUSTC_VERSION", Some(114929), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a183cfd8776a..2f7cff3ce5c8 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -35,6 +35,7 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), + (sym::relocation_model, sym::cfg_relocation_model, cfg_fn!(cfg_relocation_model)), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 28ae88424ab1..f00472f181d8 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,7 +12,7 @@ use crate::{EarlyErrorHandler, Session}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_target::abi::Align; -use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo}; +use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use crate::parse::{CrateCheckConfig, CrateConfig}; @@ -1193,6 +1193,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let os = &sess.target.os; let env = &sess.target.env; let abi = &sess.target.abi; + let relocation_model = sess.target.relocation_model.desc_symbol(); let vendor = &sess.target.vendor; let min_atomic_width = sess.target.min_atomic_width(); let max_atomic_width = sess.target.max_atomic_width(); @@ -1218,6 +1219,9 @@ fn default_configuration(sess: &Session) -> CrateConfig { ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz)))); ret.insert((sym::target_env, Some(Symbol::intern(env)))); ret.insert((sym::target_abi, Some(Symbol::intern(abi)))); + if sess.is_nightly_build() { + ret.insert((sym::relocation_model, Some(relocation_model))); + } ret.insert((sym::target_vendor, Some(Symbol::intern(vendor)))); if sess.target.has_thread_local { ret.insert((sym::target_thread_local, None)); @@ -1415,6 +1419,8 @@ impl CrateCheckConfig { .into_iter() .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap())); + let relocation_model_values = RelocModel::all(); + // Unknown possible values: // - `feature` // - `target_feature` @@ -1453,6 +1459,10 @@ impl CrateCheckConfig { .entry(sym::target_has_atomic_equal_alignment) .or_insert_with(no_values) .extend(atomic_values); + self.expecteds + .entry(sym::relocation_model) + .or_insert_with(empty_values) + .extend(relocation_model_values); // Target specific values { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index edbf51e9b33a..e511898513af 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -468,6 +468,7 @@ symbols! { cfg_hide, cfg_overflow_checks, cfg_panic, + cfg_relocation_model, cfg_sanitize, cfg_target_abi, cfg_target_compact, @@ -661,6 +662,7 @@ symbols! { dyn_metadata, dyn_star, dyn_trait, + dynamic_no_pic: "dynamic-no-pic", e, edition_panic, effects, @@ -1115,6 +1117,8 @@ symbols! { path, pattern_parentheses, phantom_data, + pic, + pie, pin, platform_intrinsics, plugin, @@ -1223,6 +1227,7 @@ symbols! { register_tool, relaxed_adts, relaxed_struct_unsize, + relocation_model, rem, rem_assign, repr, @@ -1243,6 +1248,8 @@ symbols! { rintf64, riscv_target_feature, rlib, + ropi, + ropi_rwpi: "ropi-rwpi", rotate_left, rotate_right, roundevenf32, @@ -1354,6 +1361,7 @@ symbols! { rustdoc_missing_doc_code_examples, rustfmt, rvalue_static_promotion, + rwpi, s, safety, sanitize, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index e18f35ac5ffd..31b6961bb622 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -42,7 +42,7 @@ use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_fs_util::try_canonicalize; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use serde_json::Value; use std::borrow::Cow; use std::collections::BTreeMap; @@ -655,6 +655,43 @@ pub enum RelocModel { RopiRwpi, } +impl RelocModel { + pub fn desc(&self) -> &str { + match *self { + RelocModel::Static => "static", + RelocModel::Pic => "pic", + RelocModel::Pie => "pie", + RelocModel::DynamicNoPic => "dynamic-no-pic", + RelocModel::Ropi => "ropi", + RelocModel::Rwpi => "rwpi", + RelocModel::RopiRwpi => "ropi-rwpi", + } + } + pub const fn desc_symbol(&self) -> Symbol { + match *self { + RelocModel::Static => kw::Static, + RelocModel::Pic => sym::pic, + RelocModel::Pie => sym::pie, + RelocModel::DynamicNoPic => sym::dynamic_no_pic, + RelocModel::Ropi => sym::ropi, + RelocModel::Rwpi => sym::rwpi, + RelocModel::RopiRwpi => sym::ropi_rwpi, + } + } + + pub const fn all() -> [Symbol; 7] { + [ + RelocModel::Static.desc_symbol(), + RelocModel::Pic.desc_symbol(), + RelocModel::Pie.desc_symbol(), + RelocModel::DynamicNoPic.desc_symbol(), + RelocModel::Ropi.desc_symbol(), + RelocModel::Rwpi.desc_symbol(), + RelocModel::RopiRwpi.desc_symbol(), + ] + } +} + impl FromStr for RelocModel { type Err = (); @@ -674,16 +711,7 @@ impl FromStr for RelocModel { impl ToJson for RelocModel { fn to_json(&self) -> Json { - match *self { - RelocModel::Static => "static", - RelocModel::Pic => "pic", - RelocModel::Pie => "pie", - RelocModel::DynamicNoPic => "dynamic-no-pic", - RelocModel::Ropi => "ropi", - RelocModel::Rwpi => "rwpi", - RelocModel::RopiRwpi => "ropi-rwpi", - } - .to_json() + self.desc().to_json() } } diff --git a/tests/ui/abi/relocation_model_pic.rs b/tests/ui/abi/relocation_model_pic.rs new file mode 100644 index 000000000000..0cfc44cd09d8 --- /dev/null +++ b/tests/ui/abi/relocation_model_pic.rs @@ -0,0 +1,9 @@ +// run-pass +// compile-flags: -C relocation-model=pic +// ignore-emscripten no pic +// ignore-wasm + +#![feature(cfg_relocation_model)] + +#[cfg(relocation_model = "pic")] +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-relocation-model.rs b/tests/ui/feature-gates/feature-gate-cfg-relocation-model.rs new file mode 100644 index 000000000000..7529014ece2c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-relocation-model.rs @@ -0,0 +1,4 @@ +#[cfg(relocation_model = "pic")] //~ ERROR +fn _foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-relocation-model.stderr b/tests/ui/feature-gates/feature-gate-cfg-relocation-model.stderr new file mode 100644 index 000000000000..592768a42031 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-relocation-model.stderr @@ -0,0 +1,12 @@ +error[E0658]: `cfg(relocation_model)` is experimental and subject to change + --> $DIR/feature-gate-cfg-relocation-model.rs:1:7 + | +LL | #[cfg(relocation_model = "pic")] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #114929 for more information + = help: add `#![feature(cfg_relocation_model)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From df8aed400b9e496062f865f4991af7606c6c1e87 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 18 Aug 2023 19:20:28 +0200 Subject: [PATCH 136/169] More error details upon unexpected incr-comp session dir --- compiler/rustc_incremental/src/persist/fs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 1111a1a17e29..6b894c3a69d8 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -538,8 +538,8 @@ where continue; } - let timestamp = extract_timestamp_from_session_dir(&directory_name).unwrap_or_else(|_| { - bug!("unexpected incr-comp session dir: {}", session_dir.display()) + let timestamp = extract_timestamp_from_session_dir(&directory_name).unwrap_or_else(|e| { + bug!("unexpected incr-comp session dir: {}: {}", session_dir.display(), e) }); if timestamp > best_candidate.0 { @@ -562,14 +562,14 @@ fn is_session_directory_lock_file(file_name: &str) -> bool { file_name.starts_with("s-") && file_name.ends_with(LOCK_FILE_EXT) } -fn extract_timestamp_from_session_dir(directory_name: &str) -> Result { +fn extract_timestamp_from_session_dir(directory_name: &str) -> Result { if !is_session_directory(directory_name) { - return Err(()); + return Err("not a directory"); } let dash_indices: Vec<_> = directory_name.match_indices('-').map(|(idx, _)| idx).collect(); if dash_indices.len() != 3 { - return Err(()); + return Err("not three dashes in name"); } string_to_timestamp(&directory_name[dash_indices[0] + 1..dash_indices[1]]) @@ -581,11 +581,11 @@ fn timestamp_to_string(timestamp: SystemTime) -> String { base_n::encode(micros as u128, INT_ENCODE_BASE) } -fn string_to_timestamp(s: &str) -> Result { +fn string_to_timestamp(s: &str) -> Result { let micros_since_unix_epoch = u64::from_str_radix(s, INT_ENCODE_BASE as u32); if micros_since_unix_epoch.is_err() { - return Err(()); + return Err("timestamp not an int"); } let micros_since_unix_epoch = micros_since_unix_epoch.unwrap(); From 64e8aea9ce6f40083445d9c161d233499ee559cd Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 18 Aug 2023 19:20:28 +0200 Subject: [PATCH 137/169] Ignore unexpected incr-comp session dirs Clearly the code path can be hit without the presence of a compiler bug. All it takes is mischief. See 71698. Ignore problematic directories instead of ICE:ing. `continue`ing is already done for problematic dirs in the code block above us. --- compiler/rustc_incremental/src/persist/fs.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 6b894c3a69d8..db8ea2bfe48a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -538,9 +538,13 @@ where continue; } - let timestamp = extract_timestamp_from_session_dir(&directory_name).unwrap_or_else(|e| { - bug!("unexpected incr-comp session dir: {}: {}", session_dir.display(), e) - }); + let timestamp = match extract_timestamp_from_session_dir(&directory_name) { + Ok(timestamp) => timestamp, + Err(e) => { + debug!("unexpected incr-comp session dir: {}: {}", session_dir.display(), e); + continue; + } + }; if timestamp > best_candidate.0 { best_candidate = (timestamp, Some(session_dir.clone())); From 297ff8c97ef7b34e620e8f016361227f0be79a7c Mon Sep 17 00:00:00 2001 From: Kyle Lin Date: Sat, 19 Aug 2023 02:22:13 +0800 Subject: [PATCH 138/169] Fix redundant explicit link in rustc_borrowck --- compiler/rustc_borrowck/src/consumers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index d257145373f7..becfa535a59c 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -30,7 +30,7 @@ pub use super::{ /// will be retrieved. #[derive(Debug, Copy, Clone)] pub enum ConsumerOptions { - /// Retrieve the [`Body`] along with the [`BorrowSet`](super::borrow_set::BorrowSet) + /// Retrieve the [`Body`] along with the [`BorrowSet`] /// and [`RegionInferenceContext`]. If you would like the body only, use /// [`TyCtxt::mir_promoted`]. /// From 2c2163538246ad528e57e87db021d7528060aa65 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 18 Aug 2023 08:09:00 -0700 Subject: [PATCH 139/169] Add `modulo` and `mod` as doc aliases for `rem_euclid`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When I was learning Rust I looked for “a modulo function” and couldn’t find one, so thought I had to write my own; it wasn't at all obvious that a function with “rem” in the name was the function I wanted. Hopefully this will save the next learner from that. However, it does have the disadvantage that the top results in rustdoc for “mod” are now these aliases instead of the Rust keyword, which probably isn't ideal. --- library/core/src/num/int_macros.rs | 1 + library/core/src/num/uint_macros.rs | 1 + library/std/src/f32.rs | 1 + library/std/src/f64.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 1199d09b563d..1f43520e1b30 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2126,6 +2126,7 @@ macro_rules! int_impl { /// assert_eq!(a.rem_euclid(-b), 3); /// assert_eq!((-a).rem_euclid(-b), 1); /// ``` + #[doc(alias = "modulo", alias = "mod")] #[stable(feature = "euclidean_division", since = "1.38.0")] #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 2136d29255f7..81148c7cc51f 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2024,6 +2024,7 @@ macro_rules! uint_impl { /// ``` #[doc = concat!("assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type")] /// ``` + #[doc(alias = "modulo", alias = "mod")] #[stable(feature = "euclidean_division", since = "1.38.0")] #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index a53b85352136..3b74febc20d4 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -321,6 +321,7 @@ impl f32 { /// // limitation due to round-off error /// assert!((-f32::EPSILON).rem_euclid(3.0) != 0.0); /// ``` + #[doc(alias = "modulo", alias = "mod")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[inline] diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index a1cec22c97ae..4c068a7a7abb 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -321,6 +321,7 @@ impl f64 { /// // limitation due to round-off error /// assert!((-f64::EPSILON).rem_euclid(3.0) != 0.0); /// ``` + #[doc(alias = "modulo", alias = "mod")] #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[inline] From 11716830ace2bb94a53a9003fcb8842df0c302bb Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 17 Aug 2023 15:15:09 +0200 Subject: [PATCH 140/169] instantiate response: no unnecessary new universe this previously was a off-by-one error. --- .../src/solve/eval_ctxt/canonical.rs | 2 +- .../generalize-proj-new-universe-index-1.rs | 73 ++++++++++++++++++ .../generalize-proj-new-universe-index-2.rs | 75 +++++++++++++++++++ ...eneralize-proj-new-universe-index-2.stderr | 9 +++ 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-1.rs create mode 100644 tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs create mode 100644 tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 0990b9bee90f..523841951b07 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -215,7 +215,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // created inside of the query directly instead of returning them to the // caller. let prev_universe = self.infcx.universe(); - let universes_created_in_query = response.max_universe.index() + 1; + let universes_created_in_query = response.max_universe.index(); for _ in 0..universes_created_in_query { self.infcx.create_next_universe(); } diff --git a/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-1.rs b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-1.rs new file mode 100644 index 000000000000..b0b9b6bbd206 --- /dev/null +++ b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-1.rs @@ -0,0 +1,73 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +// A minimization of an ambiguity when using typenum. See +// https://github.com/rust-lang/trait-system-refactor-initiative/issues/55 +// for more details. +trait Id { + type Assoc: ?Sized; +} +impl Id for T { + type Assoc = T; +} + +trait WithAssoc { + type Assoc: ?Sized; +} + + +struct Leaf; +struct Wrapper(U); + +impl WithAssoc for Leaf { + type Assoc = U; +} + +impl WithAssoc> for Wrapper
      +where + Ul: WithAssoc, +{ + type Assoc = <
        >::Assoc as Id>::Assoc; +} + +fn bound() +where + T: WithAssoc, +{ +} + +// normalize self type to `Wrapper` +// This succeeds, HOWEVER, instantiating the query response previously +// incremented the universe index counter. +// equate impl headers: +// as WithAssoc< as Id>::Assoc>> +// as WithAssoc>> +// ~> AliasRelate( as Id>::Assoc, Equate, Wrapper) +// add where bounds: +// ~> Leaf: WithAssoc +// equate with assoc type: +// ?0t +// >::Assoc as Id>::Assoc +// ~> AliasRelate( +// <>::Assoc as Id>::Assoc, +// Equate, +// <>::Assoc as Id>::Assoc, +// ) +// +// We do not reuse `?3t` during generalization because `?0t` cannot name `?4t` as we created +// it after incrementing the universe index while normalizing the self type. +// +// evaluate_added_goals_and_make_query_response: +// AliasRelate( as Id>::Assoc, Equate, Wrapper) +// YES, constrains ?3t to Leaf +// AliasRelate( +// <>::Assoc as Id>::Assoc, +// Equate, +// <>::Assoc as Id>::Assoc, +// ) +// +// Normalizing <>::Assoc as Id>::Assoc then *correctly* +// results in ambiguity. +fn main() { + bound::< as Id>::Assoc, as Id>::Assoc, _>() +} diff --git a/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs new file mode 100644 index 000000000000..544051fca433 --- /dev/null +++ b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs @@ -0,0 +1,75 @@ +// compile-flags: -Ztrait-solver=next + +// Generalizing a projection containing an inference variable +// which cannot be named by the `root_vid` can result in ambiguity. +// +// Because we do not decrement the universe index when exiting a forall, +// this can cause unexpected failures. +// +// See generalize-proj-new-universe-index-1.rs for more details. + +// For this reproduction we need: +// - an inference variable with a lower universe +// - enter a binder to increment the current universe +// - create a new inference variable which is constrained by proving a goal +// - equate a projection containing the new variable with the first variable +// - generalization creates yet another inference variable which is then +// part of an alias-relate, resulting this to fail with ambiguity. +// +// Because we need to enter the binder in-between the creation of the first +// and second inference variable, this is easiest via +// `assemble_candidates_after_normalizing_self_ty` because eagerly call +// `try_evaluate_added_goals` there before creating the inference variables +// for the impl parameters. +trait Id { + type Assoc: ?Sized; +} +impl Id for T { + type Assoc = T; +} + +// By adding an higher ranked bound to the impl we currently +// propagate this bound to the caller, forcing us to create a new +// universe. +trait IdHigherRankedBound { + type Assoc: ?Sized; +} + +impl IdHigherRankedBound for T +where + for<'a> T: 'a, +{ + type Assoc = T; +} + +trait WithAssoc { + type Assoc: ?Sized; +} + + +struct Leaf; +struct Wrapper(U); +struct Rigid; + +impl WithAssoc for Leaf { + type Assoc = U; +} + + +impl WithAssoc> for Rigid +where + Leaf: WithAssoc, +{ + type Assoc = <>::Assoc as Id>::Assoc; +} + +fn bound() +where + T: WithAssoc, +{ +} + +fn main() { + bound::<::Assoc, as Id>::Assoc, _>() + //~^ ERROR type annotations needed +} diff --git a/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr new file mode 100644 index 000000000000..3fe96c868880 --- /dev/null +++ b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/generalize-proj-new-universe-index-2.rs:72:5 + | +LL | bound::<::Assoc, as Id>::Assoc, _>() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `V` declared on the function `bound` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. From ee04744e6411368e9cf3460bde8396999778a6f8 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 18 Aug 2023 23:59:49 +0200 Subject: [PATCH 141/169] change to known bug --- .../generalize/generalize-proj-new-universe-index-2.rs | 2 +- .../generalize/generalize-proj-new-universe-index-2.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs index 544051fca433..94d645a98592 100644 --- a/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs +++ b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.rs @@ -1,4 +1,5 @@ // compile-flags: -Ztrait-solver=next +// known-bug: trait-system-refactor-initiative#60 // Generalizing a projection containing an inference variable // which cannot be named by the `root_vid` can result in ambiguity. @@ -71,5 +72,4 @@ where fn main() { bound::<::Assoc, as Id>::Assoc, _>() - //~^ ERROR type annotations needed } diff --git a/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr index 3fe96c868880..9a8060133b81 100644 --- a/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr +++ b/tests/ui/traits/new-solver/generalize/generalize-proj-new-universe-index-2.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/generalize-proj-new-universe-index-2.rs:72:5 + --> $DIR/generalize-proj-new-universe-index-2.rs:74:5 | LL | bound::<::Assoc, as Id>::Assoc, _>() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `V` declared on the function `bound` From 4504cc513fb794116d0d2b9b73a40658a2f472cc Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sat, 19 Aug 2023 14:32:15 +0800 Subject: [PATCH 142/169] Usage zero as language id for FormatMessageW() --- library/std/src/sys/windows/os.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index 2329426ad1df..58afca088ef9 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -25,10 +25,6 @@ pub fn errno() -> i32 { /// Gets a detailed string description for the given error number. pub fn error_string(mut errnum: i32) -> String { - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as c::DWORD; - let mut buf = [0 as c::WCHAR; 2048]; unsafe { @@ -56,13 +52,13 @@ pub fn error_string(mut errnum: i32) -> String { flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, module, errnum as c::DWORD, - langId, + 0, buf.as_mut_ptr(), buf.len() as c::DWORD, ptr::null(), ) as usize; if res == 0 { - // Sometimes FormatMessageW can fail e.g., system doesn't like langId, + // Sometimes FormatMessageW can fail e.g., system doesn't like 0 as langId, let fm_err = errno(); return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})"); } From 07ff87bf735e8e811e5cb5aed13424d4a7bc7d0f Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 19 Aug 2023 08:46:37 +0100 Subject: [PATCH 143/169] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 7c3904d6c3ed..80eca0e58fb2 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 7c3904d6c3ed54e8a413023519b55a536ad44d5b +Subproject commit 80eca0e58fb2ff52c1e94fc191b55b37ed73e0e4 From 1e87ef66f4695d650672c8db0f60128f5024df18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 19 Aug 2023 12:55:01 +0200 Subject: [PATCH 144/169] Fix a stack overflow with long else if chains --- compiler/rustc_ast/src/mut_visit.rs | 3 ++- compiler/rustc_parse/src/parser/expr.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index bae3979fbf9f..48e9b180b74f 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -13,6 +13,7 @@ use crate::tokenstream::*; use crate::{ast::*, StaticItem}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; @@ -1369,7 +1370,7 @@ pub fn noop_visit_expr( ExprKind::If(cond, tr, fl) => { vis.visit_expr(cond); vis.visit_block(tr); - visit_opt(fl, |fl| vis.visit_expr(fl)); + visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl))); } ExprKind::While(cond, body, label) => { vis.visit_expr(cond); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e308e5b34207..9ae3ef6172c7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -22,6 +22,7 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, StashKey, @@ -2489,7 +2490,7 @@ impl<'a> Parser<'a> { let else_span = self.prev_token.span; // `else` let attrs = self.parse_outer_attributes()?; // For recovery. let expr = if self.eat_keyword(kw::If) { - self.parse_expr_if()? + ensure_sufficient_stack(|| self.parse_expr_if())? } else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) { self.parse_simple_block()? } else { From 269803ee56146c1739ec8f7169ad8fe0f90fb30c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 19 Aug 2023 14:09:30 +0200 Subject: [PATCH 145/169] remove redundant var rebindings --- compiler/rustc_middle/src/hir/mod.rs | 7 ++----- compiler/rustc_passes/src/layout_test.rs | 1 - compiler/rustc_passes/src/liveness.rs | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index e8fd469e1fb8..0da8fe9cca72 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -164,18 +164,15 @@ pub fn provide(providers: &mut Providers) { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; providers.def_span = |tcx, def_id| { - let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP) }; providers.def_ident_span = |tcx, def_id| { - let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_ident_span(hir_id) }; - providers.fn_arg_names = |tcx, id| { + providers.fn_arg_names = |tcx, def_id| { let hir = tcx.hir(); - let def_id = id; let hir_id = hir.local_def_id_to_hir_id(def_id); if let Some(body_id) = hir.maybe_body_owned_by(def_id) { tcx.arena.alloc_from_iter(hir.body_param_names(body_id)) @@ -190,7 +187,7 @@ pub fn provide(providers: &mut Providers) { { idents } else { - span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id); + span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", def_id); } }; providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id); diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 0463ee2914bc..a7a8af864ac1 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -27,7 +27,6 @@ pub fn test_layout(tcx: TyCtxt<'_>) { } fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { - let tcx = tcx; let param_env = tcx.param_env(item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); match tcx.layout_of(param_env.and(ty)) { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 0c0b8b6d094d..20e996eaec4c 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1105,7 +1105,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } // Then do a second pass for inputs - let mut succ = succ; for (op, _op_sp) in asm.operands.iter().rev() { match op { hir::InlineAsmOperand::In { expr, .. } => { From 410bd45ff2d9ae4fcd4a9a8c38ce44499d884baf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Aug 2023 13:51:13 +0200 Subject: [PATCH 146/169] const-eval: ensure we never const-execute a function marked rustc_do_not_const_check --- .../src/const_eval/machine.rs | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 032f4be6c997..b740b79d1624 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -427,52 +427,41 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, + orig_instance: ty::Instance<'tcx>, _abi: CallAbi, args: &[FnArg<'tcx>], dest: &PlaceTy<'tcx>, ret: Option, _unwind: mir::UnwindAction, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - debug!("find_mir_or_eval_fn: {:?}", instance); + debug!("find_mir_or_eval_fn: {:?}", orig_instance); + + // Replace some functions. + let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else { + // Call has already been handled. + return Ok(None); + }; // Only check non-glue functions if let ty::InstanceDef::Item(def) = instance.def { // Execution might have wandered off into other crates, so we cannot do a stability- - // sensitive check here. But we can at least rule out functions that are not const - // at all. - if !ecx.tcx.is_const_fn_raw(def) { - // allow calling functions inside a trait marked with #[const_trait]. - if !ecx.tcx.is_const_default_method(def) { - // We certainly do *not* want to actually call the fn - // though, so be sure we return here. - throw_unsup_format!("calling non-const function `{}`", instance) - } - } - - let Some(new_instance) = ecx.hook_special_const_fn(instance, args, dest, ret)? else { - return Ok(None); - }; - - if new_instance != instance { - // We call another const fn instead. - // However, we return the *original* instance to make backtraces work out - // (and we hope this does not confuse the FnAbi checks too much). - return Ok(Self::find_mir_or_eval_fn( - ecx, - new_instance, - _abi, - args, - dest, - ret, - _unwind, - )? - .map(|(body, _instance)| (body, instance))); + // sensitive check here. But we can at least rule out functions that are not const at + // all. That said, we have to allow calling functions inside a trait marked with + // #[const_trait]. These *are* const-checked! + // FIXME: why does `is_const_fn_raw` not classify them as const? + if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def)) + || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) + { + // We certainly do *not* want to actually call the fn + // though, so be sure we return here. + throw_unsup_format!("calling non-const function `{}`", instance) } } // This is a const fn. Call it. - Ok(Some((ecx.load_mir(instance.def, None)?, instance))) + // In case of replacement, we return the *original* instance to make backtraces work out + // (and we hope this does not confuse the FnAbi checks too much). + Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) } fn call_intrinsic( From 76efd398ba5a75247f4ba7e4508a246473ba9940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 19 Aug 2023 17:08:09 +0200 Subject: [PATCH 147/169] instead of collecting newly formatted Strings into one String, only create a single String and write!() to it (clippy::format_collect) --- .../src/method/prelude2021.rs | 21 ++++++++++--------- compiler/rustc_middle/src/ty/diagnostics.rs | 9 ++++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 5b19a4c525f8..3f1dca5b1dea 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -14,6 +14,7 @@ use rustc_span::symbol::kw::{Empty, Underscore}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; +use std::fmt::Write; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn lint_dot_call_from_2018( @@ -143,16 +144,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp); if precise { - let args = args - .iter() - .map(|arg| { - let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); - format!( - ", {}", - self.sess().source_map().span_to_snippet(span).unwrap() - ) - }) - .collect::(); + let args = args.iter().fold(String::new(), |mut string, arg| { + let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); + write!( + string, + ", {}", + self.sess().source_map().span_to_snippet(span).unwrap() + ) + .unwrap(); + string + }); lint.span_suggestion( sp, diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index e71482326da7..5db9b775a0f0 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -1,6 +1,7 @@ //! Diagnostics related methods for `Ty`. use std::borrow::Cow; +use std::fmt::Write; use std::ops::ControlFlow; use crate::ty::{ @@ -335,10 +336,10 @@ pub fn suggest_constraining_type_params<'a>( // - insert: `, X: Bar` suggestions.push(( generics.tail_span_for_predicate_suggestion(), - constraints - .iter() - .map(|&(constraint, _)| format!(", {param_name}: {constraint}")) - .collect::(), + constraints.iter().fold(String::new(), |mut string, &(constraint, _)| { + write!(string, ", {param_name}: {constraint}").unwrap(); + string + }), SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, )); continue; From ba33bb45694854a6ac5e3224f1eb41597e7f91c0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Aug 2023 17:19:46 +0200 Subject: [PATCH 148/169] Use function to remove code duplication for `search-form-elements.goml` test --- tests/rustdoc-gui/search-form-elements.goml | 393 +++++++------------- 1 file changed, 143 insertions(+), 250 deletions(-) diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml index 83c6980909c2..d84c16449ab6 100644 --- a/tests/rustdoc-gui/search-form-elements.goml +++ b/tests/rustdoc-gui/search-form-elements.goml @@ -2,262 +2,155 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true -// Ayu theme -set-local-storage: { - "rustdoc-theme": "ayu", - "rustdoc-use-system-theme": "false", -} -reload: - -assert-css: ( - ".search-input", - { - "border-color": "rgb(92, 103, 115)", - "background-color": "rgb(20, 25, 32)", - "color": "rgb(255, 255, 255)", - }, -) -focus: ".search-input" -// Nothing should change. -assert-css: ( - ".search-input", - { - "border-color": "rgb(92, 103, 115)", - "background-color": "rgb(20, 25, 32)", - "color": "rgb(255, 255, 255)", +define-function: ( + "check-search-colors", + ( + theme, search_input_border, search_input_background, search_input_color, + search_input_border_focus, menu_button_border, menu_button_a_color, menu_button_a_border, + menu_button_a_background, menu_button_border_hover, menu_button_a_hover, + menu_button_a_border_hover, menu_button_a_background_hover, menu_a_color, + ), + block { + set-local-storage: { + "rustdoc-theme": |theme|, + "rustdoc-use-system-theme": "false", + } + reload: + assert-css: ( + ".search-input", + { + "border-color": |search_input_border|, + "background-color": |search_input_background|, + "color": |search_input_color|, + }, + ) + // Focus on search input. + focus: ".search-input" + assert-css: ( + ".search-input", + { + "border-color": |search_input_border_focus|, + "background-color": |search_input_background|, + "color": |search_input_color|, + }, + ) + assert-css: ( + "#help-button", + {"border-color": |menu_button_border|}, + ) + assert-css: ( + "#help-button > a", + { + "color": |menu_button_a_color|, + "border-color": |menu_button_a_border|, + "background-color": |menu_button_a_background|, + }, + ) + // Hover help button. + move-cursor-to: "#help-button" + assert-css: ( + "#help-button:hover", + {"border-color": |menu_button_border_hover|}, + ) + assert-css: ( + "#help-button > a", + { + "color": |menu_button_a_hover|, + "border-color": |menu_button_a_border_hover|, + "background-color": |menu_button_a_background_hover|, + }, + ) + // Link color inside + click: "#help-button" + assert-css: ( + "#help a", + { + "color": |menu_a_color|, + }, + ) + assert-css: ( + "#settings-menu", + {"border-color": |menu_button_border|}, + ) + assert-css: ( + "#settings-menu > a", + { + "color": |menu_button_a_color|, + "border-color": |menu_button_a_border|, + "background-color": |menu_button_a_background|, + }, + ) + // Hover settings menu. + move-cursor-to: "#settings-menu" + assert-css: ( + "#settings-menu:hover", + {"border-color": |menu_button_border|}, + ) + assert-css: ( + "#settings-menu:hover > a", + { + "color": |menu_button_a_hover|, + "border-color": |menu_button_a_border_hover|, + "background-color": |menu_button_a_background_hover|, + }, + ) }, ) -assert-css: ( - "#help-button", - {"border-color": "rgb(197, 197, 197)"}, -) -assert-css: ( - "#help-button > a", +call-function: ( + "check-search-colors", { - "color": "rgb(255, 255, 255)", - "border-color": "rgb(92, 103, 115)", - "background-color": "rgb(20, 25, 32)", - }, + "theme": "ayu", + "search_input_border": "rgb(92, 103, 115)", + "search_input_background": "rgb(20, 25, 32)", + "search_input_color": "rgb(255, 255, 255)", + "search_input_border_focus": "rgb(92, 103, 115)", + "menu_button_border": "rgb(197, 197, 197)", + "menu_button_a_color": "rgb(255, 255, 255)", + "menu_button_a_border": "rgb(92, 103, 115)", + "menu_button_a_background": "rgb(20, 25, 32)", + "menu_button_border_hover": "rgb(197, 197, 197)", + "menu_button_a_hover": "rgb(255, 255, 255)", + "menu_button_a_border_hover": "rgb(224, 224, 224)", + "menu_button_a_background_hover": "rgb(20, 25, 32)", + "menu_a_color": "rgb(57, 175, 215)", + } ) -move-cursor-to: "#help-button" -assert-css: ( - "#help-button:hover", - {"border-color": "rgb(197, 197, 197)"}, -) -// Only "border-color" should change. -assert-css: ( - "#help-button:hover > a", +call-function: ( + "check-search-colors", { - "color": "rgb(255, 255, 255)", - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(20, 25, 32)", - }, + "theme": "dark", + "search_input_border": "rgb(224, 224, 224)", + "search_input_background": "rgb(240, 240, 240)", + "search_input_color": "rgb(17, 17, 17)", + "search_input_border_focus": "rgb(0, 141, 253)", + "menu_button_border": "rgb(221, 221, 221)", + "menu_button_a_color": "rgb(0, 0, 0)", + "menu_button_a_border": "rgb(224, 224, 224)", + "menu_button_a_background": "rgb(240, 240, 240)", + "menu_button_border_hover": "rgb(221, 221, 221)", + "menu_button_a_hover": "rgb(0, 0, 0)", + "menu_button_a_border_hover": "rgb(255, 185, 0)", + "menu_button_a_background_hover": "rgb(240, 240, 240)", + "menu_a_color": "rgb(210, 153, 29)", + } ) -// Link color inside -click: "#help-button" -assert-css: ( - "#help a", +call-function: ( + "check-search-colors", { - "color": "rgb(57, 175, 215)", - }, -) - -assert-css: ( - "#settings-menu", - {"border-color": "rgb(197, 197, 197)"}, -) -assert-css: ( - "#settings-menu > a", - { - "border-color": "rgb(92, 103, 115)", - "background-color": "rgb(20, 25, 32)", - }, -) -move-cursor-to: "#settings-menu" -assert-css: ( - "#settings-menu:hover", - {"border-color": "rgb(197, 197, 197)"}, -) -// Only "border-color" should change. -assert-css: ( - "#settings-menu:hover > a", - { - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(20, 25, 32)", - }, -) - -// Dark theme -set-local-storage: { - "rustdoc-theme": "dark", - "rustdoc-use-system-theme": "false", -} -reload: - -assert-css: ( - ".search-input", - { - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(240, 240, 240)", - "color": "rgb(17, 17, 17)", - }, -) -focus: ".search-input" -// Only "border-color" should change. -assert-css: ( - ".search-input", - { - "border-color": "rgb(0, 141, 253)", - "background-color": "rgb(240, 240, 240)", - "color": "rgb(17, 17, 17)", - }, -) - -assert-css: ( - "#help-button", - {"border-color": "rgb(221, 221, 221)"}, -) -assert-css: ( - "#help-button > a", - { - "color": "rgb(0, 0, 0)", - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(240, 240, 240)", - }, -) -move-cursor-to: "#help-button" -assert-css: ( - "#help-button:hover", - {"border-color": "rgb(221, 221, 221)"}, -) -// Only "border-color" should change. -assert-css: ( - "#help-button:hover > a", - { - "color": "rgb(0, 0, 0)", - "border-color": "rgb(255, 185, 0)", - "background-color": "rgb(240, 240, 240)", - }, -) -// Link color inside -click: "#help-button" -assert-css: ( - "#help a", - { - "color": "rgb(210, 153, 29)", - }, -) - -assert-css: ( - "#settings-menu", - {"border-color": "rgb(221, 221, 221)"}, -) -assert-css: ( - "#settings-menu > a", - { - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(240, 240, 240)", - }, -) -move-cursor-to: "#settings-menu" -assert-css: ( - "#settings-menu:hover", - {"border-color": "rgb(221, 221, 221)"}, -) -// Only "border-color" should change. -assert-css: ( - "#settings-menu:hover > a", - { - "color": "rgb(0, 0, 0)", - "border-color": "rgb(255, 185, 0)", - "background-color": "rgb(240, 240, 240)", - }, -) - -// Light theme -set-local-storage: { - "rustdoc-theme": "light", - "rustdoc-use-system-theme": "false", -} -reload: - -assert-css: ( - ".search-input", - { - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(255, 255, 255)", - "color": "rgb(0, 0, 0)", - }, -) -focus: ".search-input" -// Nothing should change. -assert-css: ( - ".search-input", - { - "border-color": "rgb(102, 175, 233)", - "background-color": "rgb(255, 255, 255)", - "color": "rgb(0, 0, 0)", - }, -) - -assert-css: ( - "#help-button", - {"border-color": "rgb(0, 0, 0)"}, -) -assert-css: ( - "#help-button > a", - { - "color": "rgb(0, 0, 0)", - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(255, 255, 255)", - }, -) -move-cursor-to: "#help-button" -assert-css: ( - "#help-button:hover", - {"border-color": "rgb(0, 0, 0)"}, -) -// Only "border-color" should change. -assert-css: ( - "#help-button:hover > a", - { - "color": "rgb(0, 0, 0)", - "border-color": "rgb(113, 113, 113)", - "background-color": "rgb(255, 255, 255)", - }, -) -// Link color inside -click: "#help-button" -assert-css: ( - "#help a", - { - "color": "rgb(56, 115, 173)", - }, -) - -assert-css: ( - "#settings-menu", - {"border-color": "rgb(0, 0, 0)"}, -) -assert-css: ( - "#settings-menu > a", - { - "border-color": "rgb(224, 224, 224)", - "background-color": "rgb(255, 255, 255)", - }, -) -move-cursor-to: "#settings-menu" -assert-css: ( - "#settings-menu:hover", - {"border-color": "rgb(0, 0, 0)"}, -) -// Only "border-color" should change. -assert-css: ( - "#settings-menu:hover > a", - { - "color": "rgb(0, 0, 0)", - "border-color": "rgb(113, 113, 113)", - "background-color": "rgb(255, 255, 255)", - }, + "theme": "light", + "search_input_border": "rgb(224, 224, 224)", + "search_input_background": "rgb(255, 255, 255)", + "search_input_color": "rgb(0, 0, 0)", + "search_input_border_focus": "rgb(102, 175, 233)", + "menu_button_border": "rgb(0, 0, 0)", + "menu_button_a_color": "rgb(0, 0, 0)", + "menu_button_a_border": "rgb(224, 224, 224)", + "menu_button_a_background": "rgb(255, 255, 255)", + "menu_button_border_hover": "rgb(0, 0, 0)", + "menu_button_a_hover": "rgb(0, 0, 0)", + "menu_button_a_border_hover": "rgb(113, 113, 113)", + "menu_button_a_background_hover": "rgb(255, 255, 255)", + "menu_a_color": "rgb(56, 115, 173)", + } ) From 87a0efbf02c79c37d71b815b4baa7f433a23b67b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Aug 2023 17:51:23 +0200 Subject: [PATCH 149/169] Merge values with same colors --- tests/rustdoc-gui/search-form-elements.goml | 57 ++++++++------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml index d84c16449ab6..fb75114fe454 100644 --- a/tests/rustdoc-gui/search-form-elements.goml +++ b/tests/rustdoc-gui/search-form-elements.goml @@ -5,10 +5,8 @@ show-text: true define-function: ( "check-search-colors", ( - theme, search_input_border, search_input_background, search_input_color, - search_input_border_focus, menu_button_border, menu_button_a_color, menu_button_a_border, - menu_button_a_background, menu_button_border_hover, menu_button_a_hover, - menu_button_a_border_hover, menu_button_a_background_hover, menu_a_color, + theme, border, background, search_input_color, search_input_border_focus, + menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color, ), block { set-local-storage: { @@ -19,8 +17,8 @@ define-function: ( assert-css: ( ".search-input", { - "border-color": |search_input_border|, - "background-color": |search_input_background|, + "border-color": |border|, + "background-color": |background|, "color": |search_input_color|, }, ) @@ -30,7 +28,7 @@ define-function: ( ".search-input", { "border-color": |search_input_border_focus|, - "background-color": |search_input_background|, + "background-color": |background|, "color": |search_input_color|, }, ) @@ -42,22 +40,22 @@ define-function: ( "#help-button > a", { "color": |menu_button_a_color|, - "border-color": |menu_button_a_border|, - "background-color": |menu_button_a_background|, + "border-color": |border|, + "background-color": |background|, }, ) // Hover help button. move-cursor-to: "#help-button" assert-css: ( "#help-button:hover", - {"border-color": |menu_button_border_hover|}, + {"border-color": |menu_button_border|}, ) assert-css: ( "#help-button > a", { - "color": |menu_button_a_hover|, + "color": |menu_button_a_color|, "border-color": |menu_button_a_border_hover|, - "background-color": |menu_button_a_background_hover|, + "background-color": |background|, }, ) // Link color inside @@ -76,8 +74,8 @@ define-function: ( "#settings-menu > a", { "color": |menu_button_a_color|, - "border-color": |menu_button_a_border|, - "background-color": |menu_button_a_background|, + "border-color": |border|, + "background-color": |background|, }, ) // Hover settings menu. @@ -89,9 +87,9 @@ define-function: ( assert-css: ( "#settings-menu:hover > a", { - "color": |menu_button_a_hover|, + "color": |menu_button_a_color|, "border-color": |menu_button_a_border_hover|, - "background-color": |menu_button_a_background_hover|, + "background-color": |background|, }, ) }, @@ -101,18 +99,13 @@ call-function: ( "check-search-colors", { "theme": "ayu", - "search_input_border": "rgb(92, 103, 115)", - "search_input_background": "rgb(20, 25, 32)", + "border": "rgb(92, 103, 115)", + "background": "rgb(20, 25, 32)", "search_input_color": "rgb(255, 255, 255)", "search_input_border_focus": "rgb(92, 103, 115)", "menu_button_border": "rgb(197, 197, 197)", "menu_button_a_color": "rgb(255, 255, 255)", - "menu_button_a_border": "rgb(92, 103, 115)", - "menu_button_a_background": "rgb(20, 25, 32)", - "menu_button_border_hover": "rgb(197, 197, 197)", - "menu_button_a_hover": "rgb(255, 255, 255)", "menu_button_a_border_hover": "rgb(224, 224, 224)", - "menu_button_a_background_hover": "rgb(20, 25, 32)", "menu_a_color": "rgb(57, 175, 215)", } ) @@ -120,18 +113,13 @@ call-function: ( "check-search-colors", { "theme": "dark", - "search_input_border": "rgb(224, 224, 224)", - "search_input_background": "rgb(240, 240, 240)", + "border": "rgb(224, 224, 224)", + "background": "rgb(240, 240, 240)", "search_input_color": "rgb(17, 17, 17)", "search_input_border_focus": "rgb(0, 141, 253)", "menu_button_border": "rgb(221, 221, 221)", "menu_button_a_color": "rgb(0, 0, 0)", - "menu_button_a_border": "rgb(224, 224, 224)", - "menu_button_a_background": "rgb(240, 240, 240)", - "menu_button_border_hover": "rgb(221, 221, 221)", - "menu_button_a_hover": "rgb(0, 0, 0)", "menu_button_a_border_hover": "rgb(255, 185, 0)", - "menu_button_a_background_hover": "rgb(240, 240, 240)", "menu_a_color": "rgb(210, 153, 29)", } ) @@ -139,18 +127,13 @@ call-function: ( "check-search-colors", { "theme": "light", - "search_input_border": "rgb(224, 224, 224)", - "search_input_background": "rgb(255, 255, 255)", + "border": "rgb(224, 224, 224)", + "background": "rgb(255, 255, 255)", "search_input_color": "rgb(0, 0, 0)", "search_input_border_focus": "rgb(102, 175, 233)", "menu_button_border": "rgb(0, 0, 0)", "menu_button_a_color": "rgb(0, 0, 0)", - "menu_button_a_border": "rgb(224, 224, 224)", - "menu_button_a_background": "rgb(255, 255, 255)", - "menu_button_border_hover": "rgb(0, 0, 0)", - "menu_button_a_hover": "rgb(0, 0, 0)", "menu_button_a_border_hover": "rgb(113, 113, 113)", - "menu_button_a_background_hover": "rgb(255, 255, 255)", "menu_a_color": "rgb(56, 115, 173)", } ) From 03a3d24a116ced3b33a0541e3de559ff62907f0d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 19 Aug 2023 17:51:47 +0200 Subject: [PATCH 150/169] Migrate GUI colors test to original CSS color format --- tests/rustdoc-gui/search-form-elements.goml | 48 ++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml index fb75114fe454..a4e223648598 100644 --- a/tests/rustdoc-gui/search-form-elements.goml +++ b/tests/rustdoc-gui/search-form-elements.goml @@ -99,41 +99,41 @@ call-function: ( "check-search-colors", { "theme": "ayu", - "border": "rgb(92, 103, 115)", - "background": "rgb(20, 25, 32)", - "search_input_color": "rgb(255, 255, 255)", - "search_input_border_focus": "rgb(92, 103, 115)", - "menu_button_border": "rgb(197, 197, 197)", - "menu_button_a_color": "rgb(255, 255, 255)", - "menu_button_a_border_hover": "rgb(224, 224, 224)", - "menu_a_color": "rgb(57, 175, 215)", + "border": "#5c6773", + "background": "#141920", + "search_input_color": "#fff", + "search_input_border_focus": "#5c6773", + "menu_button_border": "#c5c5c5", + "menu_button_a_color": "#fff", + "menu_button_a_border_hover": "#e0e0e0", + "menu_a_color": "#39afd7", } ) call-function: ( "check-search-colors", { "theme": "dark", - "border": "rgb(224, 224, 224)", - "background": "rgb(240, 240, 240)", - "search_input_color": "rgb(17, 17, 17)", - "search_input_border_focus": "rgb(0, 141, 253)", - "menu_button_border": "rgb(221, 221, 221)", - "menu_button_a_color": "rgb(0, 0, 0)", - "menu_button_a_border_hover": "rgb(255, 185, 0)", - "menu_a_color": "rgb(210, 153, 29)", + "border": "#e0e0e0", + "background": "#f0f0f0", + "search_input_color": "#111", + "search_input_border_focus": "#008dfd", + "menu_button_border": "#ddd", + "menu_button_a_color": "#000", + "menu_button_a_border_hover": "#ffb900", + "menu_a_color": "#d2991d", } ) call-function: ( "check-search-colors", { "theme": "light", - "border": "rgb(224, 224, 224)", - "background": "rgb(255, 255, 255)", - "search_input_color": "rgb(0, 0, 0)", - "search_input_border_focus": "rgb(102, 175, 233)", - "menu_button_border": "rgb(0, 0, 0)", - "menu_button_a_color": "rgb(0, 0, 0)", - "menu_button_a_border_hover": "rgb(113, 113, 113)", - "menu_a_color": "rgb(56, 115, 173)", + "border": "#e0e0e0", + "background": "#fff", + "search_input_color": "#000", + "search_input_border_focus": "#66afe9", + "menu_button_border": "#000", + "menu_button_a_color": "#000", + "menu_button_a_border_hover": "#717171", + "menu_a_color": "#3873ad", } ) From 4cd3b0b71ca1bcabb3b6ff7be6410d96356d9768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 19 Aug 2023 18:49:58 +0200 Subject: [PATCH 151/169] use static arrays instead of vectors --- compiler/rustc_mir_transform/src/coverage/debug.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index d2c0c4ba0692..083f1f8aef69 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -199,9 +199,9 @@ impl DebugOptions { fn bool_option_val(option: &str, some_strval: Option<&str>) -> bool { if let Some(val) = some_strval { - if vec!["yes", "y", "on", "true"].contains(&val) { + if ["yes", "y", "on", "true"].contains(&val) { true - } else if vec!["no", "n", "off", "false"].contains(&val) { + } else if ["no", "n", "off", "false"].contains(&val) { false } else { bug!( From 7a6346660e8587fa4c92dc846fdcd8f3bc828ac3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Aug 2023 18:08:23 +0200 Subject: [PATCH 152/169] custom_mir: change Call() terminator syntax to something more readable --- .../src/build/custom/parse/instruction.rs | 19 +++++++++---------- library/core/src/intrinsics/mir.rs | 9 +++++---- .../fail/function_calls/arg_inplace_mutate.rs | 4 ++-- .../arg_inplace_mutate.stack.stderr | 6 +++--- .../arg_inplace_mutate.tree.stderr | 6 +++--- .../arg_inplace_observe_after.rs | 4 ++-- .../arg_inplace_observe_during.none.stderr | 4 ++-- .../arg_inplace_observe_during.rs | 4 ++-- .../arg_inplace_observe_during.stack.stderr | 6 +++--- .../arg_inplace_observe_during.tree.stderr | 6 +++--- .../return_pointer_aliasing.none.stderr | 4 ++-- .../function_calls/return_pointer_aliasing.rs | 2 +- .../return_pointer_aliasing.stack.stderr | 4 ++-- .../return_pointer_aliasing.tree.stderr | 4 ++-- .../return_pointer_aliasing2.rs | 6 +++--- .../return_pointer_aliasing2.stderr | 8 ++++---- .../function_calls/return_place_on_heap.rs | 2 +- tests/mir-opt/building/custom/terminators.rs | 4 ++-- tests/mir-opt/copy-prop/borrowed_local.rs | 4 ++-- tests/mir-opt/copy-prop/custom_move_arg.rs | 4 ++-- tests/mir-opt/copy-prop/move_projection.rs | 4 ++-- tests/mir-opt/reference_prop.rs | 10 +++++----- 22 files changed, 62 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index fe5190900e94..26662f5de459 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -61,9 +61,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { }) }, @call("mir_call", args) => { - let destination = self.parse_place(args[0])?; - let target = self.parse_block(args[1])?; - self.parse_call(args[2], destination, target) + self.parse_call(args) }, ExprKind::Match { scrutinee, arms, .. } => { let discr = self.parse_operand(*scrutinee)?; @@ -109,13 +107,14 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise)) } - fn parse_call( - &self, - expr_id: ExprId, - destination: Place<'tcx>, - target: BasicBlock, - ) -> PResult> { - parse_by_kind!(self, expr_id, _, "function call", + fn parse_call(&self, args: &[ExprId]) -> PResult> { + let (destination, call) = parse_by_kind!(self, args[0], _, "function call", + ExprKind::Assign { lhs, rhs } => (*lhs, *rhs), + ); + let destination = self.parse_place(destination)?; + let target = self.parse_block(args[1])?; + + parse_by_kind!(self, call, _, "function call", ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => { let fun = self.parse_operand(*fun)?; let args = args diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 036edbebbf3e..ef0a2fd4ec4b 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -104,17 +104,18 @@ //! } //! //! #[custom_mir(dialect = "runtime", phase = "optimized")] +#![cfg_attr(bootstrap, doc = "#[cfg(any())]")] // disable the following function in doctests when `bootstrap` is set //! fn push_and_pop(v: &mut Vec, value: T) { //! mir!( -//! let unused; +//! let _unused; //! let popped; //! //! { -//! Call(unused, pop, Vec::push(v, value)) +//! Call(_unused = Vec::push(v, value), pop) //! } //! //! pop = { -//! Call(popped, drop, Vec::pop(v)) +//! Call(popped = Vec::pop(v), drop) //! } //! //! drop = { @@ -275,7 +276,7 @@ define!("mir_return", fn Return() -> BasicBlock); define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock); define!("mir_unreachable", fn Unreachable() -> BasicBlock); define!("mir_drop", fn Drop(place: T, goto: BasicBlock)); -define!("mir_call", fn Call(place: T, goto: BasicBlock, call: T)); +define!("mir_call", fn Call(call: (), goto: BasicBlock)); define!("mir_storage_live", fn StorageLive(local: T)); define!("mir_storage_dead", fn StorageDead(local: T)); define!("mir_deinit", fn Deinit(place: T)); diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.rs index 625a8bda8af1..d47af50d407e 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.rs +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.rs @@ -8,13 +8,13 @@ pub struct S(i32); #[custom_mir(dialect = "runtime", phase = "optimized")] fn main() { mir! { - let unit: (); + let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! - Call(unit, after_call, callee(Move(*ptr), ptr)) + Call(_unit = callee(Move(*ptr), ptr), after_call) } after_call = { Return() diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr index 471dc1dd6dd3..381442e69b13 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr @@ -10,7 +10,7 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/arg_inplace_mutate.rs:LL:CC | LL | / mir! { -LL | | let unit: (); +LL | | let _unit: (); LL | | { LL | | let non_copy = S(42); ... | @@ -27,8 +27,8 @@ LL | unsafe { ptr.write(S(0)) }; note: inside `main` --> $DIR/arg_inplace_mutate.rs:LL:CC | -LL | Call(unit, after_call, callee(Move(*ptr), ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_unit = callee(Move(*ptr), ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 8393b80f25b5..544cd575ada3 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -12,7 +12,7 @@ help: the accessed tag was created here --> $DIR/arg_inplace_mutate.rs:LL:CC | LL | / mir! { -LL | | let unit: (); +LL | | let _unit: (); LL | | { LL | | let non_copy = S(42); ... | @@ -29,8 +29,8 @@ LL | unsafe { ptr.write(S(0)) }; note: inside `main` --> $DIR/arg_inplace_mutate.rs:LL:CC | -LL | Call(unit, after_call, callee(Move(*ptr), ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_unit = callee(Move(*ptr), ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.rs index 093b55759fde..ea773048dd4e 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.rs +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.rs @@ -6,12 +6,12 @@ pub struct S(i32); #[custom_mir(dialect = "runtime", phase = "optimized")] fn main() { mir! { - let unit: (); + let _unit: (); let _observe: i32; { let non_copy = S(42); // This could change `non_copy` in-place - Call(unit, after_call, change_arg(Move(non_copy))) + Call(_unit = change_arg(Move(non_copy)), after_call) } after_call = { // So now we must not be allowed to observe non-copy again. diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr index baa914847937..cba23c21d12b 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr @@ -11,8 +11,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> $DIR/arg_inplace_observe_during.rs:LL:CC | -LL | Call(unit, after_call, change_arg(Move(*ptr), ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.rs index 2e57872db963..8c6a7df7a6dd 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.rs +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.rs @@ -9,12 +9,12 @@ pub struct S(i32); #[custom_mir(dialect = "runtime", phase = "optimized")] fn main() { mir! { - let unit: (); + let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // This could change `non_copy` in-place - Call(unit, after_call, change_arg(Move(*ptr), ptr)) + Call(_unit = change_arg(Move(*ptr), ptr), after_call) } after_call = { Return() diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr index a842d3a8044a..f8532186be20 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr @@ -10,7 +10,7 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/arg_inplace_observe_during.rs:LL:CC | LL | / mir! { -LL | | let unit: (); +LL | | let _unit: (); LL | | { LL | | let non_copy = S(42); ... | @@ -27,8 +27,8 @@ LL | x.0 = 0; note: inside `main` --> $DIR/arg_inplace_observe_during.rs:LL:CC | -LL | Call(unit, after_call, change_arg(Move(*ptr), ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index 5af4856bbe3b..c33645bdd280 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -12,7 +12,7 @@ help: the accessed tag was created here --> $DIR/arg_inplace_observe_during.rs:LL:CC | LL | / mir! { -LL | | let unit: (); +LL | | let _unit: (); LL | | { LL | | let non_copy = S(42); ... | @@ -29,8 +29,8 @@ LL | x.0 = 0; note: inside `main` --> $DIR/arg_inplace_observe_during.rs:LL:CC | -LL | Call(unit, after_call, change_arg(Move(*ptr), ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.none.stderr index 9d9dfc89f897..0a31adabf73d 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.none.stderr @@ -11,8 +11,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> $DIR/return_pointer_aliasing.rs:LL:CC | -LL | Call(*ptr, after_call, myfun(ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(*ptr = myfun(ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.rs index 829809102fa9..3d560af3d5eb 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.rs @@ -15,7 +15,7 @@ pub fn main() { let ptr = &raw mut x; // We arrange for `myfun` to have a pointer that aliases // its return place. Even just reading from that pointer is UB. - Call(*ptr, after_call, myfun(ptr)) + Call(*ptr = myfun(ptr), after_call) } after_call = { diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.stack.stderr index d486dcb95df0..875cc5edad98 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.stack.stderr @@ -27,8 +27,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> $DIR/return_pointer_aliasing.rs:LL:CC | -LL | Call(*ptr, after_call, myfun(ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(*ptr = myfun(ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr index c491a904a108..66c2fb8db19f 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing.tree.stderr @@ -29,8 +29,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> $DIR/return_pointer_aliasing.rs:LL:CC | -LL | Call(*ptr, after_call, myfun(ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(*ptr = myfun(ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.rs index 7e9a63200261..9d53faccd1ef 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.rs @@ -9,11 +9,11 @@ use std::intrinsics::mir::*; pub fn main() { mir! { { - let x = 0; - let ptr = &raw mut x; + let _x = 0; + let ptr = &raw mut _x; // We arrange for `myfun` to have a pointer that aliases // its return place. Even just reading from that pointer is UB. - Call(x, after_call, myfun(ptr)) + Call(_x = myfun(ptr), after_call) } after_call = { diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.stderr index 33a8a4b46bd0..443ee8643fc2 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing2.stderr @@ -13,8 +13,8 @@ help: the accessed tag was created here | LL | / mir! { LL | | { -LL | | let x = 0; -LL | | let ptr = &raw mut x; +LL | | let _x = 0; +LL | | let ptr = &raw mut _x; ... | LL | | } LL | | } @@ -29,8 +29,8 @@ LL | unsafe { ptr.write(0) }; note: inside `main` --> $DIR/return_pointer_aliasing2.rs:LL:CC | -LL | Call(x, after_call, myfun(ptr)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), after_call) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/function_calls/return_place_on_heap.rs b/src/tools/miri/tests/pass/function_calls/return_place_on_heap.rs index dcfebd0f82b8..d410a875b1be 100644 --- a/src/tools/miri/tests/pass/function_calls/return_place_on_heap.rs +++ b/src/tools/miri/tests/pass/function_calls/return_place_on_heap.rs @@ -11,7 +11,7 @@ pub fn main() { { let x = 0; let ptr = &raw mut x; - Call(*ptr, after_call, myfun()) + Call(*ptr = myfun(), after_call) } after_call = { diff --git a/tests/mir-opt/building/custom/terminators.rs b/tests/mir-opt/building/custom/terminators.rs index f12405661685..123118f654e7 100644 --- a/tests/mir-opt/building/custom/terminators.rs +++ b/tests/mir-opt/building/custom/terminators.rs @@ -12,7 +12,7 @@ fn ident(t: T) -> T { fn direct_call(x: i32) -> i32 { mir!( { - Call(RET, retblock, ident(x)) + Call(RET = ident(x), retblock) } retblock = { @@ -26,7 +26,7 @@ fn direct_call(x: i32) -> i32 { fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 { mir!( { - Call(RET, retblock, f(x)) + Call(RET = f(x), retblock) } retblock = { diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs index a89b64441d0c..bf94dc57d336 100644 --- a/tests/mir-opt/copy-prop/borrowed_local.rs +++ b/tests/mir-opt/copy-prop/borrowed_local.rs @@ -21,11 +21,11 @@ fn f() -> bool { let b = a; // We cannot propagate the place `a`. let r2 = &b; - Call(RET, next, cmp_ref(r1, r2)) + Call(RET = cmp_ref(r1, r2), next) } next = { // But we can propagate the value `a`. - Call(RET, ret, opaque(b)) + Call(RET = opaque(b), ret) } ret = { Return() diff --git a/tests/mir-opt/copy-prop/custom_move_arg.rs b/tests/mir-opt/copy-prop/custom_move_arg.rs index a90db08fa517..d1c5ffdff0dc 100644 --- a/tests/mir-opt/copy-prop/custom_move_arg.rs +++ b/tests/mir-opt/copy-prop/custom_move_arg.rs @@ -13,11 +13,11 @@ struct NotCopy(bool); fn f(_1: NotCopy) { mir!({ let _2 = _1; - Call(RET, bb1, opaque(Move(_1))) + Call(RET = opaque(Move(_1)), bb1) } bb1 = { let _3 = Move(_2); - Call(RET, bb2, opaque(_3)) + Call(RET = opaque(_3), bb2) } bb2 = { Return() diff --git a/tests/mir-opt/copy-prop/move_projection.rs b/tests/mir-opt/copy-prop/move_projection.rs index 40f51ce8406a..f94addb5629c 100644 --- a/tests/mir-opt/copy-prop/move_projection.rs +++ b/tests/mir-opt/copy-prop/move_projection.rs @@ -17,10 +17,10 @@ fn f(a: Foo) -> bool { let b = a; // This is a move out of a copy, so must become a copy of `a.0`. let c = Move(b.0); - Call(RET, bb1, opaque(Move(a))) + Call(RET = opaque(Move(a)), bb1) } bb1 = { - Call(RET, ret, opaque(Move(c))) + Call(RET = opaque(Move(c)), ret) } ret = { Return() diff --git a/tests/mir-opt/reference_prop.rs b/tests/mir-opt/reference_prop.rs index 4083b45470b4..610660131b19 100644 --- a/tests/mir-opt/reference_prop.rs +++ b/tests/mir-opt/reference_prop.rs @@ -426,7 +426,7 @@ fn multiple_storage() { // As there are multiple `StorageLive` statements for `x`, we cannot know if this `z`'s // pointer address is the address of `x`, so do nothing. let y = *z; - Call(RET, retblock, opaque(y)) + Call(RET = opaque(y), retblock) } retblock = { @@ -452,7 +452,7 @@ fn dominate_storage() { } bb1 = { let c = *r; - Call(RET, bb2, opaque(c)) + Call(RET = opaque(c), bb2) } bb2 = { StorageDead(x); @@ -486,18 +486,18 @@ fn maybe_dead(m: bool) { bb1 = { StorageDead(x); StorageDead(y); - Call(RET, bb2, opaque(u)) + Call(RET = opaque(u), bb2) } bb2 = { // As `x` may be `StorageDead`, `a` may be dangling, so we do nothing. let z = *a; - Call(RET, bb3, opaque(z)) + Call(RET = opaque(z), bb3) } bb3 = { // As `y` may be `StorageDead`, `b` may be dangling, so we do nothing. // This implies that we also do not substitute `b` in `bb0`. let t = *b; - Call(RET, retblock, opaque(t)) + Call(RET = opaque(t), retblock) } retblock = { Return() From 822caa8b800f54c414b692fee64cd844bb6c0f25 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Aug 2023 02:23:49 +0000 Subject: [PATCH 153/169] Avoid side-effects from try_coerce when suggesting borrowing LHS of cast --- compiler/rustc_hir_typeck/src/cast.rs | 24 ++---------- .../type-checking-test-1.current.stderr | 20 ++-------- .../trait-upcasting/type-checking-test-1.rs | 1 - .../trait-upcasting/type-checking-test-2.rs | 2 - .../type-checking-test-2.stderr | 37 +++---------------- 5 files changed, 12 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 5bc0e2ee86c8..0f1456882fa3 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -389,34 +389,26 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: expr_ty, mutbl }, ), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() && expr_mutbl == Mutability::Not && mutbl == Mutability::Mut && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx, expr_reg, TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, ), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg_mutref = true; } @@ -424,30 +416,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { if !sugg_mutref && sugg == None && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() && fcx - .try_coerce( - self.expr, + .can_coerce( Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: self.expr_ty, mutbl }, ), self.cast_ty, - AllowTwoPhase::No, - None, ) - .is_ok() { sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr index d48d9b89d1da..b612005fcb05 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr @@ -2,22 +2,8 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` --> $DIR/type-checking-test-1.rs:19:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous - | ^^^^^^^^^^^^^^^^ invalid cast - | -help: consider borrowing the value - | -LL | let _ = &x as &dyn Bar<_>; // Ambiguous - | + + | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied - --> $DIR/type-checking-test-1.rs:19:13 - | -LL | let _ = x as &dyn Bar<_>; // Ambiguous - | ^ the trait `Bar<_>` is not implemented for `&dyn Foo` - | - = note: required for the cast from `&&dyn Foo` to `&dyn Bar<_>` +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0277, E0605. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0605`. diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs index 7c7beec0809d..afea8521e87d 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs @@ -18,7 +18,6 @@ fn test_specific(x: &dyn Foo) { fn test_unknown_version(x: &dyn Foo) { let _ = x as &dyn Bar<_>; // Ambiguous //~^ ERROR non-primitive cast - //[current]~^^ ERROR the trait bound `&dyn Foo: Bar<_>` is not satisfied } fn test_infer_version(x: &dyn Foo) { diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs index 36b11dffdb15..b024b27750bc 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs @@ -18,13 +18,11 @@ fn test_specific2(x: &dyn Foo) { fn test_specific3(x: &dyn Foo) { let _ = x as &dyn Bar; // Error //~^ ERROR non-primitive cast - //~^^ ERROR the trait bound `&dyn Foo: Bar` is not satisfied } fn test_infer_arg(x: &dyn Foo) { let a = x as &dyn Bar<_>; // Ambiguous //~^ ERROR non-primitive cast - //~^^ ERROR the trait bound `&dyn Foo: Bar<_>` is not satisfied let _ = a.bar(); } diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr index 856303ef4dd4..3e59b9d33634 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr @@ -2,41 +2,14 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar` --> $DIR/type-checking-test-2.rs:19:13 | LL | let _ = x as &dyn Bar; // Error - | ^^^^^^^^^^^^^^^^^^ invalid cast - | -help: consider borrowing the value - | -LL | let _ = &x as &dyn Bar; // Error - | + - -error[E0277]: the trait bound `&dyn Foo: Bar` is not satisfied - --> $DIR/type-checking-test-2.rs:19:13 - | -LL | let _ = x as &dyn Bar; // Error - | ^ the trait `Bar` is not implemented for `&dyn Foo` - | - = note: required for the cast from `&&dyn Foo` to `&dyn Bar` + | ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-2.rs:25:13 + --> $DIR/type-checking-test-2.rs:24:13 | LL | let a = x as &dyn Bar<_>; // Ambiguous - | ^^^^^^^^^^^^^^^^ invalid cast - | -help: consider borrowing the value - | -LL | let a = &x as &dyn Bar<_>; // Ambiguous - | + + | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied - --> $DIR/type-checking-test-2.rs:25:13 - | -LL | let a = x as &dyn Bar<_>; // Ambiguous - | ^ the trait `Bar<_>` is not implemented for `&dyn Foo` - | - = note: required for the cast from `&&dyn Foo` to `&dyn Bar<_>` +error: aborting due to 2 previous errors -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0277, E0605. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0605`. From 406b0e2935549a0c63a09d47776aeb92a06f6ddf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Aug 2023 02:27:13 +0000 Subject: [PATCH 154/169] Rename try_coerce to coerce --- compiler/rustc_hir_typeck/src/cast.rs | 8 ++++---- compiler/rustc_hir_typeck/src/coercion.rs | 6 +++--- compiler/rustc_hir_typeck/src/demand.rs | 4 ++-- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 ++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 0f1456882fa3..31a03fabe4f2 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -744,7 +744,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ty::FnDef(..) => { // Attempt a coercion to a fn pointer type. let f = fcx.normalize(self.expr_span, self.expr_ty.fn_sig(fcx.tcx)); - let res = fcx.try_coerce( + let res = fcx.coerce( self.expr, self.expr_ty, Ty::new_fn_ptr(fcx.tcx, f), @@ -844,7 +844,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { (_, DynStar) => { if fcx.tcx.features().dyn_star { - bug!("should be handled by `try_coerce`") + bug!("should be handled by `coerce`") } else { Err(CastError::IllegalCast) } @@ -940,7 +940,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Coerce to a raw pointer so that we generate AddressOf in MIR. let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr); - fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) + fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) .unwrap_or_else(|_| { bug!( "could not cast from reference to array to pointer to array ({:?} to {:?})", @@ -976,7 +976,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'tcx>> { - match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) { + match fcx.coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) { Ok(_) => Ok(()), Err(err) => Err(err), } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 726914a995b1..fca675ea9d80 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1005,7 +1005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. /// The expressions *must not* have any preexisting adjustments. - pub fn try_coerce( + pub fn coerce( &self, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, @@ -1036,7 +1036,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - /// Same as `try_coerce()`, but without side-effects. + /// Same as `coerce()`, but without side-effects. /// /// Returns false if the coercion creates any obligations that result in /// errors. @@ -1494,7 +1494,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // Special-case the first expression we are coercing. // To be honest, I'm not entirely sure why we do this. // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why - fcx.try_coerce( + fcx.coerce( expression, expression_ty, self.expected_ty, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 6aeabc1bebb2..2c16f21b4916 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> (Ty<'tcx>, Option>) { let expected = self.resolve_vars_with_obligations(expected); - let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) { + let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { Ok(ty) => return (ty, None), Err(e) => e, }; @@ -475,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; let arg_ty = arg_ty.fold_with(&mut fudger); - let _ = self.try_coerce( + let _ = self.coerce( arg_expr, arg_ty, *expected_arg_ty, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 004c8affcf0d..4def78673841 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -260,9 +260,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // fulfillment error to be more accurate. let coerced_ty = self.resolve_vars_with_obligations(coerced_ty); - let coerce_error = self - .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None) - .err(); + let coerce_error = + self.coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None).err(); if coerce_error.is_some() { return Compatibility::Incompatible(coerce_error); From cad50f40e54ff41252a3a33aae166fcdc291aba0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 14 Aug 2023 11:41:22 +1000 Subject: [PATCH 155/169] coverage: Remove a useless `let () =` --- compiler/rustc_mir_transform/src/coverage/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index d797a6057a7f..f46542ef58bd 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -676,7 +676,7 @@ fn test_make_bcb_counters() { } } let mut coverage_counters = counters::CoverageCounters::new(0, &basic_coverage_blocks); - let () = coverage_counters + coverage_counters .make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans) .expect("should be Ok"); assert_eq!(coverage_counters.intermediate_expressions.len(), 0); From 629437eec78a56b04c4a2dbc6c85278ec1221a26 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 22 Jul 2023 13:17:33 +1000 Subject: [PATCH 156/169] coverage: Move a debug print into `make_code_region` --- .../rustc_mir_transform/src/coverage/mod.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index e08b6d6f6e8d..43a54496db07 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -309,19 +309,14 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { }; graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); - debug!( - "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", - file_name, - self.source_file, - source_map.span_to_diagnostic_string(span), - source_map.span_to_diagnostic_string(body_span) - ); + let code_region = + make_code_region(source_map, file_name, &self.source_file, span, body_span); inject_statement( self.mir_body, counter_kind, self.bcb_leader_bb(bcb), - Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)), + Some(code_region), ); } } @@ -498,6 +493,14 @@ fn make_code_region( span: Span, body_span: Span, ) -> CodeRegion { + debug!( + "Called make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", + file_name, + source_file, + source_map.span_to_diagnostic_string(span), + source_map.span_to_diagnostic_string(body_span) + ); + let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo()); let (end_line, end_col) = if span.hi() == span.lo() { let (end_line, mut end_col) = (start_line, start_col); From fbab055e7704a1cd321628a1896333e0c13ebc2f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 8 Jul 2023 13:43:29 +1000 Subject: [PATCH 157/169] coverage: Give the instrumentor its own counter type, separate from MIR This splits off `BcbCounter` from MIR's `CoverageKind`, allowing the two types to evolve in different directions as necessary. --- compiler/rustc_middle/src/mir/coverage.rs | 15 ---- .../src/coverage/counters.rs | 80 ++++++++++++++----- .../rustc_mir_transform/src/coverage/debug.rs | 69 ++++++++-------- .../rustc_mir_transform/src/coverage/mod.rs | 45 ++++++++--- .../rustc_mir_transform/src/coverage/tests.rs | 5 +- 5 files changed, 129 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index d7d6e3a0086c..1efb54bdb087 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -96,21 +96,6 @@ pub enum CoverageKind { Unreachable, } -impl CoverageKind { - pub fn as_operand(&self) -> Operand { - use CoverageKind::*; - match *self { - Counter { id, .. } => Operand::Counter(id), - Expression { id, .. } => Operand::Expression(id), - Unreachable => bug!("Unreachable coverage cannot be part of an expression"), - } - } - - pub fn is_expression(&self) -> bool { - matches!(self, Self::Expression { .. }) - } -} - impl Debug for CoverageKind { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use CoverageKind::*; diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index d1f2f0c76c83..3eca2610de60 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -14,6 +14,48 @@ use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::coverage::*; +use std::fmt::{self, Debug}; + +/// The coverage counter or counter expression associated with a particular +/// BCB node or BCB edge. +#[derive(Clone)] +pub(super) enum BcbCounter { + Counter { function_source_hash: u64, id: CounterId }, + Expression { id: ExpressionId, lhs: Operand, op: Op, rhs: Operand }, +} + +impl BcbCounter { + fn is_expression(&self) -> bool { + matches!(self, Self::Expression { .. }) + } + + pub(super) fn as_operand(&self) -> Operand { + match *self { + BcbCounter::Counter { id, .. } => Operand::Counter(id), + BcbCounter::Expression { id, .. } => Operand::Expression(id), + } + } +} + +impl Debug for BcbCounter { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()), + Self::Expression { id, lhs, op, rhs } => write!( + fmt, + "Expression({:?}) = {:?} {} {:?}", + id.index(), + lhs, + match op { + Op::Add => "+", + Op::Subtract => "-", + }, + rhs, + ), + } + } +} + /// Generates and stores coverage counter and coverage expression information /// associated with nodes/edges in the BCB graph. pub(super) struct CoverageCounters { @@ -22,18 +64,18 @@ pub(super) struct CoverageCounters { next_expression_id: ExpressionId, /// Coverage counters/expressions that are associated with individual BCBs. - bcb_counters: IndexVec>, + bcb_counters: IndexVec>, /// Coverage counters/expressions that are associated with the control-flow /// edge between two BCBs. - bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), CoverageKind>, + bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, /// Tracks which BCBs have a counter associated with some incoming edge. /// Only used by debug assertions, to verify that BCBs with incoming edge /// counters do not have their own physical counters (expressions are allowed). bcb_has_incoming_edge_counters: BitSet, /// Expression nodes that are not directly associated with any particular /// BCB/edge, but are needed as operands to more complex expressions. - /// These are always `CoverageKind::Expression`. - pub(super) intermediate_expressions: Vec, + /// These are always [`BcbCounter::Expression`]. + pub(super) intermediate_expressions: Vec, pub debug_counters: DebugCounters, } @@ -57,12 +99,12 @@ impl CoverageCounters { } /// Activate the `DebugCounters` data structures, to provide additional debug formatting - /// features when formatting `CoverageKind` (counter) values. + /// features when formatting [`BcbCounter`] (counter) values. pub fn enable_debug(&mut self) { self.debug_counters.enable(); } - /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or + /// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or /// indirectly associated with `CoverageSpans`, and accumulates additional `Expression`s /// representing intermediate values. pub fn make_bcb_counters( @@ -73,11 +115,11 @@ impl CoverageCounters { MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(coverage_spans) } - fn make_counter(&mut self, debug_block_label_fn: F) -> CoverageKind + fn make_counter(&mut self, debug_block_label_fn: F) -> BcbCounter where F: Fn() -> Option, { - let counter = CoverageKind::Counter { + let counter = BcbCounter::Counter { function_source_hash: self.function_source_hash, id: self.next_counter(), }; @@ -93,19 +135,19 @@ impl CoverageCounters { op: Op, rhs: Operand, debug_block_label_fn: F, - ) -> CoverageKind + ) -> BcbCounter where F: Fn() -> Option, { let id = self.next_expression(); - let expression = CoverageKind::Expression { id, lhs, op, rhs }; + let expression = BcbCounter::Expression { id, lhs, op, rhs }; if self.debug_counters.is_enabled() { self.debug_counters.add_counter(&expression, (debug_block_label_fn)()); } expression } - pub fn make_identity_counter(&mut self, counter_operand: Operand) -> CoverageKind { + pub fn make_identity_counter(&mut self, counter_operand: Operand) -> BcbCounter { let some_debug_block_label = if self.debug_counters.is_enabled() { self.debug_counters.some_block_label(counter_operand).cloned() } else { @@ -134,7 +176,7 @@ impl CoverageCounters { fn set_bcb_counter( &mut self, bcb: BasicCoverageBlock, - counter_kind: CoverageKind, + counter_kind: BcbCounter, ) -> Result { debug_assert!( // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also @@ -158,7 +200,7 @@ impl CoverageCounters { &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, - counter_kind: CoverageKind, + counter_kind: BcbCounter, ) -> Result { if level_enabled!(tracing::Level::DEBUG) { // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also @@ -183,17 +225,17 @@ impl CoverageCounters { } } - pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<&CoverageKind> { + pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<&BcbCounter> { self.bcb_counters[bcb].as_ref() } - pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option { + pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option { self.bcb_counters[bcb].take() } pub(super) fn drain_bcb_counters( &mut self, - ) -> impl Iterator + '_ { + ) -> impl Iterator + '_ { self.bcb_counters .iter_enumerated_mut() .filter_map(|(bcb, counter)| Some((bcb, counter.take()?))) @@ -201,7 +243,7 @@ impl CoverageCounters { pub(super) fn drain_bcb_edge_counters( &mut self, - ) -> impl Iterator + '_ { + ) -> impl Iterator + '_ { self.bcb_edge_counters.drain() } } @@ -653,7 +695,7 @@ impl<'a> MakeBcbCounters<'a> { self.branch_counter(branch).is_none() } - fn branch_counter(&self, branch: &BcbBranch) -> Option<&CoverageKind> { + fn branch_counter(&self, branch: &BcbBranch) -> Option<&BcbCounter> { let to_bcb = branch.target_bcb; if let Some(from_bcb) = branch.edge_from_bcb { self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) @@ -675,7 +717,7 @@ impl<'a> MakeBcbCounters<'a> { } #[inline] - fn format_counter(&self, counter_kind: &CoverageKind) -> String { + fn format_counter(&self, counter_kind: &BcbCounter) -> String { self.coverage_counters.debug_counters.format_counter(counter_kind) } } diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index 083f1f8aef69..af616c498fd3 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -108,7 +108,7 @@ //! recursively, generating labels with nested operations, enclosed in parentheses //! (for example: `bcb2 + (bcb0 - bcb1)`). -use super::counters::CoverageCounters; +use super::counters::{BcbCounter, CoverageCounters}; use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use super::spans::CoverageSpan; @@ -247,11 +247,11 @@ impl Default for ExpressionFormat { } } -/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `Operand`) to -/// the `CoverageKind` data and optional label (normally, the counter's associated +/// If enabled, this struct maintains a map from `BcbCounter` IDs (as `Operand`) to +/// the `BcbCounter` data and optional label (normally, the counter's associated /// `BasicCoverageBlock` format string, if any). /// -/// Use `format_counter` to convert one of these `CoverageKind` counters to a debug output string, +/// Use `format_counter` to convert one of these `BcbCounter` counters to a debug output string, /// as directed by the `DebugOptions`. This allows the format of counter labels in logs and dump /// files (including the `CoverageGraph` graphviz file) to be changed at runtime, via environment /// variable. @@ -276,7 +276,7 @@ impl DebugCounters { self.some_counters.is_some() } - pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option) { + pub fn add_counter(&mut self, counter_kind: &BcbCounter, some_block_label: Option) { if let Some(counters) = &mut self.some_counters { let id = counter_kind.as_operand(); counters @@ -291,21 +291,20 @@ impl DebugCounters { }) } - pub fn format_counter(&self, counter_kind: &CoverageKind) -> String { + pub fn format_counter(&self, counter_kind: &BcbCounter) -> String { match *counter_kind { - CoverageKind::Counter { .. } => { + BcbCounter::Counter { .. } => { format!("Counter({})", self.format_counter_kind(counter_kind)) } - CoverageKind::Expression { .. } => { + BcbCounter::Expression { .. } => { format!("Expression({})", self.format_counter_kind(counter_kind)) } - CoverageKind::Unreachable { .. } => "Unreachable".to_owned(), } } - fn format_counter_kind(&self, counter_kind: &CoverageKind) -> String { + fn format_counter_kind(&self, counter_kind: &BcbCounter) -> String { let counter_format = &debug_options().counter_format; - if let CoverageKind::Expression { id, lhs, op, rhs } = *counter_kind { + if let BcbCounter::Expression { id, lhs, op, rhs } = *counter_kind { if counter_format.operation { return format!( "{}{} {} {}", @@ -346,7 +345,7 @@ impl DebugCounters { } if let Some(counters) = &self.some_counters { if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) { - if let CoverageKind::Expression { .. } = counter_kind { + if let BcbCounter::Expression { .. } = counter_kind { if let Some(label) = some_block_label && debug_options().counter_format.block { return format!( "{}:({})", @@ -366,12 +365,12 @@ impl DebugCounters { /// A non-public support class to `DebugCounters`. #[derive(Debug)] struct DebugCounter { - counter_kind: CoverageKind, + counter_kind: BcbCounter, some_block_label: Option, } impl DebugCounter { - fn new(counter_kind: CoverageKind, some_block_label: Option) -> Self { + fn new(counter_kind: BcbCounter, some_block_label: Option) -> Self { Self { counter_kind, some_block_label } } } @@ -380,9 +379,9 @@ impl DebugCounter { /// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes. pub(super) struct GraphvizData { some_bcb_to_coverage_spans_with_counters: - Option>>, - some_bcb_to_dependency_counters: Option>>, - some_edge_to_counter: Option>, + Option>>, + some_bcb_to_dependency_counters: Option>>, + some_edge_to_counter: Option>, } impl GraphvizData { @@ -409,7 +408,7 @@ impl GraphvizData { &mut self, bcb: BasicCoverageBlock, coverage_span: &CoverageSpan, - counter_kind: &CoverageKind, + counter_kind: &BcbCounter, ) { if let Some(bcb_to_coverage_spans_with_counters) = self.some_bcb_to_coverage_spans_with_counters.as_mut() @@ -424,7 +423,7 @@ impl GraphvizData { pub fn get_bcb_coverage_spans_with_counters( &self, bcb: BasicCoverageBlock, - ) -> Option<&[(CoverageSpan, CoverageKind)]> { + ) -> Option<&[(CoverageSpan, BcbCounter)]> { if let Some(bcb_to_coverage_spans_with_counters) = self.some_bcb_to_coverage_spans_with_counters.as_ref() { @@ -437,7 +436,7 @@ impl GraphvizData { pub fn add_bcb_dependency_counter( &mut self, bcb: BasicCoverageBlock, - counter_kind: &CoverageKind, + counter_kind: &BcbCounter, ) { if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() { bcb_to_dependency_counters @@ -447,7 +446,7 @@ impl GraphvizData { } } - pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[CoverageKind]> { + pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[BcbCounter]> { if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() { bcb_to_dependency_counters.get(&bcb).map(Deref::deref) } else { @@ -459,7 +458,7 @@ impl GraphvizData { &mut self, from_bcb: BasicCoverageBlock, to_bb: BasicBlock, - counter_kind: &CoverageKind, + counter_kind: &BcbCounter, ) { if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() { edge_to_counter @@ -472,7 +471,7 @@ impl GraphvizData { &self, from_bcb: BasicCoverageBlock, to_bb: BasicBlock, - ) -> Option<&CoverageKind> { + ) -> Option<&BcbCounter> { if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() { edge_to_counter.get(&(from_bcb, to_bb)) } else { @@ -488,7 +487,7 @@ impl GraphvizData { pub(super) struct UsedExpressions { some_used_expression_operands: Option>>, some_unused_expressions: - Option, BasicCoverageBlock)>>, + Option, BasicCoverageBlock)>>, } impl UsedExpressions { @@ -506,16 +505,16 @@ impl UsedExpressions { self.some_used_expression_operands.is_some() } - pub fn add_expression_operands(&mut self, expression: &CoverageKind) { + pub fn add_expression_operands(&mut self, expression: &BcbCounter) { if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() { - if let CoverageKind::Expression { id, lhs, rhs, .. } = *expression { + if let BcbCounter::Expression { id, lhs, rhs, .. } = *expression { used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id); used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id); } } } - pub fn expression_is_used(&self, expression: &CoverageKind) -> bool { + pub fn expression_is_used(&self, expression: &BcbCounter) -> bool { if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() { used_expression_operands.contains_key(&expression.as_operand()) } else { @@ -525,7 +524,7 @@ impl UsedExpressions { pub fn add_unused_expression_if_not_found( &mut self, - expression: &CoverageKind, + expression: &BcbCounter, edge_from_bcb: Option, target_bcb: BasicCoverageBlock, ) { @@ -540,11 +539,11 @@ impl UsedExpressions { } } - /// Return the list of unused counters (if any) as a tuple with the counter (`CoverageKind`), + /// Return the list of unused counters (if any) as a tuple with the counter (`BcbCounter`), /// optional `from_bcb` (if it was an edge counter), and `target_bcb`. pub fn get_unused_expressions( &self, - ) -> Vec<(CoverageKind, Option, BasicCoverageBlock)> { + ) -> Vec<(BcbCounter, Option, BasicCoverageBlock)> { if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { unused_expressions.clone() } else { @@ -560,7 +559,7 @@ impl UsedExpressions { bcb_counters_without_direct_coverage_spans: &[( Option, BasicCoverageBlock, - CoverageKind, + BcbCounter, )], ) { if self.is_enabled() { @@ -662,7 +661,7 @@ pub(super) fn dump_coverage_graphviz<'tcx>( basic_coverage_blocks: &CoverageGraph, coverage_counters: &CoverageCounters, graphviz_data: &GraphvizData, - intermediate_expressions: &[CoverageKind], + intermediate_expressions: &[BcbCounter], debug_used_expressions: &UsedExpressions, ) { let debug_counters = &coverage_counters.debug_counters; @@ -743,9 +742,9 @@ fn bcb_to_string_sections<'tcx>( coverage_counters: &CoverageCounters, bcb: BasicCoverageBlock, bcb_data: &BasicCoverageBlockData, - some_coverage_spans_with_counters: Option<&[(CoverageSpan, CoverageKind)]>, - some_dependency_counters: Option<&[CoverageKind]>, - some_intermediate_expressions: Option<&[CoverageKind]>, + some_coverage_spans_with_counters: Option<&[(CoverageSpan, BcbCounter)]>, + some_dependency_counters: Option<&[BcbCounter]>, + some_intermediate_expressions: Option<&[BcbCounter]>, ) -> Vec { let debug_counters = &coverage_counters.debug_counters; diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 43a54496db07..39b56d1f00b9 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -8,9 +8,9 @@ mod spans; #[cfg(test)] mod tests; -use counters::CoverageCounters; -use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; -use spans::{CoverageSpan, CoverageSpans}; +use self::counters::{BcbCounter, CoverageCounters}; +use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use self::spans::{CoverageSpan, CoverageSpans}; use crate::MirPass; @@ -270,8 +270,11 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { //////////////////////////////////////////////////// // Finally, inject the intermediate expressions collected along the way. - for intermediate_expression in self.coverage_counters.intermediate_expressions.drain(..) { - inject_intermediate_expression(self.mir_body, intermediate_expression); + for intermediate_expression in &self.coverage_counters.intermediate_expressions { + inject_intermediate_expression( + self.mir_body, + self.make_mir_coverage_kind(intermediate_expression), + ); } } @@ -314,7 +317,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { inject_statement( self.mir_body, - counter_kind, + self.make_mir_coverage_kind(&counter_kind), self.bcb_leader_bb(bcb), Some(code_region), ); @@ -362,7 +365,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { ); match counter_kind { - CoverageKind::Counter { .. } => { + BcbCounter::Counter { .. } => { let inject_to_bb = if let Some(from_bcb) = edge_from_bcb { // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the @@ -395,12 +398,17 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { target_bb }; - inject_statement(self.mir_body, counter_kind, inject_to_bb, None); + inject_statement( + self.mir_body, + self.make_mir_coverage_kind(&counter_kind), + inject_to_bb, + None, + ); } - CoverageKind::Expression { .. } => { - inject_intermediate_expression(self.mir_body, counter_kind) - } - _ => bug!("CoverageKind should be a counter"), + BcbCounter::Expression { .. } => inject_intermediate_expression( + self.mir_body, + self.make_mir_coverage_kind(&counter_kind), + ), } } } @@ -421,9 +429,20 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { } #[inline] - fn format_counter(&self, counter_kind: &CoverageKind) -> String { + fn format_counter(&self, counter_kind: &BcbCounter) -> String { self.coverage_counters.debug_counters.format_counter(counter_kind) } + + fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { + match *counter_kind { + BcbCounter::Counter { function_source_hash, id } => { + CoverageKind::Counter { function_source_hash, id } + } + BcbCounter::Expression { id, lhs, op, rhs } => { + CoverageKind::Expression { id, lhs, op, rhs } + } + } + } } fn inject_edge_counter_basic_block( diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index f46542ef58bd..99ac769be648 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -34,7 +34,6 @@ use itertools::Itertools; use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithSuccessors; use rustc_index::{Idx, IndexVec}; -use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::*; use rustc_middle::ty; use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP}; @@ -685,7 +684,7 @@ fn test_make_bcb_counters() { assert_eq!( 0, // bcb1 has a `Counter` with id = 0 match coverage_counters.bcb_counter(bcb1).expect("should have a counter") { - CoverageKind::Counter { id, .. } => id, + counters::BcbCounter::Counter { id, .. } => id, _ => panic!("expected a Counter"), } .as_u32() @@ -695,7 +694,7 @@ fn test_make_bcb_counters() { assert_eq!( 1, // bcb2 has a `Counter` with id = 1 match coverage_counters.bcb_counter(bcb2).expect("should have a counter") { - CoverageKind::Counter { id, .. } => id, + counters::BcbCounter::Counter { id, .. } => id, _ => panic!("expected a Counter"), } .as_u32() From 72f4c78dc6d5fc4a09d946f979ccfbf3fa763585 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 14 Aug 2023 12:16:29 +1000 Subject: [PATCH 158/169] coverage: Don't store `function_source_hash` in `BcbCounter::Counter` This shows one small benefit of separating `BcbCounter` from `CoverageKind`. The function source hash will be the same for all counters within a function, so instead of passing it through `CoverageCounters` and storing it in every counter, we can just supply it during the final conversion to `CoverageKind`. --- compiler/rustc_mir_transform/src/coverage/counters.rs | 11 +++-------- compiler/rustc_mir_transform/src/coverage/mod.rs | 8 +++++--- compiler/rustc_mir_transform/src/coverage/tests.rs | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 3eca2610de60..3d442e5dca9f 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -20,7 +20,7 @@ use std::fmt::{self, Debug}; /// BCB node or BCB edge. #[derive(Clone)] pub(super) enum BcbCounter { - Counter { function_source_hash: u64, id: CounterId }, + Counter { id: CounterId }, Expression { id: ExpressionId, lhs: Operand, op: Op, rhs: Operand }, } @@ -59,7 +59,6 @@ impl Debug for BcbCounter { /// Generates and stores coverage counter and coverage expression information /// associated with nodes/edges in the BCB graph. pub(super) struct CoverageCounters { - function_source_hash: u64, next_counter_id: CounterId, next_expression_id: ExpressionId, @@ -81,11 +80,10 @@ pub(super) struct CoverageCounters { } impl CoverageCounters { - pub(super) fn new(function_source_hash: u64, basic_coverage_blocks: &CoverageGraph) -> Self { + pub(super) fn new(basic_coverage_blocks: &CoverageGraph) -> Self { let num_bcbs = basic_coverage_blocks.num_nodes(); Self { - function_source_hash, next_counter_id: CounterId::START, next_expression_id: ExpressionId::START, @@ -119,10 +117,7 @@ impl CoverageCounters { where F: Fn() -> Option, { - let counter = BcbCounter::Counter { - function_source_hash: self.function_source_hash, - id: self.next_counter(), - }; + let counter = BcbCounter::Counter { id: self.next_counter() }; if self.debug_counters.is_enabled() { self.debug_counters.add_counter(&counter, (debug_block_label_fn)()); } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 39b56d1f00b9..8c9eae508b4a 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -106,6 +106,7 @@ struct Instrumentor<'a, 'tcx> { source_file: Lrc, fn_sig_span: Span, body_span: Span, + function_source_hash: u64, basic_coverage_blocks: CoverageGraph, coverage_counters: CoverageCounters, } @@ -137,7 +138,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let function_source_hash = hash_mir_source(tcx, hir_body); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); - let coverage_counters = CoverageCounters::new(function_source_hash, &basic_coverage_blocks); + let coverage_counters = CoverageCounters::new(&basic_coverage_blocks); Self { pass_name, @@ -146,6 +147,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { source_file, fn_sig_span, body_span, + function_source_hash, basic_coverage_blocks, coverage_counters, } @@ -435,8 +437,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { match *counter_kind { - BcbCounter::Counter { function_source_hash, id } => { - CoverageKind::Counter { function_source_hash, id } + BcbCounter::Counter { id } => { + CoverageKind::Counter { function_source_hash: self.function_source_hash, id } } BcbCounter::Expression { id, lhs, op, rhs } => { CoverageKind::Expression { id, lhs, op, rhs } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 99ac769be648..4a066ed3abde 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -674,7 +674,7 @@ fn test_make_bcb_counters() { )); } } - let mut coverage_counters = counters::CoverageCounters::new(0, &basic_coverage_blocks); + let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks); coverage_counters .make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans) .expect("should be Ok"); From f2f999e7b21bdcf41d5c335f98cc06067cb626a6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 20 Aug 2023 14:44:36 +0200 Subject: [PATCH 159/169] Migrate GUI colors test to original CSS color format --- tests/rustdoc-gui/docblock-table.goml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/rustdoc-gui/docblock-table.goml b/tests/rustdoc-gui/docblock-table.goml index 011451ef4f39..678b302f22e3 100644 --- a/tests/rustdoc-gui/docblock-table.goml +++ b/tests/rustdoc-gui/docblock-table.goml @@ -36,17 +36,17 @@ define-function: ( ) call-function: ("check-colors", { - "theme": "dark", - "border_color": "rgb(224, 224, 224)", - "zebra_stripe_color": "rgb(42, 42, 42)", + "theme": "ayu", + "border_color": "#5c6773", + "zebra_stripe_color": "#191f26", }) call-function: ("check-colors", { - "theme": "ayu", - "border_color": "rgb(92, 103, 115)", - "zebra_stripe_color": "rgb(25, 31, 38)", + "theme": "dark", + "border_color": "#e0e0e0", + "zebra_stripe_color": "#2a2a2a", }) call-function: ("check-colors", { "theme": "light", - "border_color": "rgb(224, 224, 224)", - "zebra_stripe_color": "rgb(245, 245, 245)", + "border_color": "#e0e0e0", + "zebra_stripe_color": "#f5f5f5", }) From 818ec8e23adcc4c6b684fc070b8c7e89c941171e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Aug 2023 13:10:25 +0200 Subject: [PATCH 160/169] give some unwind-related terminators a more clear name --- compiler/rustc_borrowck/src/invalidation.rs | 6 +++-- compiler/rustc_borrowck/src/lib.rs | 10 ++++--- compiler/rustc_borrowck/src/type_check/mod.rs | 8 +++--- compiler/rustc_codegen_cranelift/src/base.rs | 4 +-- .../rustc_codegen_cranelift/src/constant.rs | 4 +-- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 4 +-- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +-- .../src/interpret/terminator.rs | 4 +-- .../src/transform/check_consts/check.rs | 4 +-- .../check_consts/post_drop_elaboration.rs | 4 +-- .../src/transform/validate.rs | 14 +++++----- compiler/rustc_middle/src/mir/patch.rs | 8 +++--- compiler/rustc_middle/src/mir/spanview.rs | 4 +-- compiler/rustc_middle/src/mir/syntax.rs | 8 +++--- compiler/rustc_middle/src/mir/terminator.rs | 26 ++++++++++--------- compiler/rustc_middle/src/mir/visit.rs | 4 +-- compiler/rustc_mir_build/src/build/scope.rs | 14 +++++----- compiler/rustc_mir_build/src/lints.rs | 4 +-- .../src/impls/borrowed_locals.rs | 4 +-- .../src/impls/storage_liveness.rs | 8 +++--- .../src/move_paths/builder.rs | 4 +-- .../rustc_mir_dataflow/src/value_analysis.rs | 4 +-- .../rustc_mir_transform/src/check_unsafety.rs | 4 +-- .../src/const_prop_lint.rs | 4 +-- .../rustc_mir_transform/src/coverage/graph.rs | 4 +-- .../rustc_mir_transform/src/coverage/spans.rs | 4 +-- compiler/rustc_mir_transform/src/dest_prop.rs | 4 +-- .../src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/generator.rs | 12 ++++----- compiler/rustc_mir_transform/src/inline.rs | 10 +++---- .../src/remove_noop_landing_pads.rs | 6 ++--- .../src/separate_const_switch.rs | 8 +++--- compiler/rustc_mir_transform/src/shim.rs | 6 ++--- compiler/rustc_monomorphize/src/collector.rs | 4 +-- compiler/rustc_smir/src/rustc_smir/mod.rs | 4 +-- .../clippy_utils/src/qualify_min_const_fn.rs | 4 +-- .../rust-analyzer/crates/hir-ty/src/mir.rs | 2 +- .../crates/hir-ty/src/mir/borrowck.rs | 6 ++--- .../crates/hir-ty/src/mir/monomorphization.rs | 2 +- 39 files changed, 123 insertions(+), 117 deletions(-) diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index df5e383ad40b..d4c42a758748 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -159,7 +159,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.mutate_place(location, *resume_arg, Deep); } - TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { + TerminatorKind::UnwindResume + | TerminatorKind::Return + | TerminatorKind::GeneratorDrop => { // Invalidate all borrows of local places let borrow_set = self.borrow_set; let start = self.location_table.start_index(location); @@ -200,7 +202,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } TerminatorKind::Goto { target: _ } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index efe525c224d0..ef2788efbcfc 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -770,9 +770,9 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro } TerminatorKind::Goto { target: _ } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate | TerminatorKind::Unreachable - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } @@ -803,7 +803,9 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro } } - TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { + TerminatorKind::UnwindResume + | TerminatorKind::Return + | TerminatorKind::GeneratorDrop => { // Returning from the function implicitly kills storage for all locals and statics. // Often, the storage will already have been killed by an explicit // StorageDead, but we don't always emit those (notably on unwind paths), @@ -815,7 +817,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro } } - TerminatorKind::Terminate + TerminatorKind::UnwindTerminate | TerminatorKind::Assert { .. } | TerminatorKind::Call { .. } | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 50d875dfae99..d91a3d94045e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1333,8 +1333,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("terminator kind: {:?}", term.kind); match &term.kind { TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable @@ -1608,12 +1608,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.assert_iscleanup(body, block_data, *target, is_cleanup); } } - TerminatorKind::Resume => { + TerminatorKind::UnwindResume => { if !is_cleanup { span_mirbug!(self, block_data, "resume on non-cleanup block!") } } - TerminatorKind::Terminate => { + TerminatorKind::UnwindTerminate => { if !is_cleanup { span_mirbug!(self, block_data, "abort on non-cleanup block!") } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 522dd7189fe6..ed371a04c537 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -474,10 +474,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { *destination, ); } - TerminatorKind::Terminate => { + TerminatorKind::UnwindTerminate => { codegen_panic_cannot_unwind(fx, source_info); } - TerminatorKind::Resume => { + TerminatorKind::UnwindResume => { // FIXME implement unwinding fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c31535742957..7db5f79eead9 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -550,8 +550,8 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( match &bb_data.terminator().kind { TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 22c1f05974dd..3f5b46333d9b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -284,8 +284,8 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(bx, terminator.source_info); match terminator.kind { - mir::TerminatorKind::Resume => { + mir::TerminatorKind::UnwindResume => { self.codegen_resume_terminator(helper, bx); MergingSucc::False } - mir::TerminatorKind::Terminate => { + mir::TerminatorKind::UnwindTerminate => { self.codegen_terminate_terminator(helper, bx, terminator); MergingSucc::False } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 3c03172bbeff..afca6a803196 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -196,7 +196,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Terminate => { + UnwindTerminate => { // FIXME: maybe should call `panic_no_unwind` lang item instead. M::abort(self, "panic in a function that cannot unwind".to_owned())?; } @@ -204,7 +204,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // When we encounter Resume, we've finished unwinding // cleanup for the current stack frame. We pop it in order // to continue unwinding the next frame - Resume => { + UnwindResume => { trace!("unwinding: resuming from cleanup"); // By definition, a Resume terminator means // that we're unwinding diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index fae047bff9e7..e67098a3ac38 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -1037,7 +1037,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.check_op(ops::Generator(hir::GeneratorKind::Gen)) } - TerminatorKind::Terminate => { + TerminatorKind::UnwindTerminate => { // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`). span_bug!(self.span, "`Terminate` terminator outside of cleanup block") } @@ -1046,7 +1046,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } | TerminatorKind::Unreachable => {} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index e3377bd10c61..a8c61d2c8fd8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -106,7 +106,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> { } } - mir::TerminatorKind::Terminate + mir::TerminatorKind::UnwindTerminate | mir::TerminatorKind::Call { .. } | mir::TerminatorKind::Assert { .. } | mir::TerminatorKind::FalseEdge { .. } @@ -114,7 +114,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> { | mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::InlineAsm { .. } - | mir::TerminatorKind::Resume + | mir::TerminatorKind::UnwindResume | mir::TerminatorKind::Return | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Unreachable diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 783b52d00402..0dfbbf73dce4 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -492,19 +492,19 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { ); } } - TerminatorKind::Resume => { + TerminatorKind::UnwindResume => { let bb = location.block; if !self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `Resume` from non-cleanup basic block") + self.fail(location, "Cannot `UnwindResume` from non-cleanup basic block") } if !self.can_unwind { - self.fail(location, "Cannot `Resume` in a function that cannot unwind") + self.fail(location, "Cannot `UnwindResume` in a function that cannot unwind") } } - TerminatorKind::Terminate => { + TerminatorKind::UnwindTerminate => { let bb = location.block; if !self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `Terminate` from non-cleanup basic block") + self.fail(location, "Cannot `UnwindTerminate` from non-cleanup basic block") } } TerminatorKind::Return => { @@ -1232,8 +1232,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | TerminatorKind::FalseUnwind { .. } | TerminatorKind::InlineAsm { .. } | TerminatorKind::GeneratorDrop - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable => {} } diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index c4c3341f873a..cd74a403ff6b 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -35,7 +35,7 @@ impl<'tcx> MirPatch<'tcx> { for (bb, block) in body.basic_blocks.iter_enumerated() { // Check if we already have a resume block - if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() { + if let TerminatorKind::UnwindResume = block.terminator().kind && block.statements.is_empty() { result.resume_block = Some(bb); continue; } @@ -50,7 +50,7 @@ impl<'tcx> MirPatch<'tcx> { } // Check if we already have a terminate block - if let TerminatorKind::Terminate = block.terminator().kind && block.statements.is_empty() { + if let TerminatorKind::UnwindTerminate = block.terminator().kind && block.statements.is_empty() { result.terminate_block = Some(bb); continue; } @@ -68,7 +68,7 @@ impl<'tcx> MirPatch<'tcx> { statements: vec![], terminator: Some(Terminator { source_info: SourceInfo::outermost(self.body_span), - kind: TerminatorKind::Resume, + kind: TerminatorKind::UnwindResume, }), is_cleanup: true, }); @@ -102,7 +102,7 @@ impl<'tcx> MirPatch<'tcx> { statements: vec![], terminator: Some(Terminator { source_info: SourceInfo::outermost(self.body_span), - kind: TerminatorKind::Terminate, + kind: TerminatorKind::UnwindTerminate, }), is_cleanup: true, }); diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 20a9e6889e40..30e37e7dabb1 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -262,8 +262,8 @@ pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { match term.kind { Goto { .. } => "Goto", SwitchInt { .. } => "SwitchInt", - Resume => "Resume", - Terminate => "Terminate", + UnwindResume => "Resume", + UnwindTerminate => "Terminate", Return => "Return", Unreachable => "Unreachable", Drop { .. } => "Drop", diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index be27bf75dbd1..a37aa8590763 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -593,13 +593,13 @@ pub enum TerminatorKind<'tcx> { /// /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after /// deaggregation runs. - Resume, + UnwindResume, /// Indicates that the landing pad is finished and that the process should terminate. /// /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in /// cleanup blocks. - Terminate, + UnwindTerminate, /// Returns from the function. /// @@ -790,8 +790,8 @@ impl TerminatorKind<'_> { match self { TerminatorKind::Goto { .. } => "Goto", TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::Resume => "Resume", - TerminatorKind::Terminate => "Terminate", + TerminatorKind::UnwindResume => "Resume", + TerminatorKind::UnwindTerminate => "Terminate", TerminatorKind::Return => "Return", TerminatorKind::Unreachable => "Unreachable", TerminatorKind::Drop { .. } => "Drop", diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 1f878d23b443..bd87563e2bb4 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -155,8 +155,8 @@ impl<'tcx> TerminatorKind<'tcx> { | InlineAsm { destination: Some(t), unwind: _, .. } => { Some(t).into_iter().chain((&[]).into_iter().copied()) } - Resume - | Terminate + UnwindResume + | UnwindTerminate | GeneratorDrop | Return | Unreachable @@ -197,8 +197,8 @@ impl<'tcx> TerminatorKind<'tcx> { | InlineAsm { destination: Some(ref mut t), unwind: _, .. } => { Some(t).into_iter().chain(&mut []) } - Resume - | Terminate + UnwindResume + | UnwindTerminate | GeneratorDrop | Return | Unreachable @@ -214,8 +214,8 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn unwind(&self) -> Option<&UnwindAction> { match *self { TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop @@ -233,8 +233,8 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { match *self { TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop @@ -311,8 +311,8 @@ impl<'tcx> TerminatorKind<'tcx> { SwitchInt { discr, .. } => write!(fmt, "switchInt({discr:?})"), Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), - Resume => write!(fmt, "resume"), - Terminate => write!(fmt, "abort"), + UnwindResume => write!(fmt, "resume"), + UnwindTerminate => write!(fmt, "abort"), Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"), Unreachable => write!(fmt, "unreachable"), Drop { place, .. } => write!(fmt, "drop({place:?})"), @@ -391,7 +391,7 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn fmt_successor_labels(&self) -> Vec> { use self::TerminatorKind::*; match *self { - Return | Resume | Terminate | Unreachable | GeneratorDrop => vec![], + Return | UnwindResume | UnwindTerminate | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], SwitchInt { ref targets, .. } => targets .values @@ -486,7 +486,9 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> { use TerminatorKind::*; match *self { - Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdges::None, + Return | UnwindResume | UnwindTerminate | GeneratorDrop | Unreachable => { + TerminatorEdges::None + } Goto { target } => TerminatorEdges::Single(target), diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 069b38591684..b3d3366ae104 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -469,8 +469,8 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); match kind { TerminatorKind::Goto { .. } | - TerminatorKind::Resume | - TerminatorKind::Terminate | + TerminatorKind::UnwindResume | + TerminatorKind::UnwindTerminate | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { .. } | diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index a96288a11e58..567e7bfb5bf8 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -685,9 +685,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { drops.add_entry(block, drop_idx); // `build_drop_trees` doesn't have access to our source_info, so we - // create a dummy terminator now. `TerminatorKind::Resume` is used + // create a dummy terminator now. `TerminatorKind::UnwindResume` is used // because MIR type checking will panic if it hasn't been overwritten. - self.cfg.terminate(block, source_info, TerminatorKind::Resume); + self.cfg.terminate(block, source_info, TerminatorKind::UnwindResume); self.cfg.start_new_block().unit() } @@ -717,9 +717,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { drops.add_entry(block, drop_idx); // `build_drop_trees` doesn't have access to our source_info, so we - // create a dummy terminator now. `TerminatorKind::Resume` is used + // create a dummy terminator now. `TerminatorKind::UnwindResume` is used // because MIR type checking will panic if it hasn't been overwritten. - self.cfg.terminate(block, source_info, TerminatorKind::Resume); + self.cfg.terminate(block, source_info, TerminatorKind::UnwindResume); } // Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue` @@ -1441,7 +1441,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { blocks[ROOT_NODE] = *resume_block; drops.build_mir::(cfg, &mut blocks); if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) { - cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::Resume); + cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::UnwindResume); *resume_block = blocks[ROOT_NODE]; } @@ -1506,8 +1506,8 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { } TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Yield { .. } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 7fb73b5c7b2f..84c80bf41a4d 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -186,9 +186,9 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor ControlFlow::Break(NonRecursive), diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 8d7b50796bbf..5ed8f20b73f1 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -131,7 +131,7 @@ where } } - TerminatorKind::Terminate + TerminatorKind::UnwindTerminate | TerminatorKind::Assert { .. } | TerminatorKind::Call { .. } | TerminatorKind::FalseEdge { .. } @@ -139,7 +139,7 @@ where | TerminatorKind::GeneratorDrop | TerminatorKind::Goto { .. } | TerminatorKind::InlineAsm { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } | TerminatorKind::Unreachable diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index bea23b7f7ae1..531390c2f077 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -291,14 +291,14 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { // Nothing to do for these. Match exhaustively so this fails to compile when new // variants are added. - TerminatorKind::Terminate + TerminatorKind::UnwindTerminate | TerminatorKind::Assert { .. } | TerminatorKind::Drop { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::GeneratorDrop | TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } | TerminatorKind::Unreachable => {} @@ -328,14 +328,14 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { // Nothing to do for these. Match exhaustively so this fails to compile when new // variants are added. TerminatorKind::Yield { .. } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate | TerminatorKind::Assert { .. } | TerminatorKind::Drop { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::GeneratorDrop | TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } | TerminatorKind::Unreachable => {} diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 5052de991840..4adf3dec61be 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -370,8 +370,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // this that could possibly access the return place, this doesn't // need recording. | TerminatorKind::Return - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } => {} diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 766e0257efdc..1eea8eef0adf 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -269,8 +269,8 @@ pub trait ValueAnalysis<'tcx> { return self.handle_switch_int(discr, targets, state); } TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Assert { .. } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 58e9786ec1a5..e72db1a59a05 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -57,8 +57,8 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { | TerminatorKind::Yield { .. } | TerminatorKind::Assert { .. } | TerminatorKind::GeneratorDrop - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { .. } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index ac07c25763ba..4f8ca916d5b4 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -678,8 +678,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { } // None of these have Operands to const-propagate. TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 59b01ffec0f1..d3d4fcd3a527 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -116,7 +116,7 @@ impl CoverageGraph { match term.kind { TerminatorKind::Return { .. } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } => { // The `bb` has more than one _outgoing_ edge, or exits the function. Save the @@ -146,7 +146,7 @@ impl CoverageGraph { // is as intended. (See Issue #78544 for a possible future option to support // coverage in test programs that panic.) TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } | TerminatorKind::Call { .. } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index deebf5345bac..6fabaca524a0 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -867,8 +867,8 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option (), TerminatorKind::Drop { .. } => { diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index b6b1ae6d3c37..a80ae480089b 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -470,7 +470,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // drop elaboration should handle that by itself continue; } - TerminatorKind::Resume => { + TerminatorKind::UnwindResume => { // It is possible for `Resume` to be patched // (in particular it can be patched to be replaced with // a Goto; see `MirPatch::new`). diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index ff4822f333f0..96077322575e 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1239,7 +1239,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { // These never unwind. TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop @@ -1248,7 +1248,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { // Resume will *continue* unwinding, but if there's no other unwinding terminator it // will never be reached. - TerminatorKind::Resume => {} + TerminatorKind::UnwindResume => {} TerminatorKind::Yield { .. } => { unreachable!("`can_unwind` called before generator transform") @@ -1279,14 +1279,14 @@ fn create_generator_resume_function<'tcx>( let source_info = SourceInfo::outermost(body.span); let poison_block = body.basic_blocks_mut().push(BasicBlockData { statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }), + terminator: Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }), is_cleanup: true, }); for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() { let source_info = block.terminator().source_info; - if let TerminatorKind::Resume = block.terminator().kind { + if let TerminatorKind::UnwindResume = block.terminator().kind { // An existing `Resume` terminator is redirected to jump to our dedicated // "poisoning block" above. if idx != poison_block { @@ -1758,8 +1758,8 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { TerminatorKind::Call { .. } | TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index fc9e18378d5a..734e93783d10 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -839,7 +839,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { self.cost += LANDINGPAD_PENALTY; } } - TerminatorKind::Resume => self.cost += RESUME_PENALTY, + TerminatorKind::UnwindResume => self.cost += RESUME_PENALTY, TerminatorKind::InlineAsm { unwind, .. } => { self.cost += INSTR_COST; if let UnwindAction::Cleanup(_) = unwind { @@ -1017,15 +1017,15 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { TerminatorKind::Unreachable } } - TerminatorKind::Resume => { + TerminatorKind::UnwindResume => { terminator.kind = match self.cleanup_block { UnwindAction::Cleanup(tgt) => TerminatorKind::Goto { target: tgt }, - UnwindAction::Continue => TerminatorKind::Resume, + UnwindAction::Continue => TerminatorKind::UnwindResume, UnwindAction::Unreachable => TerminatorKind::Unreachable, - UnwindAction::Terminate => TerminatorKind::Terminate, + UnwindAction::Terminate => TerminatorKind::UnwindTerminate, }; } - TerminatorKind::Terminate => {} + TerminatorKind::UnwindTerminate => {} TerminatorKind::Unreachable => {} TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => { *real_target = self.map_block(*real_target); diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 4e85c76fbc06..5782adbb3ffa 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -63,7 +63,7 @@ impl RemoveNoopLandingPads { let terminator = body[bb].terminator(); match terminator.kind { TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => { @@ -72,7 +72,7 @@ impl RemoveNoopLandingPads { TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | TerminatorKind::Return - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate | TerminatorKind::Unreachable | TerminatorKind::Call { .. } | TerminatorKind::Assert { .. } @@ -88,7 +88,7 @@ impl RemoveNoopLandingPads { let has_resume = body .basic_blocks .iter_enumerated() - .any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::Resume)); + .any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::UnwindResume)); if !has_resume { debug!("remove_noop_landing_pads: no resume block in MIR"); return; diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 1d8e54cdca09..de1b80585d15 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -108,13 +108,13 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize { } // The following terminators are not allowed - TerminatorKind::Resume + TerminatorKind::UnwindResume | TerminatorKind::Drop { .. } | TerminatorKind::Call { .. } | TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Yield { .. } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::InlineAsm { .. } @@ -165,8 +165,8 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize { }); } - TerminatorKind::Resume - | TerminatorKind::Terminate + TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 223dc59c68d1..046eed2dd193 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -583,7 +583,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { I: IntoIterator>, { self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); - let unwind = self.block(vec![], TerminatorKind::Resume, true); + let unwind = self.block(vec![], TerminatorKind::UnwindResume, true); let target = self.block(vec![], TerminatorKind::Return, false); let _final_cleanup_block = self.clone_fields(dest, src, target, unwind, tys); @@ -597,7 +597,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { args: GeneratorArgs<'tcx>, ) { self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); - let unwind = self.block(vec![], TerminatorKind::Resume, true); + let unwind = self.block(vec![], TerminatorKind::UnwindResume, true); // This will get overwritten with a switch once we know the target blocks let switch = self.block(vec![], TerminatorKind::Unreachable, false); let unwind = self.clone_fields(dest, src, switch, unwind, args.upvar_tys()); @@ -854,7 +854,7 @@ fn build_call_shim<'tcx>( ); // BB #4 - resume - block(&mut blocks, vec![], TerminatorKind::Resume, true); + block(&mut blocks, vec![], TerminatorKind::UnwindResume, true); } let mut body = diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 55b14ce1c3ee..cd7908e75e20 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -776,7 +776,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { self.output.push(create_fn_mono_item(tcx, instance, source)); } } - mir::TerminatorKind::Terminate { .. } => { + mir::TerminatorKind::UnwindTerminate { .. } => { let instance = Instance::mono( tcx, tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)), @@ -787,7 +787,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } - | mir::TerminatorKind::Resume + | mir::TerminatorKind::UnwindResume | mir::TerminatorKind::Return | mir::TerminatorKind::Unreachable => {} mir::TerminatorKind::GeneratorDrop diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 06b37008ebed..7e8ac9a141a7 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -780,8 +780,8 @@ impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { .collect(), otherwise: targets.otherwise().as_usize(), }, - Resume => Terminator::Resume, - Terminate => Terminator::Abort, + UnwindResume => Terminator::Resume, + UnwindTerminate => Terminator::Abort, Return => Terminator::Return, Unreachable => Terminator::Unreachable, Drop { place, target, unwind, replace: _ } => Terminator::Drop { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 139e31bc5286..43523faa2361 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -291,8 +291,8 @@ fn check_terminator<'tcx>( | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } | TerminatorKind::Return - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate | TerminatorKind::Unreachable => Ok(()), TerminatorKind::Drop { place, .. } => { if !is_ty_const_destruct(tcx, place.ty(&body.local_decls, tcx).ty, body) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 4723c25ed080..76a535e3067c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -1057,7 +1057,7 @@ impl MirBody { TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::GeneratorDrop | TerminatorKind::Abort | TerminatorKind::Return diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index ad98e8fa1810..c70d7f63fd88 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -160,7 +160,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::GeneratorDrop | TerminatorKind::Abort | TerminatorKind::Return @@ -280,7 +280,7 @@ fn ever_initialized_map( let targets = match &terminator.kind { TerminatorKind::Goto { target } => vec![*target], TerminatorKind::SwitchInt { targets, .. } => targets.all_targets().to_vec(), - TerminatorKind::Resume + TerminatorKind::UnwindResume | TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::Unreachable => vec![], @@ -371,7 +371,7 @@ fn mutability_of_locals( }; match &terminator.kind { TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::Unreachable diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index c565228d91e7..df16d0d82015 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -265,7 +265,7 @@ impl Filler<'_> { self.fill_operand(discr)?; } TerminatorKind::Goto { .. } - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Abort | TerminatorKind::Return | TerminatorKind::Unreachable From 788fd44a3be128243ac48539d23235a3d91d9a85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Aug 2023 13:21:41 +0200 Subject: [PATCH 161/169] interpret/miri: call panic_cannot_unwind lang item instead of hard-coding the same message --- .../src/interpret/eval_context.rs | 6 +++- .../rustc_const_eval/src/interpret/machine.rs | 8 ++++++ .../src/interpret/terminator.rs | 3 +- src/tools/miri/src/machine.rs | 14 ++++++++++ .../exported_symbol_bad_unwind2.both.stderr | 27 +++++++++++++----- ...orted_symbol_bad_unwind2.definition.stderr | 27 +++++++++++++----- ...ted_symbol_bad_unwind2.extern_block.stderr | 2 +- .../exported_symbol_bad_unwind2.rs | 7 +++-- .../miri/tests/fail/panic/double_panic.rs | 3 +- .../miri/tests/fail/panic/double_panic.stderr | 24 ++++++++++++---- .../miri/tests/fail/terminate-terminator.rs | 8 ++++-- .../tests/fail/terminate-terminator.stderr | 28 ++++++++++++++----- .../tests/fail/unwind-action-terminate.rs | 6 +++- .../tests/fail/unwind-action-terminate.stderr | 26 +++++++++++++---- 14 files changed, 147 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3ac6f07e8b7b..61d3de5c4050 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -765,7 +765,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } mir::UnwindAction::Terminate => { self.frame_mut().loc = Right(self.frame_mut().body.span); - M::abort(self, "panic in a function that cannot unwind".to_owned())?; + M::unwind_terminate(self)?; + // This might have pushed a new stack frame, or it terminated execution. + // Either way, `loc` will not be updated. + return Ok(()); } }; Ok(()) @@ -865,6 +868,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { panic!("encountered StackPopCleanup::Root when unwinding!") } }; + // This must be the very last thing that happens, since it can in fact push a new stack frame. self.unwind_to_block(unwind) } else { // Follow the normal return edge. diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index e101785b6e24..15f2dd17bf57 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -223,6 +223,9 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { throw_unsup_format!("aborting execution is not supported") } + /// Called when unwinding reached a state where execution should be terminated. + fn unwind_terminate(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>; + /// Called for all binary operations where the LHS has pointer type. /// /// Returns a (value, overflowed) pair if the operation succeeded @@ -499,6 +502,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { false } + #[inline(always)] + fn unwind_terminate(_ecx: &mut InterpCx<$mir, $tcx, Self>) -> InterpResult<$tcx> { + unreachable!("unwinding cannot happen during compile-time evaluation") + } + #[inline(always)] fn call_extra_fn( _ecx: &mut InterpCx<$mir, $tcx, Self>, diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index afca6a803196..b2ebcceceb32 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -197,8 +197,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } UnwindTerminate => { - // FIXME: maybe should call `panic_no_unwind` lang item instead. - M::abort(self, "panic in a function that cannot unwind".to_owned())?; + M::unwind_terminate(self)?; } // When we encounter Resume, we've finished unwinding diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 90c3c70ae5b4..069cb20974e7 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -976,6 +976,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { throw_machine_stop!(TerminationInfo::Abort(msg)) } + fn unwind_terminate(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + // Call the lang item. + let panic = ecx.tcx.lang_items().panic_cannot_unwind().unwrap(); + let panic = ty::Instance::mono(ecx.tcx.tcx, panic); + ecx.call_function( + panic, + Abi::Rust, + &[], + None, + StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable }, + )?; + Ok(()) + } + #[inline(always)] fn binary_ptr_op( ecx: &MiriInterpCx<'mir, 'tcx>, diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index bf5199307f6c..e4821bc0bac2 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -1,22 +1,35 @@ thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: abnormal termination: panic in a function that cannot unwind +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +panic in a function that cannot unwind +stack backtrace: +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `nounwind` --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | -LL | | LL | | panic!(); LL | | } - | |_^ panic in a function that cannot unwind - | - = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | |_^ note: inside `main` --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } - | ^^^^^^^^^^ + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index bf5199307f6c..e4821bc0bac2 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -1,22 +1,35 @@ thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: abnormal termination: panic in a function that cannot unwind +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +panic in a function that cannot unwind +stack backtrace: +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `nounwind` --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | -LL | | LL | | panic!(); LL | | } - | |_^ panic in a function that cannot unwind - | - = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | |_^ note: inside `main` --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } - | ^^^^^^^^^^ + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index c774bd4dd911..25e13d747542 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -5,7 +5,7 @@ error: Undefined Behavior: unwinding past a stack frame that does not allow unwi --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } - | ^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | ^ unwinding past a stack frame that does not allow unwinding | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index 65ba3433c28c..10bd5eb7211d 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -1,11 +1,14 @@ //@revisions: extern_block definition both +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" +//@[definition,both]error-in-other-file: aborted execution #![feature(rustc_attrs, c_unwind)] #[cfg_attr(any(definition, both), rustc_nounwind)] #[no_mangle] extern "C-unwind" fn nounwind() { - //~[definition]^ ERROR: abnormal termination: panic in a function that cannot unwind - //~[both]^^ ERROR: abnormal termination: panic in a function that cannot unwind panic!(); } diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs index adb30714269e..4627e9f1c8e1 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.rs +++ b/src/tools/miri/tests/fail/panic/double_panic.rs @@ -1,6 +1,8 @@ +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" //@normalize-stderr-test: "\n at [^\n]+" -> "$1" +//@error-in-other-file: aborted execution struct Foo; impl Drop for Foo { @@ -9,7 +11,6 @@ impl Drop for Foo { } } fn main() { - //~^ERROR: panic in a function that cannot unwind let _foo = Foo; panic!("first"); } diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 8e008da75ee8..25c9a7c44bcb 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -4,17 +4,31 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at $DIR/double_panic.rs:LL:CC: second stack backtrace: -error: abnormal termination: panic in a function that cannot unwind +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +panic in a function that cannot unwind +stack backtrace: +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` --> $DIR/double_panic.rs:LL:CC | LL | / fn main() { -LL | | LL | | let _foo = Foo; LL | | panic!("first"); LL | | } - | |_^ panic in a function that cannot unwind - | - = note: inside `main` at $DIR/double_panic.rs:LL:CC + | |_^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs index bd6cd69215ae..5373b5f70c07 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.rs +++ b/src/tools/miri/tests/fail/terminate-terminator.rs @@ -1,5 +1,10 @@ //@compile-flags: -Zmir-opt-level=3 -Zinline-mir-hint-threshold=1000 -// Enable MIR inlining to ensure that `TerminatorKind::Terminate` is generated +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" +//@error-in-other-file: aborted execution +// Enable MIR inlining to ensure that `TerminatorKind::UnwindTerminate` is generated // instead of just `UnwindAction::Terminate`. #![feature(c_unwind)] @@ -12,7 +17,6 @@ impl Drop for Foo { #[inline(always)] fn has_cleanup() { - //~^ ERROR: panic in a function that cannot unwind let _f = Foo; panic!(); } diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index 4f73b599a3f9..e9277ebdbfd3 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -3,27 +3,41 @@ warning: You have explicitly enabled MIR optimizations, overriding Miri's defaul thread 'main' panicked at $DIR/terminate-terminator.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: abnormal termination: panic in a function that cannot unwind +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +panic in a function that cannot unwind +stack backtrace: +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `has_cleanup` --> $DIR/terminate-terminator.rs:LL:CC | LL | / fn has_cleanup() { -LL | | LL | | let _f = Foo; LL | | panic!(); LL | | } - | |_^ panic in a function that cannot unwind - | - = note: inside `has_cleanup` at $DIR/terminate-terminator.rs:LL:CC + | |_^ note: inside `panic_abort` --> $DIR/terminate-terminator.rs:LL:CC | LL | has_cleanup(); - | ^^^^^^^^^^^^^ + | ^ note: inside `main` --> $DIR/terminate-terminator.rs:LL:CC | LL | panic_abort(); - | ^^^^^^^^^^^^^ + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs index 876b9a9ab0ab..77844844483e 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.rs +++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs @@ -1,7 +1,11 @@ +//@error-in-other-file: aborted execution +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" #![feature(c_unwind)] extern "C" fn panic_abort() { - //~^ ERROR: panic in a function that cannot unwind panic!() } diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index daa4a808df9c..cf94dbb99090 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -1,21 +1,35 @@ thread 'main' panicked at $DIR/unwind-action-terminate.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: abnormal termination: panic in a function that cannot unwind +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +panic in a function that cannot unwind +stack backtrace: +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `panic_abort` --> $DIR/unwind-action-terminate.rs:LL:CC | LL | / extern "C" fn panic_abort() { -LL | | LL | | panic!() LL | | } - | |_^ panic in a function that cannot unwind - | - = note: inside `panic_abort` at $DIR/unwind-action-terminate.rs:LL:CC + | |_^ note: inside `main` --> $DIR/unwind-action-terminate.rs:LL:CC | LL | panic_abort(); - | ^^^^^^^^^^^^^ + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From ac3bca24b72ff31c6059c537bbc913c60acfaa40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Aug 2023 14:20:41 +0200 Subject: [PATCH 162/169] interpret: have assert_* intrinsics call the panic machinery instead of a direct abort --- .../rustc_const_eval/src/const_eval/error.rs | 4 +--- .../src/const_eval/machine.rs | 11 ++++++---- .../src/interpret/intrinsics.rs | 16 +++++--------- .../rustc_const_eval/src/interpret/machine.rs | 6 ++--- .../rustc_mir_transform/src/const_prop.rs | 4 ++++ .../src/dataflow_const_prop.rs | 7 ++++++ src/tools/miri/src/machine.rs | 5 ++--- src/tools/miri/src/shims/intrinsics/mod.rs | 16 +++++++++++--- src/tools/miri/src/shims/panic.rs | 19 ++++++++++++++++ src/tools/miri/tests/fail/breakpoint.rs | 2 +- src/tools/miri/tests/fail/breakpoint.stderr | 4 ++-- .../intrinsics/uninit_uninhabited_type.rs | 6 ++++- .../intrinsics/uninit_uninhabited_type.stderr | 22 +++++++++++++++---- .../miri/tests/fail/intrinsics/zero_fn_ptr.rs | 7 +++++- .../tests/fail/intrinsics/zero_fn_ptr.stderr | 22 +++++++++++++++---- tests/ui/consts/assert-type-intrinsics.stderr | 6 ++--- 16 files changed, 114 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index d39a7e8a1925..f146b93ff0cc 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -18,7 +18,6 @@ pub enum ConstEvalErrKind { ModifiedGlobal, AssertFailure(AssertKind), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, - Abort(String), } impl MachineStopType for ConstEvalErrKind { @@ -30,7 +29,6 @@ impl MachineStopType for ConstEvalErrKind { ModifiedGlobal => const_eval_modified_global, Panic { .. } => const_eval_panic, AssertFailure(x) => x.diagnostic_message(), - Abort(msg) => msg.to_string().into(), } } fn add_args( @@ -39,7 +37,7 @@ impl MachineStopType for ConstEvalErrKind { ) { use ConstEvalErrKind::*; match *self { - ConstAccessesStatic | ModifiedGlobal | Abort(_) => {} + ConstAccessesStatic | ModifiedGlobal => {} AssertFailure(kind) => kind.add_args(adder), Panic { msg, line, col, file } => { adder("msg".into(), msg.into_diagnostic_arg()); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index b740b79d1624..cf0108640185 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -464,6 +464,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) } + fn panic_nounwind(ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx> { + let msg = Symbol::intern(msg); + let span = ecx.find_closest_untracked_caller_location(); + let (file, line, col) = ecx.location_triple_for_span(span); + return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); + } + fn call_intrinsic( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, @@ -584,10 +591,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::AssertFailure(err).into()) } - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { - Err(ConstEvalErrKind::Abort(msg).into()) - } - fn binary_ptr_op( _ecx: &InterpCx<'mir, 'tcx, Self>, _bin_op: mir::BinOp, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index f22cd919c369..d6ca6fe73a6e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -125,15 +125,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, bool> { let instance_args = instance.args; let intrinsic_name = self.tcx.item_name(instance.def_id()); - - // First handle intrinsics without return place. - let ret = match ret { - None => match intrinsic_name { - sym::abort => M::abort(self, "the program aborted execution".to_owned())?, - // Unsupported diverging intrinsic. - _ => return Ok(false), - }, - Some(p) => p, + let Some(ret) = ret else { + // We don't support any intrinsic without return place. + return Ok(false); }; match intrinsic_name { @@ -410,7 +404,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), }; - M::abort(self, msg)?; + M::panic_nounwind(self, &msg)?; + // Skip the `go_to_block` at the end. + return Ok(true); } } sym::simd_insert => { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 15f2dd17bf57..d3c73b896c08 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -218,10 +218,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { unwind: mir::UnwindAction, ) -> InterpResult<'tcx>; - /// Called to abort evaluation. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { - throw_unsup_format!("aborting execution is not supported") - } + /// Called to trigger a non-unwinding panic. + fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx>; /// Called when unwinding reached a state where execution should be terminated. fn unwind_terminate(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>; diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 7529ed8186bd..a793b384d813 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -180,6 +180,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("calling functions isn't supported in ConstProp") } + fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: &str) -> InterpResult<'tcx> { + throw_machine_stop_str!("panicking isn't supported in ConstProp") + } + fn find_mir_or_eval_fn( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 8f4dc9f69e9a..3a1ef3e7d64a 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -541,6 +541,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm unimplemented!() } + fn panic_nounwind( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _msg: &str, + ) -> interpret::InterpResult<'tcx> { + unimplemented!() + } + fn call_intrinsic( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 069cb20974e7..550c9650fb39 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -971,9 +971,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx.assert_panic(msg, unwind) } - #[inline(always)] - fn abort(_ecx: &mut MiriInterpCx<'mir, 'tcx>, msg: String) -> InterpResult<'tcx, !> { - throw_machine_stop!(TerminationInfo::Abort(msg)) + fn panic_nounwind(ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx> { + ecx.start_panic_nounwind(msg) } fn unwind_terminate(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index b2c297fe542c..ea6ea5a8474e 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -34,10 +34,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if this.emulate_intrinsic(instance, args, dest, ret)? { return Ok(()); } - - // All remaining supported intrinsics have a return place. let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); + + // Handle intrinsics without return place. + match intrinsic_name { + "abort" => { + throw_machine_stop!(TerminationInfo::Abort( + "the program aborted execution".to_owned() + )) + } + _ => {}, + } + + // All remaining supported intrinsics have a return place. let ret = match ret { None => throw_unsup_format!("unimplemented (diverging) intrinsic: `{intrinsic_name}`"), Some(p) => p, @@ -393,7 +403,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "breakpoint" => { let [] = check_arg_count(args)?; // normally this would raise a SIGTRAP, which aborts if no debugger is connected - throw_machine_stop!(TerminationInfo::Abort(format!("Trace/breakpoint trap"))) + throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap"))) } name => throw_unsup_format!("unimplemented intrinsic: `{name}`"), diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 7aefdfcb976a..5c0f828e4e6b 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -188,6 +188,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) } + /// Start a non-unwinding panic in the interpreter with the given message as payload. + fn start_panic_nounwind(&mut self, msg: &str) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // First arg: message. + let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?; + + // Call the lang item. + let panic = this.tcx.lang_items().panic_nounwind().unwrap(); + let panic = ty::Instance::mono(this.tcx.tcx, panic); + this.call_function( + panic, + Abi::Rust, + &[msg.to_ref(this)], + None, + StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable }, + ) + } + fn assert_panic( &mut self, msg: &mir::AssertMessage<'tcx>, diff --git a/src/tools/miri/tests/fail/breakpoint.rs b/src/tools/miri/tests/fail/breakpoint.rs index fb1d4d958ee6..2dd87ea60839 100644 --- a/src/tools/miri/tests/fail/breakpoint.rs +++ b/src/tools/miri/tests/fail/breakpoint.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - core::intrinsics::breakpoint() //~ ERROR: Trace/breakpoint trap + core::intrinsics::breakpoint() //~ ERROR: trace/breakpoint trap }; } diff --git a/src/tools/miri/tests/fail/breakpoint.stderr b/src/tools/miri/tests/fail/breakpoint.stderr index 7b9bbdb38289..8b99c1493b53 100644 --- a/src/tools/miri/tests/fail/breakpoint.stderr +++ b/src/tools/miri/tests/fail/breakpoint.stderr @@ -1,8 +1,8 @@ -error: abnormal termination: Trace/breakpoint trap +error: abnormal termination: trace/breakpoint trap --> $DIR/breakpoint.rs:LL:CC | LL | core::intrinsics::breakpoint() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Trace/breakpoint trap + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trace/breakpoint trap | = note: inside `main` at $DIR/breakpoint.rs:LL:CC diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs index 59781f023661..b8fa32c986f1 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs @@ -1,7 +1,11 @@ +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" +//@error-in-other-file: aborted execution #![feature(never_type)] #[allow(deprecated, invalid_value)] fn main() { let _ = unsafe { std::mem::uninitialized::() }; - //~^ ERROR: attempted to instantiate uninhabited type `!` } diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index f2cc34303262..70e10e8dc48f 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -1,10 +1,24 @@ -error: abnormal termination: aborted execution: attempted to instantiate uninhabited type `!` +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +aborted execution: attempted to instantiate uninhabited type `!` +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` --> $DIR/uninit_uninhabited_type.rs:LL:CC | LL | let _ = unsafe { std::mem::uninitialized::() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` - | - = note: inside `main` at $DIR/uninit_uninhabited_type.rs:LL:CC + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs index e9c6e464e88c..70ae60593a1d 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs @@ -1,5 +1,10 @@ +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" +//@error-in-other-file: aborted execution + #[allow(deprecated, invalid_value)] fn main() { let _ = unsafe { std::mem::zeroed::() }; - //~^ ERROR: attempted to zero-initialize type `fn()`, which is invalid } diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index 77d582280431..56143b6c2053 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -1,10 +1,24 @@ -error: abnormal termination: aborted execution: attempted to zero-initialize type `fn()`, which is invalid +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +aborted execution: attempted to zero-initialize type `fn()`, which is invalid +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` --> $DIR/zero_fn_ptr.rs:LL:CC | LL | let _ = unsafe { std::mem::zeroed::() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `fn()`, which is invalid - | - = note: inside `main` at $DIR/zero_fn_ptr.rs:LL:CC + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/ui/consts/assert-type-intrinsics.stderr b/tests/ui/consts/assert-type-intrinsics.stderr index 70aec91e2262..3c03b03deee3 100644 --- a/tests/ui/consts/assert-type-intrinsics.stderr +++ b/tests/ui/consts/assert-type-intrinsics.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed --> $DIR/assert-type-intrinsics.rs:12:9 | LL | MaybeUninit::::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to instantiate uninhabited type `!`', $DIR/assert-type-intrinsics.rs:12:36 error[E0080]: evaluation of constant value failed --> $DIR/assert-type-intrinsics.rs:16:9 | LL | intrinsics::assert_mem_uninitialized_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `&i32` uninitialized, which is invalid + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to leave type `&i32` uninitialized, which is invalid', $DIR/assert-type-intrinsics.rs:16:9 error[E0080]: evaluation of constant value failed --> $DIR/assert-type-intrinsics.rs:20:9 | LL | intrinsics::assert_zero_valid::<&'static i32>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'aborted execution: attempted to zero-initialize type `&i32`, which is invalid', $DIR/assert-type-intrinsics.rs:20:9 error: aborting due to 3 previous errors From 807e5b8022923ce4c569c65bf79796cfa3939d6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Aug 2023 08:43:32 +0200 Subject: [PATCH 163/169] avoid return in tail position Co-authored-by: fee1-dead --- compiler/rustc_const_eval/src/const_eval/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index cf0108640185..f16aea6f34b7 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -468,7 +468,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, let msg = Symbol::intern(msg); let span = ecx.find_closest_untracked_caller_location(); let (file, line, col) = ecx.location_triple_for_span(span); - return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); + Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()) } fn call_intrinsic( From 49b5701df616523a6737b5a6541b05b1236e8e50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Aug 2023 10:16:25 +0200 Subject: [PATCH 164/169] sync printing of MIR terminators with their new names (and dedup some to-str logic) --- compiler/rustc_middle/src/mir/spanview.rs | 45 ++--------------------- compiler/rustc_middle/src/mir/syntax.rs | 26 ++++++++++++- 2 files changed, 27 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 30e37e7dabb1..a5358687c14c 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -238,45 +238,6 @@ pub fn source_range_no_file(tcx: TyCtxt<'_>, span: Span) -> String { format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) } -pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { - use StatementKind::*; - match statement.kind { - Assign(..) => "Assign", - FakeRead(..) => "FakeRead", - SetDiscriminant { .. } => "SetDiscriminant", - Deinit(..) => "Deinit", - StorageLive(..) => "StorageLive", - StorageDead(..) => "StorageDead", - Retag(..) => "Retag", - PlaceMention(..) => "PlaceMention", - AscribeUserType(..) => "AscribeUserType", - Coverage(..) => "Coverage", - Intrinsic(..) => "Intrinsic", - ConstEvalCounter => "ConstEvalCounter", - Nop => "Nop", - } -} - -pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { - use TerminatorKind::*; - match term.kind { - Goto { .. } => "Goto", - SwitchInt { .. } => "SwitchInt", - UnwindResume => "Resume", - UnwindTerminate => "Terminate", - Return => "Return", - Unreachable => "Unreachable", - Drop { .. } => "Drop", - Call { .. } => "Call", - Assert { .. } => "Assert", - Yield { .. } => "Yield", - GeneratorDrop => "GeneratorDrop", - FalseEdge { .. } => "FalseEdge", - FalseUnwind { .. } => "FalseUnwind", - InlineAsm { .. } => "InlineAsm", - } -} - fn statement_span_viewable<'tcx>( tcx: TyCtxt<'tcx>, body_span: Span, @@ -304,7 +265,7 @@ fn terminator_span_viewable<'tcx>( if !body_span.contains(span) { return None; } - let id = format!("{}:{}", bb.index(), terminator_kind_name(term)); + let id = format!("{}:{}", bb.index(), term.kind.name()); let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); Some(SpanViewable { bb, span, id, tooltip }) } @@ -631,7 +592,7 @@ fn tooltip<'tcx>( "\n{}{}: {}: {:?}", TOOLTIP_INDENT, source_range, - statement_kind_name(&statement), + statement.kind.name(), statement )); } @@ -641,7 +602,7 @@ fn tooltip<'tcx>( "\n{}{}: {}: {:?}", TOOLTIP_INDENT, source_range, - terminator_kind_name(term), + term.kind.name(), term.kind )); } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index a37aa8590763..e91e822f915a 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -380,6 +380,28 @@ pub enum StatementKind<'tcx> { Nop, } +impl StatementKind<'_> { + /// Returns a simple string representation of a `StatementKind` variant, independent of any + /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`). + pub const fn name(&self) -> &'static str { + match self { + StatementKind::Assign(..) => "Assign", + StatementKind::FakeRead(..) => "FakeRead", + StatementKind::SetDiscriminant { .. } => "SetDiscriminant", + StatementKind::Deinit(..) => "Deinit", + StatementKind::StorageLive(..) => "StorageLive", + StatementKind::StorageDead(..) => "StorageDead", + StatementKind::Retag(..) => "Retag", + StatementKind::PlaceMention(..) => "PlaceMention", + StatementKind::AscribeUserType(..) => "AscribeUserType", + StatementKind::Coverage(..) => "Coverage", + StatementKind::Intrinsic(..) => "Intrinsic", + StatementKind::ConstEvalCounter => "ConstEvalCounter", + StatementKind::Nop => "Nop", + } + } +} + #[derive( Clone, TyEncodable, @@ -790,8 +812,8 @@ impl TerminatorKind<'_> { match self { TerminatorKind::Goto { .. } => "Goto", TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::UnwindResume => "Resume", - TerminatorKind::UnwindTerminate => "Terminate", + TerminatorKind::UnwindResume => "UnwindResume", + TerminatorKind::UnwindTerminate => "UnwindTerminate", TerminatorKind::Return => "Return", TerminatorKind::Unreachable => "Unreachable", TerminatorKind::Drop { .. } => "Drop", From 83283a437e84cf3c22cf20a9d262bc039a91b78c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Aug 2023 15:55:33 +0200 Subject: [PATCH 165/169] update anyhow --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47d6b3c44a8d..266f34e69edb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" dependencies = [ "backtrace", ] From 889b55bb254118764b4f3a80de07f7936518971f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 20 Aug 2023 08:34:41 -0700 Subject: [PATCH 166/169] Remove apple-alt dist build. --- .github/workflows/ci.yml | 11 ----------- src/ci/github-actions/ci.yml | 12 ------------ 2 files changed, 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b55ab229811b..3680136d89ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -323,17 +323,6 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 os: macos-13 - - name: dist-x86_64-apple-alt - env: - SCRIPT: "./x.py dist bootstrap --include-default-paths" - RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - SELECT_XCODE: /Applications/Xcode_13.4.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - os: macos-13 - name: x86_64-apple-1 env: SCRIPT: "./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps" diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 2cc0bfd9db96..89b82d59d317 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -504,18 +504,6 @@ jobs: NO_OVERFLOW_CHECKS: 1 <<: *job-macos-xl - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist bootstrap --include-default-paths - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - SELECT_XCODE: /Applications/Xcode_13.4.1.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 - <<: *job-macos-xl - - name: x86_64-apple-1 env: &env-x86_64-apple-tests SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps From 0277351fdd8d15bfb768008bfc9ce6e10170ddce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Aug 2023 18:31:22 +0200 Subject: [PATCH 167/169] fix RA build --- src/tools/rust-analyzer/crates/hir-ty/src/mir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 76a535e3067c..9be083d01177 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -368,7 +368,7 @@ pub enum TerminatorKind { /// /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after /// deaggregation runs. - Resume, + UnwindResume, /// Indicates that the landing pad is finished and that the process should abort. /// From af57ba27dd7a6dc13430382d4288b6d1c32c47cc Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 20 Aug 2023 14:02:00 -0400 Subject: [PATCH 168/169] Bump version to 1.74.0 --- src/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version b/src/version index 5e3a42566267..dc87e8af82f6 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.73.0 +1.74.0 From f8a2f31ae48fbcf8b71684851b3652007a7094d7 Mon Sep 17 00:00:00 2001 From: ShE3py <52315535+she3py@users.noreply.github.com> Date: Sun, 20 Aug 2023 21:50:45 +0200 Subject: [PATCH 169/169] Add data race test to `std::env::{get, set}` --- library/std/tests/env.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index 96b4f372b8b1..a1ca85c2145f 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -5,6 +5,7 @@ use rand::distributions::{Alphanumeric, DistString}; mod common; use common::test_rng; +use std::thread; #[track_caller] fn make_rand_name() -> OsString { @@ -140,3 +141,22 @@ fn env_home_dir() { } } } + +#[test] // miri shouldn't detect any data race in this fn +#[cfg_attr(any(not(miri), target_os = "emscripten"), ignore)] +fn test_env_get_set_multithreaded() { + let getter = thread::spawn(|| { + for _ in 0..100 { + let _ = var_os("foo"); + } + }); + + let setter = thread::spawn(|| { + for _ in 0..100 { + set_var("foo", "bar"); + } + }); + + let _ = getter.join(); + let _ = setter.join(); +}