From 8366c7fe9c2db004224648239644f0fbecc185ea Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 18 Jul 2024 11:54:04 -0300 Subject: [PATCH 01/41] Stabilize unsafe extern blocks (RFC 3484) --- .../rustc_ast_passes/src/ast_validation.rs | 42 ++++++------------- compiler/rustc_ast_passes/src/feature_gate.rs | 4 -- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 2 - compiler/rustc_lint_defs/src/builtin.rs | 1 - compiler/rustc_parse/src/parser/mod.rs | 3 -- tests/rustdoc/unsafe-extern-blocks.rs | 3 +- .../feature-gate-unsafe-extern-blocks.rs | 13 ------ .../feature-gate-unsafe-extern-blocks.stderr | 23 ---------- .../lint/unsafe_code/unsafe-extern-blocks.rs | 1 - .../unsafe_code/unsafe-extern-blocks.stderr | 4 +- tests/ui/parser/unsafe-foreign-mod-2.rs | 2 - tests/ui/parser/unsafe-foreign-mod-2.stderr | 18 +------- tests/ui/parser/unsafe-foreign-mod.rs | 6 +-- tests/ui/parser/unsafe-foreign-mod.stderr | 12 ------ tests/ui/rust-2024/safe-outside-extern.rs | 8 ---- tests/ui/rust-2024/safe-outside-extern.stderr | 38 +++++++++++++++++ .../extern-items-unsafe.edition2021.stderr | 4 +- .../extern-items-unsafe.edition2024.stderr | 4 +- .../extern-items-unsafe.rs | 2 - .../extern-items.edition2024.stderr | 2 +- .../unsafe-extern-blocks/extern-items.rs | 2 - .../unsafe-extern-blocks/safe-impl-trait.rs | 3 -- ...it.gated.stderr => safe-impl-trait.stderr} | 2 +- .../unsafe-extern-blocks/safe-items.rs | 2 - .../unsafe-extern-blocks/safe-trait.rs | 3 -- .../unsafe-extern-blocks/safe-trait.stderr | 8 ++++ ...-unadorned-extern-block.edition2021.stderr | 4 +- ...-unadorned-extern-block.edition2024.stderr | 6 +-- .../safe-unsafe-on-unadorned-extern-block.rs | 2 - .../unsafe-extern-suggestion.fixed | 1 - .../unsafe-extern-suggestion.rs | 1 - .../unsafe-extern-suggestion.stderr | 4 +- .../unsafe-items.edition2021.stderr | 4 +- .../unsafe-items.edition2024.stderr | 4 +- .../unsafe-extern-blocks/unsafe-items.rs | 2 - .../unsafe-on-extern-block-issue-126756.fixed | 1 - .../unsafe-on-extern-block-issue-126756.rs | 1 - ...unsafe-on-extern-block-issue-126756.stderr | 2 +- tests/ui/unpretty/expanded-exhaustive.rs | 1 - tests/ui/unpretty/expanded-exhaustive.stdout | 1 - 41 files changed, 85 insertions(+), 163 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs delete mode 100644 tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr delete mode 100644 tests/ui/parser/unsafe-foreign-mod.stderr create mode 100644 tests/ui/rust-2024/safe-outside-extern.stderr rename tests/ui/rust-2024/unsafe-extern-blocks/{safe-impl-trait.gated.stderr => safe-impl-trait.stderr} (83%) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 34aac6e447304..af1d9beb527bd 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -452,11 +452,6 @@ impl<'a> AstValidator<'a> { item_span: span, block: Some(self.current_extern_span().shrink_to_lo()), }); - } else if !self.features.unsafe_extern_blocks { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span: span, - block: None, - }); } } } @@ -1053,32 +1048,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> { errors::VisibilityNotPermittedNote::IndividualForeignItems, ); - if this.features.unsafe_extern_blocks { - if &Safety::Default == safety { - if item.span.at_least_rust_2024() { - this.dcx() - .emit_err(errors::MissingUnsafeOnExtern { span: item.span }); - } else { - this.lint_buffer.buffer_lint( - MISSING_UNSAFE_ON_EXTERN, - item.id, - item.span, - BuiltinLintDiag::MissingUnsafeOnExtern { - suggestion: item.span.shrink_to_lo(), - }, - ); - } + if &Safety::Default == safety { + if item.span.at_least_rust_2024() { + this.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span }); + } else { + this.lint_buffer.buffer_lint( + MISSING_UNSAFE_ON_EXTERN, + item.id, + item.span, + BuiltinLintDiag::MissingUnsafeOnExtern { + suggestion: item.span.shrink_to_lo(), + }, + ); } - } else if let &Safety::Unsafe(span) = safety { - let mut diag = this - .dcx() - .create_err(errors::UnsafeItem { span, kind: "extern block" }); - rustc_session::parse::add_feature_diagnostics( - &mut diag, - self.session, - sym::unsafe_extern_blocks, - ); - diag.emit(); } if abi.is_none() { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e91dfb2776662..f9119c06fcf7c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -561,10 +561,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental"); - gate_all!( - unsafe_extern_blocks, - "`unsafe extern {}` blocks and `safe` keyword are experimental" - ); gate_all!(return_type_notation, "return type notation is experimental"); if !visitor.features.never_patterns { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index e671c7682391e..d5874f79a22c0 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -387,6 +387,8 @@ declare_features! ( (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208)), /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block. (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668)), + /// Allows unsafe on extern declarations and safety qualifiers over internal items. + (accepted, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)), /// Allows importing and reexporting macros with `use`, /// enables macro modularization in general. (accepted, use_extern_macros, "1.30.0", Some(35896)), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 741c621db081a..e1433a66556b1 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -628,8 +628,6 @@ declare_features! ( (incomplete, unnamed_fields, "1.74.0", Some(49804)), /// Allows unsafe attributes. (unstable, unsafe_attributes, "1.80.0", Some(123757)), - /// Allows unsafe on extern declarations and safety qualifiers over internal items. - (unstable, unsafe_extern_blocks, "1.80.0", Some(123743)), /// Allows const generic parameters to be defined with types that /// are not `Sized`, e.g. `fn foo() {`. (incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)), diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 04764b71b1002..4e1fbe8ae9d66 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4865,7 +4865,6 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(unsafe_extern_blocks)] /// #![warn(missing_unsafe_on_extern)] /// #![allow(dead_code)] /// diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7326b9ec51f2b..b46653717a4f1 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1205,9 +1205,6 @@ impl<'a> Parser<'a> { if self.eat_keyword_case(kw::Unsafe, case) { Safety::Unsafe(self.prev_token.uninterpolated_span()) } else if self.eat_keyword_case(kw::Safe, case) { - self.psess - .gated_spans - .gate(sym::unsafe_extern_blocks, self.prev_token.uninterpolated_span()); Safety::Safe(self.prev_token.uninterpolated_span()) } else { Safety::Default diff --git a/tests/rustdoc/unsafe-extern-blocks.rs b/tests/rustdoc/unsafe-extern-blocks.rs index 22d3beea6c3a9..829095f300f20 100644 --- a/tests/rustdoc/unsafe-extern-blocks.rs +++ b/tests/rustdoc/unsafe-extern-blocks.rs @@ -1,6 +1,5 @@ // Test to ensure the feature is working as expected. -#![feature(unsafe_extern_blocks)] #![crate_name = "foo"] // @has 'foo/index.html' @@ -13,7 +12,7 @@ // @count - '//ul[@class="item-table"]//sup[@title="unsafe function"]' 1 // @has - '//ul[@class="item-table"]//sup[@title="unsafe function"]' '⚠' -unsafe extern { +unsafe extern "C" { // @has 'foo/static.FOO.html' // @has - '//pre[@class="rust item-decl"]' 'pub static FOO: i32' pub safe static FOO: i32; diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs deleted file mode 100644 index 3ea62e875b8e3..0000000000000 --- a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs +++ /dev/null @@ -1,13 +0,0 @@ -unsafe extern "C" { - //~^ ERROR extern block cannot be declared unsafe -} - -// We can't gate `unsafe extern` blocks themselves since they were previously -// allowed, but we should gate the `safe` soft keyword. -#[cfg(any())] -unsafe extern "C" { - safe fn foo(); - //~^ ERROR `unsafe extern {}` blocks and `safe` keyword are experimental -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr deleted file mode 100644 index 5653494630899..0000000000000 --- a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: extern block cannot be declared unsafe - --> $DIR/feature-gate-unsafe-extern-blocks.rs:1:1 - | -LL | unsafe extern "C" { - | ^^^^^^ - | - = note: see issue #123743 for more information - = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental - --> $DIR/feature-gate-unsafe-extern-blocks.rs:9:5 - | -LL | safe fn foo(); - | ^^^^ - | - = note: see issue #123743 for more information - = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs index 6f2ead70db80c..c264fa1c8daf1 100644 --- a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs +++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs @@ -1,4 +1,3 @@ -#![feature(unsafe_extern_blocks)] #![deny(unsafe_code)] #[allow(unsafe_code)] diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr index 5439a3112560e..6d3b064da344f 100644 --- a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr +++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr @@ -1,5 +1,5 @@ error: usage of an `unsafe extern` block - --> $DIR/unsafe-extern-blocks.rs:9:1 + --> $DIR/unsafe-extern-blocks.rs:8:1 | LL | / unsafe extern "C" { LL | | @@ -8,7 +8,7 @@ LL | | } | |_^ | note: the lint level is defined here - --> $DIR/unsafe-extern-blocks.rs:2:9 + --> $DIR/unsafe-extern-blocks.rs:1:9 | LL | #![deny(unsafe_code)] | ^^^^^^^^^^^ diff --git a/tests/ui/parser/unsafe-foreign-mod-2.rs b/tests/ui/parser/unsafe-foreign-mod-2.rs index 0b63a993c5b9e..6d339cd90881f 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.rs +++ b/tests/ui/parser/unsafe-foreign-mod-2.rs @@ -1,8 +1,6 @@ extern "C" unsafe { //~^ ERROR expected `{`, found keyword `unsafe` - //~| ERROR extern block cannot be declared unsafe unsafe fn foo(); - //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers } fn main() {} diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index 8bd592b5d4311..0625e3362ed72 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -4,21 +4,5 @@ error: expected `{`, found keyword `unsafe` LL | extern "C" unsafe { | ^^^^^^ expected `{` -error: extern block cannot be declared unsafe - --> $DIR/unsafe-foreign-mod-2.rs:1:12 - | -LL | extern "C" unsafe { - | ^^^^^^ - | - = note: see issue #123743 for more information - = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/unsafe-foreign-mod-2.rs:4:5 - | -LL | unsafe fn foo(); - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/parser/unsafe-foreign-mod.rs b/tests/ui/parser/unsafe-foreign-mod.rs index eab134a4a4de4..623c3bb81e458 100644 --- a/tests/ui/parser/unsafe-foreign-mod.rs +++ b/tests/ui/parser/unsafe-foreign-mod.rs @@ -1,5 +1,5 @@ -unsafe extern "C" { - //~^ ERROR extern block cannot be declared unsafe -} +//@ check-pass + +unsafe extern "C" {} fn main() {} diff --git a/tests/ui/parser/unsafe-foreign-mod.stderr b/tests/ui/parser/unsafe-foreign-mod.stderr deleted file mode 100644 index 60b918a89b34d..0000000000000 --- a/tests/ui/parser/unsafe-foreign-mod.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: extern block cannot be declared unsafe - --> $DIR/unsafe-foreign-mod.rs:1:1 - | -LL | unsafe extern "C" { - | ^^^^^^ - | - = note: see issue #123743 for more information - = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - diff --git a/tests/ui/rust-2024/safe-outside-extern.rs b/tests/ui/rust-2024/safe-outside-extern.rs index 6773df5ef03b7..674b78dc571ea 100644 --- a/tests/ui/rust-2024/safe-outside-extern.rs +++ b/tests/ui/rust-2024/safe-outside-extern.rs @@ -1,29 +1,21 @@ -//@ revisions: gated ungated -#![cfg_attr(gated, feature(unsafe_extern_blocks))] - safe fn foo() {} //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier -//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] safe static FOO: i32 = 1; //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier -//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] trait Foo { safe fn foo(); //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier - //[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] } impl Foo for () { safe fn foo() {} //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier - //[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] } type FnPtr = safe fn(i32, i32) -> i32; //~^ ERROR: function pointers cannot be declared with `safe` safety qualifier -//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] unsafe static LOL: u8 = 0; //~^ ERROR: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block diff --git a/tests/ui/rust-2024/safe-outside-extern.stderr b/tests/ui/rust-2024/safe-outside-extern.stderr new file mode 100644 index 0000000000000..19d7c5fde0bdf --- /dev/null +++ b/tests/ui/rust-2024/safe-outside-extern.stderr @@ -0,0 +1,38 @@ +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:1:1 + | +LL | safe fn foo() {} + | ^^^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:4:1 + | +LL | safe static FOO: i32 = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:8:5 + | +LL | safe fn foo(); + | ^^^^^^^^^^^^^^ + +error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:13:5 + | +LL | safe fn foo() {} + | ^^^^^^^^^^^^^^^^ + +error: function pointers cannot be declared with `safe` safety qualifier + --> $DIR/safe-outside-extern.rs:17:14 + | +LL | type FnPtr = safe fn(i32, i32) -> i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + --> $DIR/safe-outside-extern.rs:20:1 + | +LL | unsafe static LOL: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr index 3a99caa719b53..77554da10e60b 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block - --> $DIR/extern-items-unsafe.rs:14:5 + --> $DIR/extern-items-unsafe.rs:12:5 | LL | test1(TEST1); | ^^^^^^^^^^^^ call to unsafe function @@ -7,7 +7,7 @@ LL | test1(TEST1); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/extern-items-unsafe.rs:14:11 + --> $DIR/extern-items-unsafe.rs:12:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr index fcf937b7ac577..33b752782d599 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block - --> $DIR/extern-items-unsafe.rs:14:5 + --> $DIR/extern-items-unsafe.rs:12:5 | LL | test1(TEST1); | ^^^^^^^^^^^^ call to unsafe function @@ -7,7 +7,7 @@ LL | test1(TEST1); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe block - --> $DIR/extern-items-unsafe.rs:14:11 + --> $DIR/extern-items-unsafe.rs:12:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs index ad569a256db90..721e07acca588 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs @@ -3,8 +3,6 @@ //@[edition2024] edition:2024 //@[edition2024] compile-flags: -Zunstable-options -#![feature(unsafe_extern_blocks)] - unsafe extern "C" { static TEST1: i32; fn test1(i: i32); diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr index d456cfc6829e1..8ef7c2caf21ee 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr @@ -1,5 +1,5 @@ error: extern blocks must be unsafe - --> $DIR/extern-items.rs:9:1 + --> $DIR/extern-items.rs:7:1 | LL | / extern "C" { LL | | diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs index 16fa1bbb8a404..08805c3634765 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs @@ -4,8 +4,6 @@ //@[edition2024] edition:2024 //@[edition2024] compile-flags: -Zunstable-options -#![feature(unsafe_extern_blocks)] - extern "C" { //[edition2024]~^ ERROR extern blocks must be unsafe static TEST1: i32; diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs index 57c03e4d896be..67df8c14b39fd 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs @@ -1,6 +1,3 @@ -//@ revisions: gated ungated -#![cfg_attr(gated, feature(unsafe_extern_blocks))] - trait Bar {} safe impl Bar for () { } //~^ ERROR expected one of `!` or `::`, found keyword `impl` diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.stderr similarity index 83% rename from tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr rename to tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.stderr index 80e7a45f57e79..f1021726b1816 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.stderr @@ -1,5 +1,5 @@ error: expected one of `!` or `::`, found keyword `impl` - --> $DIR/safe-impl-trait.rs:5:6 + --> $DIR/safe-impl-trait.rs:2:6 | LL | safe impl Bar for () { } | ^^^^ expected one of `!` or `::` diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs index 74cd5621fce93..b0b8a8b012a6a 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs @@ -4,8 +4,6 @@ //@[edition2024] compile-flags: -Zunstable-options //@ check-pass -#![feature(unsafe_extern_blocks)] - unsafe extern "C" { safe static TEST1: i32; safe fn test1(i: i32); diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs index e73cb45b18877..52773b4cbbbbf 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs @@ -1,6 +1,3 @@ -//@ revisions: gated ungated -#![cfg_attr(gated, feature(unsafe_extern_blocks))] - safe trait Foo {} //~^ ERROR expected one of `!` or `::`, found keyword `trait` diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr new file mode 100644 index 0000000000000..1733336a797b2 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `trait` + --> $DIR/safe-trait.rs:1:6 + | +LL | safe trait Foo {} + | ^^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr index e90613357b1ca..9379798728669 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr @@ -1,5 +1,5 @@ error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5 | LL | safe static TEST1: i32; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | unsafe extern "C" { | ++++++ error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 | LL | safe fn test1(i: i32); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr index 1207ee158cc13..e9db6006c0b58 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr @@ -1,5 +1,5 @@ error: extern blocks must be unsafe - --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:1 + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:6:1 | LL | / extern "C" { LL | | @@ -11,7 +11,7 @@ LL | | } | |_^ error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5 | LL | safe static TEST1: i32; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | unsafe extern "C" { | ++++++ error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 | LL | safe fn test1(i: i32); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs index 11f55cb195f29..4badb50b26735 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs @@ -3,8 +3,6 @@ //@[edition2024] edition:2024 //@[edition2024] compile-flags: -Zunstable-options -#![feature(unsafe_extern_blocks)] - extern "C" { //[edition2024]~^ ERROR extern blocks must be unsafe safe static TEST1: i32; diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed index 10c19759d8aaa..f686809615fb0 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed @@ -1,6 +1,5 @@ //@ run-rustfix -#![feature(unsafe_extern_blocks)] #![deny(missing_unsafe_on_extern)] #![allow(unused)] diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs index b81e52ddc5843..00f1cbdab54ff 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs @@ -1,6 +1,5 @@ //@ run-rustfix -#![feature(unsafe_extern_blocks)] #![deny(missing_unsafe_on_extern)] #![allow(unused)] diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr index 0a3c2cd25e3fe..bb1d068ceb91b 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr @@ -1,5 +1,5 @@ error: extern blocks should be unsafe - --> $DIR/unsafe-extern-suggestion.rs:7:1 + --> $DIR/unsafe-extern-suggestion.rs:6:1 | LL | extern "C" { | ^ @@ -16,7 +16,7 @@ LL | | } = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! = note: for more information, see issue #123743 note: the lint level is defined here - --> $DIR/unsafe-extern-suggestion.rs:4:9 + --> $DIR/unsafe-extern-suggestion.rs:3:9 | LL | #![deny(missing_unsafe_on_extern)] | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr index 8bb7ffefeea9e..e3626bb497e4f 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block - --> $DIR/unsafe-items.rs:20:5 + --> $DIR/unsafe-items.rs:18:5 | LL | test1(TEST1); | ^^^^^^^^^^^^ call to unsafe function @@ -7,7 +7,7 @@ LL | test1(TEST1); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/unsafe-items.rs:20:11 + --> $DIR/unsafe-items.rs:18:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr index 9a30142a632c5..89bc501b7b5a5 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block - --> $DIR/unsafe-items.rs:20:5 + --> $DIR/unsafe-items.rs:18:5 | LL | test1(TEST1); | ^^^^^^^^^^^^ call to unsafe function @@ -7,7 +7,7 @@ LL | test1(TEST1); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe block - --> $DIR/unsafe-items.rs:20:11 + --> $DIR/unsafe-items.rs:18:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs index 9066953abc615..dc2bae892a988 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs @@ -3,8 +3,6 @@ //@[edition2024] edition:2024 //@[edition2024] compile-flags: -Zunstable-options -#![feature(unsafe_extern_blocks)] - unsafe extern "C" { unsafe static TEST1: i32; unsafe fn test1(i: i32); diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed index 2ff595cc44d1e..857d34eef8521 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed @@ -1,6 +1,5 @@ //@ run-rustfix -#![feature(unsafe_extern_blocks)] #![allow(dead_code)] unsafe extern "C" { diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs index 6fe43f7a5b46d..edab9850d796f 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs @@ -1,6 +1,5 @@ //@ run-rustfix -#![feature(unsafe_extern_blocks)] #![allow(dead_code)] extern "C" { diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr index 05d23d001ada7..073245e650b1c 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr @@ -1,5 +1,5 @@ error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/unsafe-on-extern-block-issue-126756.rs:7:5 + --> $DIR/unsafe-on-extern-block-issue-126756.rs:6:5 | LL | unsafe fn foo(); | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 92c2e7b488478..29472df897a1f 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -25,7 +25,6 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unnamed_fields)] -#![feature(unsafe_extern_blocks)] #![feature(yeet_expr)] #![allow(incomplete_features)] diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 137a8aa5510d0..cf2f6f8cbaa99 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -26,7 +26,6 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unnamed_fields)] -#![feature(unsafe_extern_blocks)] #![feature(yeet_expr)] #![allow(incomplete_features)] #[prelude_import] From 571f7b658964e5781546e8ea4a2d1466e8b0a611 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Jul 2024 15:11:14 +0200 Subject: [PATCH 02/41] improve error message when global asm uses inline asm operands --- compiler/rustc_builtin_macros/messages.ftl | 3 ++ compiler/rustc_builtin_macros/src/asm.rs | 39 +++++++++++++++----- compiler/rustc_builtin_macros/src/errors.rs | 9 +++++ tests/ui/asm/parse-error.rs | 15 ++++++-- tests/ui/asm/parse-error.stderr | 40 ++++++++++++++++++--- 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index a30ab236213a0..2d9f6b974d2b8 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -199,6 +199,9 @@ builtin_macros_format_use_positional = consider using a positional formatting ar builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` +builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!` + .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it + builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!` .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly .suggestion = remove this option diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 62e59f1f4d477..7a5cabfce6ad1 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -29,6 +29,29 @@ pub struct AsmArgs { pub options_spans: Vec, } +/// Used for better error messages when operand types are used that are not +/// supported by the current macro (e.g. `in` or `out` for `global_asm!`) +/// +/// returns +/// +/// - `Ok(true)` if the current token matches the keyword, and was expected +/// - `Ok(false)` if the current token does not match the keyword +/// - `Err(_)` if the current token matches the keyword, but was not expected +fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> { + if expect { + Ok(p.eat_keyword(symbol)) + } else { + let span = p.token.span; + if p.eat_keyword_noexpect(symbol) { + // in gets printed as `r#in` otherwise + let symbol = if symbol == kw::In { "in" } else { symbol.as_str() }; + Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol })) + } else { + Ok(false) + } + } +} + fn parse_args<'a>( ecx: &ExtCtxt<'a>, sp: Span, @@ -106,7 +129,7 @@ pub fn parse_asm_args<'a>( }; let mut explicit_reg = false; - let op = if !is_global_asm && p.eat_keyword(kw::In) { + let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -114,15 +137,15 @@ pub fn parse_asm_args<'a>( } let expr = p.parse_expr()?; ast::InlineAsmOperand::In { reg, expr } - } else if !is_global_asm && p.eat_keyword(sym::out) { + } else if eat_operand_keyword(p, sym::out, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: false } - } else if !is_global_asm && p.eat_keyword(sym::lateout) { + } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: true } - } else if !is_global_asm && p.eat_keyword(sym::inout) { + } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -136,7 +159,7 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: false } } - } else if !is_global_asm && p.eat_keyword(sym::inlateout) { + } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -150,6 +173,9 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: true } } + } else if eat_operand_keyword(p, sym::label, !is_global_asm)? { + let block = p.parse_block()?; + ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(kw::Const) { let anon_const = p.parse_expr_anon_const()?; ast::InlineAsmOperand::Const { anon_const } @@ -165,9 +191,6 @@ pub fn parse_asm_args<'a>( path: path.clone(), }; ast::InlineAsmOperand::Sym { sym } - } else if !is_global_asm && p.eat_keyword(sym::label) { - let block = p.parse_block()?; - ast::InlineAsmOperand::Label { block } } else if allow_templates { let template = p.parse_expr()?; // If it can't possibly expand to a string, provide diagnostics here to include other diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index f17819474adcd..1c5d98a08970c 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -856,6 +856,15 @@ pub(crate) struct GlobalAsmUnsupportedOption { pub(crate) full_span: Span, } +#[derive(Diagnostic)] +#[diag(builtin_macros_global_asm_unsupported_operand)] +pub(crate) struct GlobalAsmUnsupportedOperand<'a> { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) symbol: &'a str, +} + #[derive(Diagnostic)] #[diag(builtin_macros_test_runner_invalid)] pub(crate) struct TestRunnerInvalid { diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs index 9dec3a1c394ef..16ae02828642d 100644 --- a/tests/ui/asm/parse-error.rs +++ b/tests/ui/asm/parse-error.rs @@ -146,5 +146,16 @@ global_asm!(format!("{{{}}}", 0), const FOO); //~^ ERROR asm template must be a string literal global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); //~^ ERROR asm template must be a string literal -global_asm!("{}", label {}); -//~^ ERROR expected operand, options, or additional template string + +global_asm!("{}", in(reg)); +//~^ ERROR the `in` operand cannot be used with `global_asm!` +global_asm!("{}", out(reg)); +//~^ ERROR the `out` operand cannot be used with `global_asm!` +global_asm!("{}", lateout(reg)); +//~^ ERROR the `lateout` operand cannot be used with `global_asm!` +global_asm!("{}", inout(reg)); +//~^ ERROR the `inout` operand cannot be used with `global_asm!` +global_asm!("{}", inlateout(reg)); +//~^ ERROR the `inlateout` operand cannot be used with `global_asm!` +global_asm!("{}", label(reg)); +//~^ ERROR the `label` operand cannot be used with `global_asm!` diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index e9ecd712bc367..f5f8d537d86b8 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -380,11 +380,41 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:149:19 +error: the `in` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:150:19 + | +LL | global_asm!("{}", in(reg)); + | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `out` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:152:19 + | +LL | global_asm!("{}", out(reg)); + | ^^^ the `out` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `lateout` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:154:19 + | +LL | global_asm!("{}", lateout(reg)); + | ^^^^^^^ the `lateout` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `inout` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:156:19 + | +LL | global_asm!("{}", inout(reg)); + | ^^^^^ the `inout` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `inlateout` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:158:19 + | +LL | global_asm!("{}", inlateout(reg)); + | ^^^^^^^^^ the `inlateout` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `label` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:160:19 | -LL | global_asm!("{}", label {}); - | ^^^^^^^^ expected operand, options, or additional template string +LL | global_asm!("{}", label(reg)); + | ^^^^^ the `label` operand is not meaningful for global-scoped inline assembly, remove it error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 @@ -441,6 +471,6 @@ help: consider using `const` instead of `let` LL | const bar: /* Type */ = 0; | ~~~~~ ++++++++++++ -error: aborting due to 67 previous errors +error: aborting due to 72 previous errors For more information about this error, try `rustc --explain E0435`. From 9b097b2d44a8f953640ba42122a804485d651ea9 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Wed, 31 Jul 2024 18:58:04 +0300 Subject: [PATCH 03/41] Delegation: second attempt to improve perf --- compiler/rustc_hir/src/hir.rs | 11 +++++++++++ .../src/collect/generics_of.rs | 17 ++++++++++------- .../src/collect/predicates_of.rs | 17 ++++++++++------- compiler/rustc_hir_analysis/src/delegation.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 13 +------------ 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3b9aea087910a..9257be8647162 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2952,6 +2952,17 @@ pub struct FnDecl<'hir> { pub lifetime_elision_allowed: bool, } +impl<'hir> FnDecl<'hir> { + pub fn opt_delegation_sig_id(&self) -> Option { + if let FnRetTy::Return(ty) = self.output + && let TyKind::InferDelegation(sig_id, _) = ty.kind + { + return Some(sig_id); + } + None + } +} + /// Represents what type of implicit self a function has, if any. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum ImplicitSelfKind { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 80a65aa298851..71a6501de8b98 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -54,13 +54,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }; } - // For a delegation item inherit generics from callee. - if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id) - && let Some(generics) = inherit_generics_for_delegation_item(tcx, def_id, sig_id) - { - return generics; - } - let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); @@ -234,6 +227,16 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // inherit the generics of the item. Some(parent.to_def_id()) } + ItemKind::Fn(sig, _, _) => { + // For a delegation item inherit generics from callee. + if let Some(sig_id) = sig.decl.opt_delegation_sig_id() + && let Some(generics) = + inherit_generics_for_delegation_item(tcx, def_id, sig_id) + { + return generics; + } + None + } _ => None, }, _ => None, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index ae52dbd56f9b7..a5a56cb845d79 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -115,13 +115,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen None => {} } - // For a delegation item inherit predicates from callee. - if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id) - && let Some(predicates) = inherit_predicates_for_delegation_item(tcx, def_id, sig_id) - { - return predicates; - } - let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); @@ -151,6 +144,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { is_trait = Some(self_bounds); } + + ItemKind::Fn(sig, _, _) => { + // For a delegation item inherit predicates from callee. + if let Some(sig_id) = sig.decl.opt_delegation_sig_id() + && let Some(predicates) = + inherit_predicates_for_delegation_item(tcx, def_id, sig_id) + { + return predicates; + } + } _ => {} } }; diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index e21ed55bce3fc..ca62ef92b83de 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -242,7 +242,7 @@ pub(crate) fn inherit_sig_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> &'tcx [Ty<'tcx>] { - let sig_id = tcx.hir().delegation_sig_id(def_id); + let sig_id = tcx.hir().opt_delegation_sig_id(def_id).unwrap(); let caller_sig = tcx.fn_sig(sig_id); if let Err(err) = check_constraints(tcx, def_id, sig_id) { let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1705c016437cc..4c243e6330b91 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -747,18 +747,7 @@ impl<'hir> Map<'hir> { } pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option { - if let Some(ret) = self.get_fn_output(def_id) - && let FnRetTy::Return(ty) = ret - && let TyKind::InferDelegation(sig_id, _) = ty.kind - { - return Some(sig_id); - } - None - } - - #[inline] - pub fn delegation_sig_id(self, def_id: LocalDefId) -> DefId { - self.opt_delegation_sig_id(def_id).unwrap() + self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id() } #[inline] From af79a6396c4175fcdacc18d7448bcde94c3f0363 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 2 Aug 2024 05:16:01 +0200 Subject: [PATCH 04/41] time.rs: remove "Basic usage text" Only one example is given (for each method) --- library/core/src/time.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 179fbabaddeb6..0390bb59a8984 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -617,8 +617,6 @@ impl Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -640,8 +638,6 @@ impl Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -700,8 +696,6 @@ impl Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -758,8 +752,6 @@ impl Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -814,8 +806,6 @@ impl Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// From 77ca30f1950a062e9eb1caeff790618488058057 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Aug 2024 21:58:34 -0700 Subject: [PATCH 05/41] Implement `UncheckedIterator` directly for `RepeatN` --- library/core/src/iter/sources/repeat_n.rs | 33 +++++++++++++-------- tests/codegen/iter-repeat-n-trivial-drop.rs | 15 +++++++++- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index 8390dab8e543e..4c4ae39f836ca 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -114,19 +114,12 @@ impl Iterator for RepeatN { #[inline] fn next(&mut self) -> Option { - if self.count == 0 { - return None; - } - - self.count -= 1; - Some(if self.count == 0 { - // SAFETY: the check above ensured that the count used to be non-zero, - // so element hasn't been dropped yet, and we just lowered the count to - // zero so it won't be dropped later, and thus it's okay to take it here. - unsafe { ManuallyDrop::take(&mut self.element) } + if self.count > 0 { + // SAFETY: Just checked it's not empty + unsafe { Some(self.next_unchecked()) } } else { - A::clone(&self.element) - }) + None + } } #[inline] @@ -194,4 +187,18 @@ impl FusedIterator for RepeatN {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for RepeatN {} #[unstable(feature = "trusted_len_next_unchecked", issue = "37572")] -impl UncheckedIterator for RepeatN {} +impl UncheckedIterator for RepeatN { + #[inline] + unsafe fn next_unchecked(&mut self) -> Self::Item { + // SAFETY: The caller promised the iterator isn't empty + self.count = unsafe { self.count.unchecked_sub(1) }; + if self.count == 0 { + // SAFETY: the check above ensured that the count used to be non-zero, + // so element hasn't been dropped yet, and we just lowered the count to + // zero so it won't be dropped later, and thus it's okay to take it here. + unsafe { ManuallyDrop::take(&mut self.element) } + } else { + A::clone(&self.element) + } + } +} diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs index 31020b77984ba..7de224b92d853 100644 --- a/tests/codegen/iter-repeat-n-trivial-drop.rs +++ b/tests/codegen/iter-repeat-n-trivial-drop.rs @@ -1,8 +1,9 @@ -//@ compile-flags: -O +//@ compile-flags: -C opt-level=3 //@ only-x86_64 #![crate_type = "lib"] #![feature(iter_repeat_n)] +#![feature(array_repeat)] #[derive(Clone)] pub struct NotCopy(u16); @@ -54,3 +55,15 @@ pub fn vec_extend_via_iter_repeat_n() -> Vec { v.extend(std::iter::repeat_n(42_u8, n)); v } + +// Array repeat uses `RepeatN::next_unchecked` internally, +// so also check that the distinction disappears there. + +#[no_mangle] +// CHECK-LABEL: @array_repeat_not_copy +pub unsafe fn array_repeat_not_copy(item: NotCopy) -> [NotCopy; 8] { + // CHECK: insertelement {{.+}} i16 %item + // CHECK: shufflevector <8 x i16> {{.+}} zeroinitializer + // CHECK: store <8 x i16> + std::array::repeat(item) +} From 6264d2eba9d5b237a5c5c9a9527fbda54d751203 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 27 Jul 2024 15:15:02 -0400 Subject: [PATCH 06/41] bootstrap: fix bug preventing the use of custom targets the bug was caused by two factors: 1. only checking the RUST_TARGET_PATH form, not the full filepath form 2. indirectly trying to use the Debug presentation to get the file path --- src/bootstrap/src/core/config/config.rs | 5 +++++ src/bootstrap/src/core/sanity.rs | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1343e257efe08..776e2c5cb17d7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -512,6 +512,11 @@ impl TargetSelection { pub fn is_windows(&self) -> bool { self.contains("windows") } + + /// Path to the file defining the custom target, if any. + pub fn filepath(&self) -> Option<&Path> { + self.file.as_ref().map(Path::new) + } } impl fmt::Display for TargetSelection { diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 45f4090ef2285..c42d4c56c3816 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -260,7 +260,9 @@ than building it. if !has_target { // This might also be a custom target, so check the target file that could have been specified by the user. - if let Some(custom_target_path) = env::var_os("RUST_TARGET_PATH") { + if target.filepath().is_some_and(|p| p.exists()) { + has_target = true; + } else if let Some(custom_target_path) = env::var_os("RUST_TARGET_PATH") { let mut target_filename = OsString::from(&target_str); // Target filename ends with `.json`. target_filename.push(".json"); @@ -275,8 +277,12 @@ than building it. if !has_target { panic!( - "No such target exists in the target list, - specify a correct location of the JSON specification file for custom targets!" + "No such target exists in the target list,\n\ + make sure to correctly specify the location \ + of the JSON specification file \ + for custom targets!\n\ + Use BOOTSTRAP_SKIP_TARGET_SANITY=1 to \ + bypass this check." ); } } From 7dd5ad282c4aab165236c8ba9404929d7dd337ac Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Aug 2024 22:54:22 -0700 Subject: [PATCH 07/41] rustdoc: Extract helper function to add item to search index --- src/librustdoc/formats/cache.rs | 272 ++++++++++++++++---------------- 1 file changed, 135 insertions(+), 137 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9f284486616a0..8c0ed6cddf064 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -260,7 +260,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } // Index this method for searching later on. - if let Some(s) = item.name.or_else(|| { + if let Some(name) = item.name.or_else(|| { if item.is_stripped() { None } else if let clean::ImportItem(ref i) = *item.kind @@ -271,142 +271,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { None } }) { - let (parent, is_inherent_impl_item) = match *item.kind { - clean::StrippedItem(..) => ((None, None), false), - clean::AssocConstItem(..) | clean::AssocTypeItem(..) - if self - .cache - .parent_stack - .last() - .is_some_and(|parent| parent.is_trait_impl()) => - { - // skip associated items in trait impls - ((None, None), false) - } - clean::TyMethodItem(..) - | clean::TyAssocConstItem(..) - | clean::TyAssocTypeItem(..) - | clean::StructFieldItem(..) - | clean::VariantItem(..) => ( - ( - Some( - self.cache - .parent_stack - .last() - .expect("parent_stack is empty") - .item_id() - .expect_def_id(), - ), - Some(&self.cache.stack[..self.cache.stack.len() - 1]), - ), - false, - ), - clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { - if self.cache.parent_stack.is_empty() { - ((None, None), false) - } else { - let last = self.cache.parent_stack.last().expect("parent_stack is empty 2"); - let did = match &*last { - ParentStackItem::Impl { - // impl Trait for &T { fn method(self); } - // - // When generating a function index with the above shape, we want it - // associated with `T`, not with the primitive reference type. It should - // show up as `T::method`, rather than `reference::method`, in the search - // results page. - for_: clean::Type::BorrowedRef { type_, .. }, - .. - } => type_.def_id(&self.cache), - ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache), - ParentStackItem::Type(item_id) => item_id.as_def_id(), - }; - let path = did - .and_then(|did| self.cache.paths.get(&did)) - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. - .map(|(fqp, _)| &fqp[..fqp.len() - 1]); - ((did, path), true) - } - } - _ => ((None, Some(&*self.cache.stack)), false), - }; - - match parent { - (parent, Some(path)) if is_inherent_impl_item || !self.cache.stripped_mod => { - debug_assert!(!item.is_stripped()); - - // A crate has a module at its root, containing all items, - // which should not be indexed. The crate-item itself is - // inserted later on when serializing the search-index. - if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) - && let ty = item.type_() - && (ty != ItemType::StructField - || u16::from_str_radix(s.as_str(), 10).is_err()) - { - let desc = - short_markdown_summary(&item.doc_value(), &item.link_names(self.cache)); - // For searching purposes, a re-export is a duplicate if: - // - // - It's either an inline, or a true re-export - // - It's got the same name - // - Both of them have the same exact path - let defid = (match &*item.kind { - &clean::ItemKind::ImportItem(ref import) => import.source.did, - _ => None, - }) - .or_else(|| item.item_id.as_def_id()); - // In case this is a field from a tuple struct, we don't add it into - // the search index because its name is something like "0", which is - // not useful for rustdoc search. - self.cache.search_index.push(IndexItem { - ty, - defid, - name: s, - path: join_with_double_colon(path), - desc, - parent, - parent_idx: None, - exact_path: None, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - self.cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - search_type: get_function_type_for_search( - &item, - self.tcx, - clean_impl_generics(self.cache.parent_stack.last()).as_ref(), - parent, - self.cache, - ), - aliases: item.attrs.get_doc_aliases(), - deprecation: item.deprecation(self.tcx), - }); - } - } - (Some(parent), None) if is_inherent_impl_item => { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - let impl_generics = clean_impl_generics(self.cache.parent_stack.last()); - self.cache.orphan_impl_items.push(OrphanImplItem { - parent, - item: item.clone(), - impl_generics, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - self.cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - }); - } - _ => {} - } + add_item_to_search_index(self.tcx, &mut self.cache, &item, name) } // Keep track of the fully qualified path for this item. @@ -573,6 +438,139 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } } +fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { + let (parent, is_inherent_impl_item) = match *item.kind { + clean::StrippedItem(..) => ((None, None), false), + clean::AssocConstItem(..) | clean::AssocTypeItem(..) + if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => + { + // skip associated items in trait impls + ((None, None), false) + } + clean::TyMethodItem(..) + | clean::TyAssocConstItem(..) + | clean::TyAssocTypeItem(..) + | clean::StructFieldItem(..) + | clean::VariantItem(..) => ( + ( + Some( + cache + .parent_stack + .last() + .expect("parent_stack is empty") + .item_id() + .expect_def_id(), + ), + Some(&cache.stack[..cache.stack.len() - 1]), + ), + false, + ), + clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { + if cache.parent_stack.is_empty() { + ((None, None), false) + } else { + let last = cache.parent_stack.last().expect("parent_stack is empty 2"); + let did = match &*last { + ParentStackItem::Impl { + // impl Trait for &T { fn method(self); } + // + // When generating a function index with the above shape, we want it + // associated with `T`, not with the primitive reference type. It should + // show up as `T::method`, rather than `reference::method`, in the search + // results page. + for_: clean::Type::BorrowedRef { type_, .. }, + .. + } => type_.def_id(&cache), + ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), + ParentStackItem::Type(item_id) => item_id.as_def_id(), + }; + let path = did + .and_then(|did| cache.paths.get(&did)) + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + .map(|(fqp, _)| &fqp[..fqp.len() - 1]); + ((did, path), true) + } + } + _ => ((None, Some(&*cache.stack)), false), + }; + + match parent { + (parent, Some(path)) if is_inherent_impl_item || !cache.stripped_mod => { + debug_assert!(!item.is_stripped()); + + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. + if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) + && let ty = item.type_() + && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) + { + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + // For searching purposes, a re-export is a duplicate if: + // + // - It's either an inline, or a true re-export + // - It's got the same name + // - Both of them have the same exact path + let defid = (match &*item.kind { + &clean::ItemKind::ImportItem(ref import) => import.source.did, + _ => None, + }) + .or_else(|| item.item_id.as_def_id()); + // In case this is a field from a tuple struct, we don't add it into + // the search index because its name is something like "0", which is + // not useful for rustdoc search. + cache.search_index.push(IndexItem { + ty, + defid, + name, + path: join_with_double_colon(path), + desc, + parent, + parent_idx: None, + exact_path: None, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = + cache.parent_stack.last() + { + item_id.as_def_id() + } else { + None + }, + search_type: get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent, + cache, + ), + aliases: item.attrs.get_doc_aliases(), + deprecation: item.deprecation(tcx), + }); + } + } + (Some(parent), None) if is_inherent_impl_item => { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + let impl_generics = clean_impl_generics(cache.parent_stack.last()); + cache.orphan_impl_items.push(OrphanImplItem { + parent, + item: item.clone(), + impl_generics, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = + cache.parent_stack.last() + { + item_id.as_def_id() + } else { + None + }, + }); + } + _ => {} + } +} + pub(crate) struct OrphanImplItem { pub(crate) parent: DefId, pub(crate) impl_id: Option, From 2721e97c5d9a4e5a001461e499a751e81e10df4c Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Aug 2024 23:20:20 -0700 Subject: [PATCH 08/41] rustdoc: Clarify construction of name for search index --- src/librustdoc/formats/cache.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8c0ed6cddf064..13b91f483ebf6 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -260,17 +260,20 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } // Index this method for searching later on. - if let Some(name) = item.name.or_else(|| { - if item.is_stripped() { - None - } else if let clean::ImportItem(ref i) = *item.kind - && let clean::ImportKind::Simple(s) = i.kind - { - Some(s) - } else { - None - } - }) { + let search_name = if !item.is_stripped() { + item.name.or_else(|| { + if let clean::ImportItem(ref i) = *item.kind + && let clean::ImportKind::Simple(s) = i.kind + { + Some(s) + } else { + None + } + }) + } else { + None + }; + if let Some(name) = search_name { add_item_to_search_index(self.tcx, &mut self.cache, &item, name) } From 4e2084769b8e6de0dd43453315b7466305e9d312 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Aug 2024 23:33:42 -0700 Subject: [PATCH 09/41] rustdoc: Simplify some search index code --- src/librustdoc/clean/types.rs | 20 +++++------ src/librustdoc/formats/cache.rs | 60 +++++++++++++++------------------ 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1ec5f38b6ec0f..cf01ffb2e7586 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1680,13 +1680,16 @@ impl Type { } } - fn inner_def_id(&self, cache: Option<&Cache>) -> Option { + /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s. + /// + /// [clean]: crate::clean + pub(crate) fn def_id(&self, cache: &Cache) -> Option { let t: PrimitiveType = match *self { Type::Path { ref path } => return Some(path.def_id()), DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()), - Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()), + Primitive(p) => return cache.primitive_locations.get(&p).cloned(), BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference, - BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache), + BorrowedRef { ref type_, .. } => return type_.def_id(cache), Tuple(ref tys) => { if tys.is_empty() { PrimitiveType::Unit @@ -1699,17 +1702,10 @@ impl Type { Array(..) => PrimitiveType::Array, Type::Pat(..) => PrimitiveType::Pat, RawPointer(..) => PrimitiveType::RawPointer, - QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache), + QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache), Generic(_) | Infer | ImplTrait(_) => return None, }; - cache.and_then(|c| Primitive(t).def_id(c)) - } - - /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s. - /// - /// [clean]: crate::clean - pub(crate) fn def_id(&self, cache: &Cache) -> Option { - self.inner_def_id(Some(cache)) + Primitive(t).def_id(cache) } } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 13b91f483ebf6..0788543d89af7 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -442,13 +442,13 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { - let (parent, is_inherent_impl_item) = match *item.kind { - clean::StrippedItem(..) => ((None, None), false), + let (parent, is_impl_child) = match *item.kind { + clean::StrippedItem(..) => return, clean::AssocConstItem(..) | clean::AssocTypeItem(..) if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => { // skip associated items in trait impls - ((None, None), false) + return; } clean::TyMethodItem(..) | clean::TyAssocConstItem(..) @@ -469,39 +469,35 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It false, ), clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { - if cache.parent_stack.is_empty() { - ((None, None), false) - } else { - let last = cache.parent_stack.last().expect("parent_stack is empty 2"); - let did = match &*last { - ParentStackItem::Impl { - // impl Trait for &T { fn method(self); } - // - // When generating a function index with the above shape, we want it - // associated with `T`, not with the primitive reference type. It should - // show up as `T::method`, rather than `reference::method`, in the search - // results page. - for_: clean::Type::BorrowedRef { type_, .. }, - .. - } => type_.def_id(&cache), - ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), - ParentStackItem::Type(item_id) => item_id.as_def_id(), - }; - let path = did - .and_then(|did| cache.paths.get(&did)) - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. - .map(|(fqp, _)| &fqp[..fqp.len() - 1]); - ((did, path), true) - } + let last = cache.parent_stack.last().expect("parent_stack is empty 2"); + let did = match &*last { + ParentStackItem::Impl { + // impl Trait for &T { fn method(self); } + // + // When generating a function index with the above shape, we want it + // associated with `T`, not with the primitive reference type. It should + // show up as `T::method`, rather than `reference::method`, in the search + // results page. + for_: clean::Type::BorrowedRef { type_, .. }, + .. + } => type_.def_id(&cache), + ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), + ParentStackItem::Type(item_id) => item_id.as_def_id(), + }; + let path = did + .and_then(|did| cache.paths.get(&did)) + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + .map(|(fqp, _)| &fqp[..fqp.len() - 1]); + ((did, path), true) } _ => ((None, Some(&*cache.stack)), false), }; match parent { - (parent, Some(path)) if is_inherent_impl_item || !cache.stripped_mod => { + (parent, Some(path)) if is_impl_child || !cache.stripped_mod => { debug_assert!(!item.is_stripped()); // A crate has a module at its root, containing all items, @@ -553,7 +549,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It }); } } - (Some(parent), None) if is_inherent_impl_item => { + (Some(parent), None) if is_impl_child => { // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. let impl_generics = clean_impl_generics(cache.parent_stack.last()); From 015aa8d0fba2247da33967a93fad9a2bea16037f Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Aug 2024 12:58:59 -0700 Subject: [PATCH 10/41] Restructure a confusing `match` --- src/librustdoc/formats/cache.rs | 124 ++++++++++++++++---------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 0788543d89af7..5c18cebb96573 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -442,7 +442,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { - let (parent, is_impl_child) = match *item.kind { + let ((parent_did, parent_path), is_impl_child) = match *item.kind { clean::StrippedItem(..) => return, clean::AssocConstItem(..) | clean::AssocTypeItem(..) if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => @@ -496,67 +496,59 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It _ => ((None, Some(&*cache.stack)), false), }; - match parent { - (parent, Some(path)) if is_impl_child || !cache.stripped_mod => { - debug_assert!(!item.is_stripped()); - - // A crate has a module at its root, containing all items, - // which should not be indexed. The crate-item itself is - // inserted later on when serializing the search-index. - if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) - && let ty = item.type_() - && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) + if let Some(parent_did) = parent_did + && parent_path.is_none() + && is_impl_child + { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + let impl_generics = clean_impl_generics(cache.parent_stack.last()); + cache.orphan_impl_items.push(OrphanImplItem { + parent: parent_did, + item: item.clone(), + impl_generics, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); - // For searching purposes, a re-export is a duplicate if: - // - // - It's either an inline, or a true re-export - // - It's got the same name - // - Both of them have the same exact path - let defid = (match &*item.kind { - &clean::ItemKind::ImportItem(ref import) => import.source.did, - _ => None, - }) - .or_else(|| item.item_id.as_def_id()); - // In case this is a field from a tuple struct, we don't add it into - // the search index because its name is something like "0", which is - // not useful for rustdoc search. - cache.search_index.push(IndexItem { - ty, - defid, - name, - path: join_with_double_colon(path), - desc, - parent, - parent_idx: None, - exact_path: None, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - search_type: get_function_type_for_search( - &item, - tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent, - cache, - ), - aliases: item.attrs.get_doc_aliases(), - deprecation: item.deprecation(tcx), - }); - } - } - (Some(parent), None) if is_impl_child => { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - let impl_generics = clean_impl_generics(cache.parent_stack.last()); - cache.orphan_impl_items.push(OrphanImplItem { - parent, - item: item.clone(), - impl_generics, + item_id.as_def_id() + } else { + None + }, + }); + } else if let Some(path) = parent_path + && (is_impl_child || !cache.stripped_mod) + { + debug_assert!(!item.is_stripped()); + + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. + if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) + && let ty = item.type_() + && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) + { + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + // For searching purposes, a re-export is a duplicate if: + // + // - It's either an inline, or a true re-export + // - It's got the same name + // - Both of them have the same exact path + let defid = (match &*item.kind { + &clean::ItemKind::ImportItem(ref import) => import.source.did, + _ => None, + }) + .or_else(|| item.item_id.as_def_id()); + // In case this is a field from a tuple struct, we don't add it into + // the search index because its name is something like "0", which is + // not useful for rustdoc search. + cache.search_index.push(IndexItem { + ty, + defid, + name, + path: join_with_double_colon(path), + desc, + parent: parent_did, + parent_idx: None, + exact_path: None, impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { @@ -564,9 +556,17 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It } else { None }, + search_type: get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent_did, + cache, + ), + aliases: item.attrs.get_doc_aliases(), + deprecation: item.deprecation(tcx), }); } - _ => {} } } From 08f4d54ea91b1092161e9bb77b5b6aa3f9d48714 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Aug 2024 14:01:38 -0700 Subject: [PATCH 11/41] Extract local variables --- src/librustdoc/formats/cache.rs | 63 +++++++++++++++++---------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 5c18cebb96573..effdce54015aa 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -503,17 +503,15 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. let impl_generics = clean_impl_generics(cache.parent_stack.last()); - cache.orphan_impl_items.push(OrphanImplItem { - parent: parent_did, - item: item.clone(), - impl_generics, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - }); + let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() + { + item_id.as_def_id() + } else { + None + }; + let orphan_item = + OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id }; + cache.orphan_impl_items.push(orphan_item); } else if let Some(path) = parent_path && (is_impl_child || !cache.stripped_mod) { @@ -540,32 +538,37 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It // In case this is a field from a tuple struct, we don't add it into // the search index because its name is something like "0", which is // not useful for rustdoc search. - cache.search_index.push(IndexItem { + let path = join_with_double_colon(path); + let impl_id = + if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { + item_id.as_def_id() + } else { + None + }; + let search_type = get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent_did, + cache, + ); + let aliases = item.attrs.get_doc_aliases(); + let deprecation = item.deprecation(tcx); + let index_item = IndexItem { ty, defid, name, - path: join_with_double_colon(path), + path, desc, parent: parent_did, parent_idx: None, exact_path: None, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - search_type: get_function_type_for_search( - &item, - tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent_did, - cache, - ), - aliases: item.attrs.get_doc_aliases(), - deprecation: item.deprecation(tcx), - }); + impl_id, + search_type, + aliases, + deprecation, + }; + cache.search_index.push(index_item); } } } From 220c2d8c9bc07d0a7b81104edb14f892e0a5f0aa Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Aug 2024 14:48:36 -0700 Subject: [PATCH 12/41] Restructure `add_item_to_search_index` to eliminate code paths Many of the code paths it handled were actually impossible. In other cases, the various checks and transformations were spread around in such a way that it was hard to tell what was going on. --- src/librustdoc/formats/cache.rs | 213 +++++++++++++++----------------- 1 file changed, 103 insertions(+), 110 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index effdce54015aa..d2d0f5a4380b6 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -442,7 +442,9 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { - let ((parent_did, parent_path), is_impl_child) = match *item.kind { + // Item has a name, so it must also have a DefId (can't be an impl, let alone a blanket or auto impl). + let item_def_id = item.item_id.as_def_id().unwrap(); + let (parent_did, parent_path) = match *item.kind { clean::StrippedItem(..) => return, clean::AssocConstItem(..) | clean::AssocTypeItem(..) if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => @@ -454,123 +456,114 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) | clean::StructFieldItem(..) - | clean::VariantItem(..) => ( - ( - Some( - cache - .parent_stack - .last() - .expect("parent_stack is empty") - .item_id() - .expect_def_id(), - ), - Some(&cache.stack[..cache.stack.len() - 1]), - ), - false, - ), + | clean::VariantItem(..) => { + // Don't index if containing module is stripped (i.e., private), + // or if item is tuple struct/variant field (name is a number -> not useful for search). + if cache.stripped_mod + || item.type_() == ItemType::StructField + && name.as_str().chars().all(|c| c.is_digit(10)) + { + return; + } + let parent_did = + cache.parent_stack.last().expect("parent_stack is empty").item_id().expect_def_id(); + let parent_path = &cache.stack[..cache.stack.len() - 1]; + (Some(parent_did), parent_path) + } clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { let last = cache.parent_stack.last().expect("parent_stack is empty 2"); - let did = match &*last { - ParentStackItem::Impl { - // impl Trait for &T { fn method(self); } - // - // When generating a function index with the above shape, we want it - // associated with `T`, not with the primitive reference type. It should - // show up as `T::method`, rather than `reference::method`, in the search - // results page. - for_: clean::Type::BorrowedRef { type_, .. }, - .. - } => type_.def_id(&cache), + let parent_did = match &*last { + // impl Trait for &T { fn method(self); } + // + // When generating a function index with the above shape, we want it + // associated with `T`, not with the primitive reference type. It should + // show up as `T::method`, rather than `reference::method`, in the search + // results page. + ParentStackItem::Impl { for_: clean::Type::BorrowedRef { type_, .. }, .. } => { + type_.def_id(&cache) + } ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), ParentStackItem::Type(item_id) => item_id.as_def_id(), }; - let path = did - .and_then(|did| cache.paths.get(&did)) - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. - .map(|(fqp, _)| &fqp[..fqp.len() - 1]); - ((did, path), true) + let Some(parent_did) = parent_did else { return }; + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + match cache.paths.get(&parent_did) { + Some((fqp, _)) => (Some(parent_did), &fqp[..fqp.len() - 1]), + None => { + handle_orphan_impl_child(cache, item, parent_did); + return; + } + } + } + _ => { + // Don't index if item is crate root, which is inserted later on when serializing the index. + if item_def_id.is_crate_root() { + return; + } + (None, &*cache.stack) } - _ => ((None, Some(&*cache.stack)), false), }; - if let Some(parent_did) = parent_did - && parent_path.is_none() - && is_impl_child - { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - let impl_generics = clean_impl_generics(cache.parent_stack.last()); - let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }; - let orphan_item = - OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id }; - cache.orphan_impl_items.push(orphan_item); - } else if let Some(path) = parent_path - && (is_impl_child || !cache.stripped_mod) - { - debug_assert!(!item.is_stripped()); - - // A crate has a module at its root, containing all items, - // which should not be indexed. The crate-item itself is - // inserted later on when serializing the search-index. - if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) - && let ty = item.type_() - && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) - { - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); - // For searching purposes, a re-export is a duplicate if: - // - // - It's either an inline, or a true re-export - // - It's got the same name - // - Both of them have the same exact path - let defid = (match &*item.kind { - &clean::ItemKind::ImportItem(ref import) => import.source.did, - _ => None, - }) - .or_else(|| item.item_id.as_def_id()); - // In case this is a field from a tuple struct, we don't add it into - // the search index because its name is something like "0", which is - // not useful for rustdoc search. - let path = join_with_double_colon(path); - let impl_id = - if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { - item_id.as_def_id() - } else { - None - }; - let search_type = get_function_type_for_search( - &item, - tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent_did, - cache, - ); - let aliases = item.attrs.get_doc_aliases(); - let deprecation = item.deprecation(tcx); - let index_item = IndexItem { - ty, - defid, - name, - path, - desc, - parent: parent_did, - parent_idx: None, - exact_path: None, - impl_id, - search_type, - aliases, - deprecation, - }; - cache.search_index.push(index_item); - } - } + debug_assert!(!item.is_stripped()); + + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + // For searching purposes, a re-export is a duplicate if: + // + // - It's either an inline, or a true re-export + // - It's got the same name + // - Both of them have the same exact path + let defid = match &*item.kind { + clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id), + _ => item_def_id, + }; + let path = join_with_double_colon(parent_path); + let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { + item_id.as_def_id() + } else { + None + }; + let search_type = get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent_did, + cache, + ); + let aliases = item.attrs.get_doc_aliases(); + let deprecation = item.deprecation(tcx); + let index_item = IndexItem { + ty: item.type_(), + defid: Some(defid), + name, + path, + desc, + parent: parent_did, + parent_idx: None, + exact_path: None, + impl_id, + search_type, + aliases, + deprecation, + }; + cache.search_index.push(index_item); +} + +/// We have a parent, but we don't know where they're +/// defined yet. Wait for later to index this item. +/// See [`Cache::orphan_impl_items`]. +fn handle_orphan_impl_child(cache: &mut Cache, item: &clean::Item, parent_did: DefId) { + let impl_generics = clean_impl_generics(cache.parent_stack.last()); + let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { + item_id.as_def_id() + } else { + None + }; + let orphan_item = + OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id }; + cache.orphan_impl_items.push(orphan_item); } pub(crate) struct OrphanImplItem { From a798e0f4883997907e6a1ffa484071c0ceb2ba85 Mon Sep 17 00:00:00 2001 From: Konippi Date: Fri, 2 Aug 2024 23:58:05 +0900 Subject: [PATCH 13/41] chore: refactor backtrace style in panic --- library/std/src/panic.rs | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 2ca9256715cd8..4c496ade81cda 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -463,11 +463,10 @@ static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0); /// environment variable; see the details in [`get_backtrace_style`]. #[unstable(feature = "panic_backtrace_config", issue = "93346")] pub fn set_backtrace_style(style: BacktraceStyle) { - if !cfg!(feature = "backtrace") { - // If the `backtrace` feature of this crate isn't enabled, skip setting. - return; + if cfg!(feature = "backtrace") { + // If the `backtrace` feature of this crate is enabled, set the backtrace style. + SHOULD_CAPTURE.store(style.as_u8(), Ordering::Release); } - SHOULD_CAPTURE.store(style.as_u8(), Ordering::Release); } /// Checks whether the standard library's panic hook will capture and print a @@ -503,21 +502,13 @@ pub fn get_backtrace_style() -> Option { return Some(style); } - let format = crate::env::var_os("RUST_BACKTRACE") - .map(|x| { - if &x == "0" { - BacktraceStyle::Off - } else if &x == "full" { - BacktraceStyle::Full - } else { - BacktraceStyle::Short - } - }) - .unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT { - BacktraceStyle::Full - } else { - BacktraceStyle::Off - }); + let format = match crate::env::var_os("RUST_BACKTRACE") { + Some(x) if &x == "0" => BacktraceStyle::Off, + Some(x) if &x == "full" => BacktraceStyle::Full, + Some(_) => BacktraceStyle::Short, + None if crate::sys::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full, + None => BacktraceStyle::Off, + }; set_backtrace_style(format); Some(format) } From ed010dd32c55c2add60dc4baff837b281cf81be8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Jul 2024 15:56:09 +0000 Subject: [PATCH 14/41] Assert that all attributes are actually checked via `CheckAttrVisitor` and aren't accidentally usable on completely unrelated HIR nodes Co-authored-by: Jieyou Xu --- compiler/rustc_feature/src/builtin_attrs.rs | 8 +-- compiler/rustc_passes/messages.ftl | 4 ++ compiler/rustc_passes/src/check_attr.rs | 66 ++++++++++++++++++++- compiler/rustc_passes/src/errors.rs | 7 +++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index ef03a25bc164b..72ea55d5999a2 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -703,21 +703,21 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, allocator_internals, experimental!(needs_allocator), ), gated!( - panic_runtime, Normal, template!(Word), WarnFollowing, + panic_runtime, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No, experimental!(panic_runtime) ), gated!( - needs_panic_runtime, Normal, template!(Word), WarnFollowing, + needs_panic_runtime, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No, experimental!(needs_panic_runtime) ), gated!( - compiler_builtins, Normal, template!(Word), WarnFollowing, + compiler_builtins, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No, "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ which contains compiler-rt intrinsics and will never be stable", ), gated!( - profiler_runtime, Normal, template!(Word), WarnFollowing, + profiler_runtime, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No, "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ which contains the profiler runtime and will never be stable", diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1747307a1b2c5..59c9d1e49f5b3 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -100,6 +100,10 @@ passes_continue_labeled_block = .label = labeled blocks cannot be `continue`'d .block_label = labeled block the `continue` points to +passes_coroutine_on_non_closure = + attribute should be applied to closures + .label = not a closure + passes_coverage_not_fn_or_closure = attribute should be applied to a function definition or closure .label = not a function or closure diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 86b18570f376b..755f67b3f4fe0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -20,13 +20,13 @@ use rustc_hir::{ TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, }; use rustc_macros::LintDiagnostic; -use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, @@ -239,7 +239,59 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_generic_attr(hir_id, attr, target, Target::Fn); self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) } - _ => {} + [sym::coroutine] => { + self.check_coroutine(attr, target); + } + [ + // ok + sym::allow + | sym::expect + | sym::warn + | sym::deny + | sym::forbid + | sym::cfg + // need to be fixed + | sym::cfi_encoding // FIXME(cfi_encoding) + | sym::may_dangle // FIXME(dropck_eyepatch) + | sym::pointee // FIXME(derive_smart_pointer) + | sym::linkage // FIXME(linkage) + | sym::no_sanitize // FIXME(no_sanitize) + | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) + | sym::used // handled elsewhere to restrict to static items + | sym::repr // handled elsewhere to restrict to type decls items + | sym::instruction_set // broken on stable!!! + | sym::windows_subsystem // broken on stable!!! + | sym::patchable_function_entry // FIXME(patchable_function_entry) + | sym::deprecated_safe // FIXME(deprecated_safe) + // internal + | sym::prelude_import + | sym::panic_handler + | sym::allow_internal_unsafe + | sym::fundamental + | sym::lang + | sym::needs_allocator + | sym::default_lib_allocator + | sym::start + | sym::custom_mir, + ] => {} + [name, ..] => { + match BUILTIN_ATTRIBUTE_MAP.get(name) { + // checked below + Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} + Some(_) => { + // FIXME: differentiate between unstable and internal attributes just like we do with features instead + // of just accepting `rustc_` attributes by name. That should allow trimming the above list, too. + if !name.as_str().starts_with("rustc_") { + span_bug!( + attr.span, + "builtin attribute {name:?} not handled by `CheckAttrVisitor`" + ) + } + } + None => (), + } + } + [] => unreachable!(), } let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); @@ -376,6 +428,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `#[optimize(..)]` is applied to a function/closure/method, /// or to an impl block or module. + // FIXME(#128488): this should probably be elevated to an error? fn check_optimize(&self, hir_id: HirId, attr: &Attribute, target: Target) { match target { Target::Fn @@ -2279,6 +2332,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.abort.set(true); } } + + fn check_coroutine(&self, attr: &Attribute, target: Target) { + match target { + Target::Closure => return, + _ => { + self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span }); + } + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c4f3c8a0d6cf3..36dfc40e7628b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -636,6 +636,13 @@ pub struct Confusables { pub attr_span: Span, } +#[derive(Diagnostic)] +#[diag(passes_coroutine_on_non_closure)] +pub struct CoroutineOnNonClosure { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_empty_confusables)] pub(crate) struct EmptyConfusables { From 33cb33441de5086e5daa2d951619c279fc394681 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 1 Aug 2024 10:03:10 +0000 Subject: [PATCH 15/41] Add test for `coroutine` attribute --- tests/ui/coroutine/invalid_attr_usage.rs | 11 +++++++++++ tests/ui/coroutine/invalid_attr_usage.stderr | 14 ++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/coroutine/invalid_attr_usage.rs create mode 100644 tests/ui/coroutine/invalid_attr_usage.stderr diff --git a/tests/ui/coroutine/invalid_attr_usage.rs b/tests/ui/coroutine/invalid_attr_usage.rs new file mode 100644 index 0000000000000..995a3aa3100fc --- /dev/null +++ b/tests/ui/coroutine/invalid_attr_usage.rs @@ -0,0 +1,11 @@ +//! The `coroutine` attribute is only allowed on closures. + +#![feature(coroutines)] + +#[coroutine] +//~^ ERROR: attribute should be applied to closures +struct Foo; + +#[coroutine] +//~^ ERROR: attribute should be applied to closures +fn main() {} diff --git a/tests/ui/coroutine/invalid_attr_usage.stderr b/tests/ui/coroutine/invalid_attr_usage.stderr new file mode 100644 index 0000000000000..316a0117e5d41 --- /dev/null +++ b/tests/ui/coroutine/invalid_attr_usage.stderr @@ -0,0 +1,14 @@ +error: attribute should be applied to closures + --> $DIR/invalid_attr_usage.rs:5:1 + | +LL | #[coroutine] + | ^^^^^^^^^^^^ + +error: attribute should be applied to closures + --> $DIR/invalid_attr_usage.rs:9:1 + | +LL | #[coroutine] + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 8b9d7b1489ddd90a69820b6b4f146a79351e850d Mon Sep 17 00:00:00 2001 From: DianQK Date: Thu, 4 Jul 2024 12:43:37 +0800 Subject: [PATCH 16/41] Simplify match based on the cast result of `IntToInt`. --- Cargo.lock | 1 + compiler/rustc_mir_transform/Cargo.toml | 1 + .../rustc_mir_transform/src/match_branches.rs | 141 +++-- ...h_i128_u128.MatchBranchSimplification.diff | 61 +- ...atch_i16_i8.MatchBranchSimplification.diff | 37 -- ...atch_i8_i16.MatchBranchSimplification.diff | 37 -- ..._i16_failed.MatchBranchSimplification.diff | 37 -- ...sext_i8_i16.MatchBranchSimplification.diff | 52 ++ ..._i16_failed.MatchBranchSimplification.diff | 47 ++ ...sext_i8_u16.MatchBranchSimplification.diff | 52 ++ ..._u16_failed.MatchBranchSimplification.diff | 47 ++ ...runc_i16_i8.MatchBranchSimplification.diff | 77 +++ ...6_i8_failed.MatchBranchSimplification.diff | 72 +++ ...runc_i16_u8.MatchBranchSimplification.diff | 77 +++ ...6_u8_failed.MatchBranchSimplification.diff | 72 +++ ...runc_u16_i8.MatchBranchSimplification.diff | 67 ++ ...6_i8_failed.MatchBranchSimplification.diff | 62 ++ ...runc_u16_u8.MatchBranchSimplification.diff | 67 ++ ...6_u8_failed.MatchBranchSimplification.diff | 62 ++ ...atch_u8_i16.MatchBranchSimplification.diff | 32 - ...ch_u8_i16_2.MatchBranchSimplification.diff | 26 - ..._i16_failed.MatchBranchSimplification.diff | 32 - ...16_fallback.MatchBranchSimplification.diff | 31 - ...match_u8_i8.MatchBranchSimplification.diff | 47 ++ ...tch_u8_i8_2.MatchBranchSimplification.diff | 80 +++ ...i8_2_failed.MatchBranchSimplification.diff | 74 +++ ...8_i8_failed.MatchBranchSimplification.diff | 42 ++ ...ailed_len_1.MatchBranchSimplification.diff | 42 ++ ...ailed_len_2.MatchBranchSimplification.diff | 42 ++ ...i8_fallback.MatchBranchSimplification.diff | 38 ++ ...atch_u8_u16.MatchBranchSimplification.diff | 37 -- ...ch_u8_u16_2.MatchBranchSimplification.diff | 37 -- ...zext_u8_i16.MatchBranchSimplification.diff | 47 ++ ..._i16_failed.MatchBranchSimplification.diff | 42 ++ ...zext_u8_u16.MatchBranchSimplification.diff | 47 ++ ..._u16_failed.MatchBranchSimplification.diff | 42 ++ tests/mir-opt/matches_reduce_branches.rs | 579 +++++++++++++++--- ...stive_match.MatchBranchSimplification.diff | 41 +- ...ve_match_i8.MatchBranchSimplification.diff | 41 +- tests/mir-opt/matches_u8.rs | 1 + 40 files changed, 1937 insertions(+), 532 deletions(-) delete mode 100644 tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff delete mode 100644 tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff create mode 100644 tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff diff --git a/Cargo.lock b/Cargo.lock index 316926e584e23..0b5aa7db3190c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4346,6 +4346,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", + "rustc_type_ir", "smallvec", "tracing", ] diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index f864a13a31bbc..07ca51a67aefb 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -25,6 +25,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index df4f3ccb9b5b8..68000fe0ef889 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -3,8 +3,10 @@ use std::iter; use rustc_index::IndexSlice; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; +use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; -use rustc_target::abi::Size; +use rustc_target::abi::Integer; +use rustc_type_ir::TyKind::*; use super::simplify::simplify_cfg; @@ -264,33 +266,56 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { } } +/// Check if the cast constant using `IntToInt` is equal to the target constant. +fn can_cast( + tcx: TyCtxt<'_>, + src_val: impl Into, + src_layout: TyAndLayout<'_>, + cast_ty: Ty<'_>, + target_scalar: ScalarInt, +) -> bool { + let from_scalar = ScalarInt::try_from_uint(src_val.into(), src_layout.size).unwrap(); + let v = match src_layout.ty.kind() { + Uint(_) => from_scalar.to_uint(src_layout.size), + Int(_) => from_scalar.to_int(src_layout.size) as u128, + _ => unreachable!("invalid int"), + }; + let size = match *cast_ty.kind() { + Int(t) => Integer::from_int_ty(&tcx, t).size(), + Uint(t) => Integer::from_uint_ty(&tcx, t).size(), + _ => unreachable!("invalid int"), + }; + let v = size.truncate(v); + let cast_scalar = ScalarInt::try_from_uint(v, size).unwrap(); + cast_scalar == target_scalar +} + #[derive(Default)] struct SimplifyToExp { - transfrom_types: Vec, + transfrom_kinds: Vec, } #[derive(Clone, Copy)] -enum CompareType<'tcx, 'a> { +enum ExpectedTransformKind<'tcx, 'a> { /// Identical statements. Same(&'a StatementKind<'tcx>), /// Assignment statements have the same value. - Eq(&'a Place<'tcx>, Ty<'tcx>, ScalarInt), + SameByEq { place: &'a Place<'tcx>, ty: Ty<'tcx>, scalar: ScalarInt }, /// Enum variant comparison type. - Discr { place: &'a Place<'tcx>, ty: Ty<'tcx>, is_signed: bool }, + Cast { place: &'a Place<'tcx>, ty: Ty<'tcx> }, } -enum TransfromType { +enum TransfromKind { Same, - Eq, - Discr, + Cast, } -impl From> for TransfromType { - fn from(compare_type: CompareType<'_, '_>) -> Self { +impl From> for TransfromKind { + fn from(compare_type: ExpectedTransformKind<'_, '_>) -> Self { match compare_type { - CompareType::Same(_) => TransfromType::Same, - CompareType::Eq(_, _, _) => TransfromType::Eq, - CompareType::Discr { .. } => TransfromType::Discr, + ExpectedTransformKind::Same(_) => TransfromKind::Same, + ExpectedTransformKind::SameByEq { .. } => TransfromKind::Same, + ExpectedTransformKind::Cast { .. } => TransfromKind::Cast, } } } @@ -354,7 +379,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { return None; } let mut target_iter = targets.iter(); - let (first_val, first_target) = target_iter.next().unwrap(); + let (first_case_val, first_target) = target_iter.next().unwrap(); let first_terminator_kind = &bbs[first_target].terminator().kind; // Check that destinations are identical, and if not, then don't optimize this block if !targets @@ -364,24 +389,20 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { return None; } - let discr_size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; + let discr_layout = tcx.layout_of(param_env.and(discr_ty)).unwrap(); let first_stmts = &bbs[first_target].statements; - let (second_val, second_target) = target_iter.next().unwrap(); + let (second_case_val, second_target) = target_iter.next().unwrap(); let second_stmts = &bbs[second_target].statements; if first_stmts.len() != second_stmts.len() { return None; } - fn int_equal(l: ScalarInt, r: impl Into, size: Size) -> bool { - l.to_bits_unchecked() == ScalarInt::try_from_uint(r, size).unwrap().to_bits_unchecked() - } - // We first compare the two branches, and then the other branches need to fulfill the same conditions. - let mut compare_types = Vec::new(); + let mut expected_transform_kinds = Vec::new(); for (f, s) in iter::zip(first_stmts, second_stmts) { let compare_type = match (&f.kind, &s.kind) { // If two statements are exactly the same, we can optimize. - (f_s, s_s) if f_s == s_s => CompareType::Same(f_s), + (f_s, s_s) if f_s == s_s => ExpectedTransformKind::Same(f_s), // If two statements are assignments with the match values to the same place, we can optimize. ( @@ -395,22 +416,29 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { f_c.const_.try_eval_scalar_int(tcx, param_env), s_c.const_.try_eval_scalar_int(tcx, param_env), ) { - (Some(f), Some(s)) if f == s => CompareType::Eq(lhs_f, f_c.const_.ty(), f), - // Enum variants can also be simplified to an assignment statement if their values are equal. - // We need to consider both unsigned and signed scenarios here. + (Some(f), Some(s)) if f == s => ExpectedTransformKind::SameByEq { + place: lhs_f, + ty: f_c.const_.ty(), + scalar: f, + }, + // Enum variants can also be simplified to an assignment statement, + // if we can use `IntToInt` cast to get an equal value. (Some(f), Some(s)) - if ((f_c.const_.ty().is_signed() || discr_ty.is_signed()) - && int_equal(f, first_val, discr_size) - && int_equal(s, second_val, discr_size)) - || (Some(f) == ScalarInt::try_from_uint(first_val, f.size()) - && Some(s) - == ScalarInt::try_from_uint(second_val, s.size())) => + if (can_cast( + tcx, + first_case_val, + discr_layout, + f_c.const_.ty(), + f, + ) && can_cast( + tcx, + second_case_val, + discr_layout, + f_c.const_.ty(), + s, + )) => { - CompareType::Discr { - place: lhs_f, - ty: f_c.const_.ty(), - is_signed: f_c.const_.ty().is_signed() || discr_ty.is_signed(), - } + ExpectedTransformKind::Cast { place: lhs_f, ty: f_c.const_.ty() } } _ => { return None; @@ -421,47 +449,36 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { // Otherwise we cannot optimize. Try another block. _ => return None, }; - compare_types.push(compare_type); + expected_transform_kinds.push(compare_type); } // All remaining BBs need to fulfill the same pattern as the two BBs from the previous step. for (other_val, other_target) in target_iter { let other_stmts = &bbs[other_target].statements; - if compare_types.len() != other_stmts.len() { + if expected_transform_kinds.len() != other_stmts.len() { return None; } - for (f, s) in iter::zip(&compare_types, other_stmts) { + for (f, s) in iter::zip(&expected_transform_kinds, other_stmts) { match (*f, &s.kind) { - (CompareType::Same(f_s), s_s) if f_s == s_s => {} + (ExpectedTransformKind::Same(f_s), s_s) if f_s == s_s => {} ( - CompareType::Eq(lhs_f, f_ty, val), + ExpectedTransformKind::SameByEq { place: lhs_f, ty: f_ty, scalar }, StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty - && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(val) => {} + && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(scalar) => {} ( - CompareType::Discr { place: lhs_f, ty: f_ty, is_signed }, + ExpectedTransformKind::Cast { place: lhs_f, ty: f_ty }, StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), - ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty => { - let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) else { - return None; - }; - if is_signed - && s_c.const_.ty().is_signed() - && int_equal(f, other_val, discr_size) - { - continue; - } - if Some(f) == ScalarInt::try_from_uint(other_val, f.size()) { - continue; - } - return None; - } + ) if let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) + && lhs_f == lhs_s + && s_c.const_.ty() == f_ty + && can_cast(tcx, other_val, discr_layout, f_ty, f) => {} _ => return None, } } } - self.transfrom_types = compare_types.into_iter().map(|c| c.into()).collect(); + self.transfrom_kinds = expected_transform_kinds.into_iter().map(|c| c.into()).collect(); Some(()) } @@ -479,13 +496,13 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { let (_, first) = targets.iter().next().unwrap(); let first = &bbs[first]; - for (t, s) in iter::zip(&self.transfrom_types, &first.statements) { + for (t, s) in iter::zip(&self.transfrom_kinds, &first.statements) { match (t, &s.kind) { - (TransfromType::Same, _) | (TransfromType::Eq, _) => { + (TransfromKind::Same, _) => { patch.add_statement(parent_end, s.kind.clone()); } ( - TransfromType::Discr, + TransfromKind::Cast, StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), ) => { let operand = Operand::Copy(Place::from(discr_local)); diff --git a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff index dc50ae9547255..fc34ce7125ec2 100644 --- a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff @@ -5,37 +5,42 @@ debug i => _1; let mut _0: u128; let mut _2: i128; ++ let mut _3: i128; bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [1: bb5, 2: bb4, 3: bb3, 340282366920938463463374607431768211455: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const core::num::::MAX; - goto -> bb6; - } - - bb3: { - _0 = const 3_u128; - goto -> bb6; - } - - bb4: { - _0 = const 2_u128; - goto -> bb6; - } - - bb5: { - _0 = const 1_u128; - goto -> bb6; - } - - bb6: { +- switchInt(move _2) -> [1: bb5, 2: bb4, 3: bb3, 340282366920938463463374607431768211455: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const core::num::::MAX; +- goto -> bb6; +- } +- +- bb3: { +- _0 = const 3_u128; +- goto -> bb6; +- } +- +- bb4: { +- _0 = const 2_u128; +- goto -> bb6; +- } +- +- bb5: { +- _0 = const 1_u128; +- goto -> bb6; +- } +- +- bb6: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u128 (IntToInt); ++ StorageDead(_3); return; } } diff --git a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff deleted file mode 100644 index 3514914b8ecb0..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff +++ /dev/null @@ -1,37 +0,0 @@ -- // MIR for `match_i16_i8` before MatchBranchSimplification -+ // MIR for `match_i16_i8` after MatchBranchSimplification - - fn match_i16_i8(_1: EnumAi16) -> i8 { - debug i => _1; - let mut _0: i8; - let mut _2: i16; - - bb0: { - _2 = discriminant(_1); - switchInt(move _2) -> [65535: bb4, 2: bb3, 65533: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const -3_i8; - goto -> bb5; - } - - bb3: { - _0 = const 2_i8; - goto -> bb5; - } - - bb4: { - _0 = const -1_i8; - goto -> bb5; - } - - bb5: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff deleted file mode 100644 index ff4255ec8cc97..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff +++ /dev/null @@ -1,37 +0,0 @@ -- // MIR for `match_i8_i16` before MatchBranchSimplification -+ // MIR for `match_i8_i16` after MatchBranchSimplification - - fn match_i8_i16(_1: EnumAi8) -> i16 { - debug i => _1; - let mut _0: i16; - let mut _2: i8; - - bb0: { - _2 = discriminant(_1); - switchInt(move _2) -> [255: bb4, 2: bb3, 253: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const -3_i16; - goto -> bb5; - } - - bb3: { - _0 = const 2_i16; - goto -> bb5; - } - - bb4: { - _0 = const -1_i16; - goto -> bb5; - } - - bb5: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff deleted file mode 100644 index 022039ecee629..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff +++ /dev/null @@ -1,37 +0,0 @@ -- // MIR for `match_i8_i16_failed` before MatchBranchSimplification -+ // MIR for `match_i8_i16_failed` after MatchBranchSimplification - - fn match_i8_i16_failed(_1: EnumAi8) -> i16 { - debug i => _1; - let mut _0: i16; - let mut _2: i8; - - bb0: { - _2 = discriminant(_1); - switchInt(move _2) -> [255: bb4, 2: bb3, 253: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 3_i16; - goto -> bb5; - } - - bb3: { - _0 = const 2_i16; - goto -> bb5; - } - - bb4: { - _0 = const -1_i16; - goto -> bb5; - } - - bb5: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..7f8c2ab8d3748 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff @@ -0,0 +1,52 @@ +- // MIR for `match_sext_i8_i16` before MatchBranchSimplification ++ // MIR for `match_sext_i8_i16` after MatchBranchSimplification + + fn match_sext_i8_i16(_1: EnumAi8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: i8; ++ let mut _3: i8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 127_i16; +- goto -> bb7; +- } +- +- bb3: { +- _0 = const 1_i16; +- goto -> bb7; +- } +- +- bb4: { +- _0 = const 0_i16; +- goto -> bb7; +- } +- +- bb5: { +- _0 = const -1_i16; +- goto -> bb7; +- } +- +- bb6: { +- _0 = const -128_i16; +- goto -> bb7; +- } +- +- bb7: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..94ec22932222b --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff @@ -0,0 +1,47 @@ +- // MIR for `match_sext_i8_i16_failed` before MatchBranchSimplification ++ // MIR for `match_sext_i8_i16_failed` after MatchBranchSimplification + + fn match_sext_i8_i16_failed(_1: EnumAi8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: i8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 127_i16; + goto -> bb7; + } + + bb3: { + _0 = const 1_i16; + goto -> bb7; + } + + bb4: { + _0 = const 0_i16; + goto -> bb7; + } + + bb5: { + _0 = const 255_i16; + goto -> bb7; + } + + bb6: { + _0 = const -128_i16; + goto -> bb7; + } + + bb7: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..86d0d0ba6cf57 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff @@ -0,0 +1,52 @@ +- // MIR for `match_sext_i8_u16` before MatchBranchSimplification ++ // MIR for `match_sext_i8_u16` after MatchBranchSimplification + + fn match_sext_i8_u16(_1: EnumAi8) -> u16 { + debug i => _1; + let mut _0: u16; + let mut _2: i8; ++ let mut _3: i8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 127_u16; +- goto -> bb7; +- } +- +- bb3: { +- _0 = const 1_u16; +- goto -> bb7; +- } +- +- bb4: { +- _0 = const 0_u16; +- goto -> bb7; +- } +- +- bb5: { +- _0 = const u16::MAX; +- goto -> bb7; +- } +- +- bb6: { +- _0 = const 65408_u16; +- goto -> bb7; +- } +- +- bb7: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..281f373bf879a --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff @@ -0,0 +1,47 @@ +- // MIR for `match_sext_i8_u16_failed` before MatchBranchSimplification ++ // MIR for `match_sext_i8_u16_failed` after MatchBranchSimplification + + fn match_sext_i8_u16_failed(_1: EnumAi8) -> u16 { + debug i => _1; + let mut _0: u16; + let mut _2: i8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 127_u16; + goto -> bb7; + } + + bb3: { + _0 = const 1_u16; + goto -> bb7; + } + + bb4: { + _0 = const 0_u16; + goto -> bb7; + } + + bb5: { + _0 = const 255_u16; + goto -> bb7; + } + + bb6: { + _0 = const 65408_u16; + goto -> bb7; + } + + bb7: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..d3d27be207019 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff @@ -0,0 +1,77 @@ +- // MIR for `match_trunc_i16_i8` before MatchBranchSimplification ++ // MIR for `match_trunc_i16_i8` after MatchBranchSimplification + + fn match_trunc_i16_i8(_1: EnumAi16) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: i16; ++ let mut _3: i16; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const i8::MAX; +- goto -> bb12; +- } +- +- bb3: { +- _0 = const 1_i8; +- goto -> bb12; +- } +- +- bb4: { +- _0 = const 0_i8; +- goto -> bb12; +- } +- +- bb5: { +- _0 = const -1_i8; +- goto -> bb12; +- } +- +- bb6: { +- _0 = const i8::MIN; +- goto -> bb12; +- } +- +- bb7: { +- _0 = const i8::MAX; +- goto -> bb12; +- } +- +- bb8: { +- _0 = const 1_i8; +- goto -> bb12; +- } +- +- bb9: { +- _0 = const 0_i8; +- goto -> bb12; +- } +- +- bb10: { +- _0 = const -1_i8; +- goto -> bb12; +- } +- +- bb11: { +- _0 = const i8::MIN; +- goto -> bb12; +- } +- +- bb12: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..7f663baefba5d --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff @@ -0,0 +1,72 @@ +- // MIR for `match_trunc_i16_i8_failed` before MatchBranchSimplification ++ // MIR for `match_trunc_i16_i8_failed` after MatchBranchSimplification + + fn match_trunc_i16_i8_failed(_1: EnumAi16) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: i16; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const -127_i8; + goto -> bb12; + } + + bb3: { + _0 = const 1_i8; + goto -> bb12; + } + + bb4: { + _0 = const 0_i8; + goto -> bb12; + } + + bb5: { + _0 = const -1_i8; + goto -> bb12; + } + + bb6: { + _0 = const i8::MIN; + goto -> bb12; + } + + bb7: { + _0 = const i8::MAX; + goto -> bb12; + } + + bb8: { + _0 = const 1_i8; + goto -> bb12; + } + + bb9: { + _0 = const 0_i8; + goto -> bb12; + } + + bb10: { + _0 = const -1_i8; + goto -> bb12; + } + + bb11: { + _0 = const i8::MIN; + goto -> bb12; + } + + bb12: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..5fe899148ebc5 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff @@ -0,0 +1,77 @@ +- // MIR for `match_trunc_i16_u8` before MatchBranchSimplification ++ // MIR for `match_trunc_i16_u8` after MatchBranchSimplification + + fn match_trunc_i16_u8(_1: EnumAi16) -> u8 { + debug i => _1; + let mut _0: u8; + let mut _2: i16; ++ let mut _3: i16; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 127_u8; +- goto -> bb12; +- } +- +- bb3: { +- _0 = const 1_u8; +- goto -> bb12; +- } +- +- bb4: { +- _0 = const 0_u8; +- goto -> bb12; +- } +- +- bb5: { +- _0 = const u8::MAX; +- goto -> bb12; +- } +- +- bb6: { +- _0 = const 128_u8; +- goto -> bb12; +- } +- +- bb7: { +- _0 = const 127_u8; +- goto -> bb12; +- } +- +- bb8: { +- _0 = const 1_u8; +- goto -> bb12; +- } +- +- bb9: { +- _0 = const 0_u8; +- goto -> bb12; +- } +- +- bb10: { +- _0 = const u8::MAX; +- goto -> bb12; +- } +- +- bb11: { +- _0 = const 128_u8; +- goto -> bb12; +- } +- +- bb12: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u8 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..1c0ffb30c5b5b --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff @@ -0,0 +1,72 @@ +- // MIR for `match_trunc_i16_u8_failed` before MatchBranchSimplification ++ // MIR for `match_trunc_i16_u8_failed` after MatchBranchSimplification + + fn match_trunc_i16_u8_failed(_1: EnumAi16) -> u8 { + debug i => _1; + let mut _0: u8; + let mut _2: i16; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const -127_i8 as u8 (IntToInt); + goto -> bb12; + } + + bb3: { + _0 = const 1_u8; + goto -> bb12; + } + + bb4: { + _0 = const 0_u8; + goto -> bb12; + } + + bb5: { + _0 = const u8::MAX; + goto -> bb12; + } + + bb6: { + _0 = const 128_u8; + goto -> bb12; + } + + bb7: { + _0 = const 127_u8; + goto -> bb12; + } + + bb8: { + _0 = const 1_u8; + goto -> bb12; + } + + bb9: { + _0 = const 0_u8; + goto -> bb12; + } + + bb10: { + _0 = const u8::MAX; + goto -> bb12; + } + + bb11: { + _0 = const 128_u8; + goto -> bb12; + } + + bb12: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..85f97a13cac94 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff @@ -0,0 +1,67 @@ +- // MIR for `match_trunc_u16_i8` before MatchBranchSimplification ++ // MIR for `match_trunc_u16_i8` after MatchBranchSimplification + + fn match_trunc_u16_i8(_1: EnumAu16) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: u16; ++ let mut _3: u16; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const -1_i8; +- goto -> bb10; +- } +- +- bb3: { +- _0 = const i8::MIN; +- goto -> bb10; +- } +- +- bb4: { +- _0 = const i8::MAX; +- goto -> bb10; +- } +- +- bb5: { +- _0 = const 0_i8; +- goto -> bb10; +- } +- +- bb6: { +- _0 = const -1_i8; +- goto -> bb10; +- } +- +- bb7: { +- _0 = const i8::MIN; +- goto -> bb10; +- } +- +- bb8: { +- _0 = const i8::MAX; +- goto -> bb10; +- } +- +- bb9: { +- _0 = const 0_i8; +- goto -> bb10; +- } +- +- bb10: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..cf6c86a71ad95 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff @@ -0,0 +1,62 @@ +- // MIR for `match_trunc_u16_i8_failed` before MatchBranchSimplification ++ // MIR for `match_trunc_u16_i8_failed` after MatchBranchSimplification + + fn match_trunc_u16_i8_failed(_1: EnumAu16) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: u16; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 1_i8; + goto -> bb10; + } + + bb3: { + _0 = const i8::MIN; + goto -> bb10; + } + + bb4: { + _0 = const i8::MAX; + goto -> bb10; + } + + bb5: { + _0 = const 0_i8; + goto -> bb10; + } + + bb6: { + _0 = const -1_i8; + goto -> bb10; + } + + bb7: { + _0 = const i8::MIN; + goto -> bb10; + } + + bb8: { + _0 = const i8::MAX; + goto -> bb10; + } + + bb9: { + _0 = const 0_i8; + goto -> bb10; + } + + bb10: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..768d838eaa6fc --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff @@ -0,0 +1,67 @@ +- // MIR for `match_trunc_u16_u8` before MatchBranchSimplification ++ // MIR for `match_trunc_u16_u8` after MatchBranchSimplification + + fn match_trunc_u16_u8(_1: EnumAu16) -> u8 { + debug i => _1; + let mut _0: u8; + let mut _2: u16; ++ let mut _3: u16; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const u8::MAX; +- goto -> bb10; +- } +- +- bb3: { +- _0 = const 128_u8; +- goto -> bb10; +- } +- +- bb4: { +- _0 = const 127_u8; +- goto -> bb10; +- } +- +- bb5: { +- _0 = const 0_u8; +- goto -> bb10; +- } +- +- bb6: { +- _0 = const u8::MAX; +- goto -> bb10; +- } +- +- bb7: { +- _0 = const 128_u8; +- goto -> bb10; +- } +- +- bb8: { +- _0 = const 127_u8; +- goto -> bb10; +- } +- +- bb9: { +- _0 = const 0_u8; +- goto -> bb10; +- } +- +- bb10: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u8 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..109e97bb578af --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff @@ -0,0 +1,62 @@ +- // MIR for `match_trunc_u16_u8_failed` before MatchBranchSimplification ++ // MIR for `match_trunc_u16_u8_failed` after MatchBranchSimplification + + fn match_trunc_u16_u8_failed(_1: EnumAu16) -> u8 { + debug i => _1; + let mut _0: u8; + let mut _2: u16; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 127_u8; + goto -> bb10; + } + + bb3: { + _0 = const 128_u8; + goto -> bb10; + } + + bb4: { + _0 = const 127_u8; + goto -> bb10; + } + + bb5: { + _0 = const 0_u8; + goto -> bb10; + } + + bb6: { + _0 = const u8::MAX; + goto -> bb10; + } + + bb7: { + _0 = const 128_u8; + goto -> bb10; + } + + bb8: { + _0 = const 127_u8; + goto -> bb10; + } + + bb9: { + _0 = const 0_u8; + goto -> bb10; + } + + bb10: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff deleted file mode 100644 index 72ad60956ab78..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `match_u8_i16` before MatchBranchSimplification -+ // MIR for `match_u8_i16` after MatchBranchSimplification - - fn match_u8_i16(_1: EnumAu8) -> i16 { - debug i => _1; - let mut _0: i16; - let mut _2: u8; - - bb0: { - _2 = discriminant(_1); - switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 2_i16; - goto -> bb4; - } - - bb3: { - _0 = const 1_i16; - goto -> bb4; - } - - bb4: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff deleted file mode 100644 index 3333cd765a891..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `match_u8_i16_2` before MatchBranchSimplification -+ // MIR for `match_u8_i16_2` after MatchBranchSimplification - - fn match_u8_i16_2(_1: EnumAu8) -> i16 { - let mut _0: i16; - let mut _2: u8; - - bb0: { - _2 = discriminant(_1); - switchInt(_2) -> [1: bb3, 2: bb1, otherwise: bb2]; - } - - bb1: { - _0 = const 2_i16; - goto -> bb3; - } - - bb2: { - unreachable; - } - - bb3: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff deleted file mode 100644 index 6da19e46dab7f..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `match_u8_i16_failed` before MatchBranchSimplification -+ // MIR for `match_u8_i16_failed` after MatchBranchSimplification - - fn match_u8_i16_failed(_1: EnumAu8) -> i16 { - debug i => _1; - let mut _0: i16; - let mut _2: u8; - - bb0: { - _2 = discriminant(_1); - switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 3_i16; - goto -> bb4; - } - - bb3: { - _0 = const 1_i16; - goto -> bb4; - } - - bb4: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff deleted file mode 100644 index 5690f17f24f65..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff +++ /dev/null @@ -1,31 +0,0 @@ -- // MIR for `match_u8_i16_fallback` before MatchBranchSimplification -+ // MIR for `match_u8_i16_fallback` after MatchBranchSimplification - - fn match_u8_i16_fallback(_1: u8) -> i16 { - debug i => _1; - let mut _0: i16; - - bb0: { - switchInt(_1) -> [1: bb3, 2: bb2, otherwise: bb1]; - } - - bb1: { - _0 = const 3_i16; - goto -> bb4; - } - - bb2: { - _0 = const 2_i16; - goto -> bb4; - } - - bb3: { - _0 = const 1_i16; - goto -> bb4; - } - - bb4: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..d63eed7c019a4 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff @@ -0,0 +1,47 @@ +- // MIR for `match_u8_i8` before MatchBranchSimplification ++ // MIR for `match_u8_i8` after MatchBranchSimplification + + fn match_u8_i8(_1: EnumAu8) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: u8; ++ let mut _3: u8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const -1_i8; +- goto -> bb6; +- } +- +- bb3: { +- _0 = const i8::MIN; +- goto -> bb6; +- } +- +- bb4: { +- _0 = const i8::MAX; +- goto -> bb6; +- } +- +- bb5: { +- _0 = const 0_i8; +- goto -> bb6; +- } +- +- bb6: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..98dee1835a827 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff @@ -0,0 +1,80 @@ +- // MIR for `match_u8_i8_2` before MatchBranchSimplification ++ // MIR for `match_u8_i8_2` after MatchBranchSimplification + + fn match_u8_i8_2(_1: EnumAu8) -> (i8, i8) { + debug i => _1; + let mut _0: (i8, i8); + let _2: i8; + let _4: (); + let mut _5: u8; + let mut _6: i8; + let mut _7: i8; ++ let mut _8: u8; + scope 1 { + debug a => _2; + let _3: i8; + scope 2 { + debug b => _3; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _5 = discriminant(_1); +- switchInt(move _5) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _2 = const -1_i8; +- _3 = const -1_i8; ++ StorageLive(_8); ++ _8 = move _5; ++ _2 = _8 as i8 (IntToInt); ++ _3 = _8 as i8 (IntToInt); + _4 = (); +- goto -> bb6; +- } +- +- bb3: { +- _2 = const i8::MIN; +- _3 = const i8::MIN; +- _4 = (); +- goto -> bb6; +- } +- +- bb4: { +- _2 = const i8::MAX; +- _3 = const i8::MAX; +- _4 = (); +- goto -> bb6; +- } +- +- bb5: { +- _2 = const 0_i8; +- _3 = const 0_i8; +- _4 = (); +- goto -> bb6; +- } +- +- bb6: { ++ StorageDead(_8); + StorageDead(_4); + StorageLive(_6); + _6 = _2; + StorageLive(_7); + _7 = _3; + _0 = (move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_3); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..901dda5861775 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff @@ -0,0 +1,74 @@ +- // MIR for `match_u8_i8_2_failed` before MatchBranchSimplification ++ // MIR for `match_u8_i8_2_failed` after MatchBranchSimplification + + fn match_u8_i8_2_failed(_1: EnumAu8) -> (i8, i8) { + debug i => _1; + let mut _0: (i8, i8); + let _2: i8; + let _4: (); + let mut _5: u8; + let mut _6: i8; + let mut _7: i8; + scope 1 { + debug a => _2; + let _3: i8; + scope 2 { + debug b => _3; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _5 = discriminant(_1); + switchInt(move _5) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _2 = const -1_i8; + _3 = const 1_i8; + _4 = (); + goto -> bb6; + } + + bb3: { + _2 = const i8::MIN; + _3 = const i8::MIN; + _4 = (); + goto -> bb6; + } + + bb4: { + _2 = const i8::MAX; + _3 = const i8::MAX; + _4 = (); + goto -> bb6; + } + + bb5: { + _2 = const 0_i8; + _3 = const 0_i8; + _4 = (); + goto -> bb6; + } + + bb6: { + StorageDead(_4); + StorageLive(_6); + _6 = _2; + StorageLive(_7); + _7 = _3; + _0 = (move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_3); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..ac96be5531270 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_u8_i8_failed` before MatchBranchSimplification ++ // MIR for `match_u8_i8_failed` after MatchBranchSimplification + + fn match_u8_i8_failed(_1: EnumAu8) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 1_i8; + goto -> bb6; + } + + bb3: { + _0 = const i8::MIN; + goto -> bb6; + } + + bb4: { + _0 = const i8::MAX; + goto -> bb6; + } + + bb5: { + _0 = const 0_i8; + goto -> bb6; + } + + bb6: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..9ebf2cf27cbf7 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_u8_i8_failed_len_1` before MatchBranchSimplification ++ // MIR for `match_u8_i8_failed_len_1` after MatchBranchSimplification + + fn match_u8_i8_failed_len_1(_1: EnumAu8) -> i8 { + let mut _0: i8; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(_2) -> [0: bb1, 127: bb2, 128: bb3, 255: bb4, otherwise: bb5]; + } + + bb1: { + _0 = const 0_i8; + goto -> bb6; + } + + bb2: { + _0 = const i8::MAX; + _0 = const i8::MAX; + goto -> bb6; + } + + bb3: { + _0 = const i8::MIN; + goto -> bb6; + } + + bb4: { + _0 = const -1_i8; + goto -> bb6; + } + + bb5: { + unreachable; + } + + bb6: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..554856777eb6e --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_u8_i8_failed_len_2` before MatchBranchSimplification ++ // MIR for `match_u8_i8_failed_len_2` after MatchBranchSimplification + + fn match_u8_i8_failed_len_2(_1: EnumAu8) -> i8 { + let mut _0: i8; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(_2) -> [0: bb1, 127: bb2, 128: bb3, 255: bb4, otherwise: bb5]; + } + + bb1: { + _0 = const 0_i8; + goto -> bb6; + } + + bb2: { + _0 = const i8::MAX; + goto -> bb6; + } + + bb3: { + _0 = const i8::MIN; + goto -> bb6; + } + + bb4: { + _0 = const -1_i8; + _0 = const -1_i8; + goto -> bb6; + } + + bb5: { + unreachable; + } + + bb6: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..356655021f7f2 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff @@ -0,0 +1,38 @@ +- // MIR for `match_u8_i8_fallback` before MatchBranchSimplification ++ // MIR for `match_u8_i8_fallback` after MatchBranchSimplification + + fn match_u8_i8_fallback(_1: EnumAu8) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb4, 127: bb3, 128: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const -1_i8; + goto -> bb5; + } + + bb2: { + _0 = const i8::MIN; + goto -> bb5; + } + + bb3: { + _0 = const i8::MAX; + goto -> bb5; + } + + bb4: { + _0 = const 0_i8; + goto -> bb5; + } + + bb5: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff deleted file mode 100644 index dc9c1c2b97f1f..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff +++ /dev/null @@ -1,37 +0,0 @@ -- // MIR for `match_u8_u16` before MatchBranchSimplification -+ // MIR for `match_u8_u16` after MatchBranchSimplification - - fn match_u8_u16(_1: EnumBu8) -> u16 { - debug i => _1; - let mut _0: u16; - let mut _2: u8; - - bb0: { - _2 = discriminant(_1); - switchInt(move _2) -> [1: bb4, 2: bb3, 5: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 5_u16; - goto -> bb5; - } - - bb3: { - _0 = const 2_u16; - goto -> bb5; - } - - bb4: { - _0 = const 1_u16; - goto -> bb5; - } - - bb5: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff deleted file mode 100644 index b47de6a52b77f..0000000000000 --- a/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff +++ /dev/null @@ -1,37 +0,0 @@ -- // MIR for `match_u8_u16_2` before MatchBranchSimplification -+ // MIR for `match_u8_u16_2` after MatchBranchSimplification - - fn match_u8_u16_2(_1: EnumBu8) -> i16 { - let mut _0: i16; - let mut _2: u8; - - bb0: { - _2 = discriminant(_1); - switchInt(_2) -> [1: bb1, 2: bb2, 5: bb3, otherwise: bb4]; - } - - bb1: { - _0 = const 1_i16; - goto -> bb5; - } - - bb2: { - _0 = const 2_i16; - goto -> bb5; - } - - bb3: { - _0 = const 5_i16; - _0 = const 5_i16; - goto -> bb5; - } - - bb4: { - unreachable; - } - - bb5: { - return; - } - } - diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..e00a604fe25da --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff @@ -0,0 +1,47 @@ +- // MIR for `match_zext_u8_i16` before MatchBranchSimplification ++ // MIR for `match_zext_u8_i16` after MatchBranchSimplification + + fn match_zext_u8_i16(_1: EnumAu8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: u8; ++ let mut _3: u8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 255_i16; +- goto -> bb6; +- } +- +- bb3: { +- _0 = const 128_i16; +- goto -> bb6; +- } +- +- bb4: { +- _0 = const 127_i16; +- goto -> bb6; +- } +- +- bb5: { +- _0 = const 0_i16; +- goto -> bb6; +- } +- +- bb6: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..a19cd796c275d --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_zext_u8_i16_failed` before MatchBranchSimplification ++ // MIR for `match_zext_u8_i16_failed` after MatchBranchSimplification + + fn match_zext_u8_i16_failed(_1: EnumAu8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 255_i16; + goto -> bb6; + } + + bb3: { + _0 = const 128_i16; + goto -> bb6; + } + + bb4: { + _0 = const -127_i16; + goto -> bb6; + } + + bb5: { + _0 = const 0_i16; + goto -> bb6; + } + + bb6: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..befb9118907b4 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff @@ -0,0 +1,47 @@ +- // MIR for `match_zext_u8_u16` before MatchBranchSimplification ++ // MIR for `match_zext_u8_u16` after MatchBranchSimplification + + fn match_zext_u8_u16(_1: EnumAu8) -> u16 { + debug i => _1; + let mut _0: u16; + let mut _2: u8; ++ let mut _3: u8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 255_u16; +- goto -> bb6; +- } +- +- bb3: { +- _0 = const 128_u16; +- goto -> bb6; +- } +- +- bb4: { +- _0 = const 127_u16; +- goto -> bb6; +- } +- +- bb5: { +- _0 = const 0_u16; +- goto -> bb6; +- } +- +- bb6: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..f781f88449d1d --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_zext_u8_u16_failed` before MatchBranchSimplification ++ // MIR for `match_zext_u8_u16_failed` after MatchBranchSimplification + + fn match_zext_u8_u16_failed(_1: EnumAu8) -> u16 { + debug i => _1; + let mut _0: u16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 255_u16; + goto -> bb6; + } + + bb3: { + _0 = const 128_u16; + goto -> bb6; + } + + bb4: { + _0 = const 65407_u16; + goto -> bb6; + } + + bb5: { + _0 = const 0_u16; + goto -> bb6; + } + + bb6: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs index 176d68bcd4019..9328c616127a8 100644 --- a/tests/mir-opt/matches_reduce_branches.rs +++ b/tests/mir-opt/matches_reduce_branches.rs @@ -1,8 +1,10 @@ //@ test-mir-pass: MatchBranchSimplification +//@ compile-flags: -Zunsound-mir-opts #![feature(repr128)] #![feature(core_intrinsics)] #![feature(custom_mir)] +#![allow(non_camel_case_types)] use std::intrinsics::mir::*; @@ -12,6 +14,7 @@ fn foo(bar: Option<()>) { // CHECK: = Eq( // CHECK: switchInt // CHECK-NOT: switchInt + // CHECK: return if matches!(bar, None) { () } @@ -23,6 +26,7 @@ fn bar(i: i32) -> (bool, bool, bool, bool) { // CHECK: = Ne( // CHECK: = Eq( // CHECK-NOT: switchInt + // CHECK: return let a; let b; let c; @@ -52,6 +56,7 @@ fn bar(i: i32) -> (bool, bool, bool, bool) { fn match_nested_if() -> bool { // CHECK-LABEL: fn match_nested_if( // CHECK-NOT: switchInt + // CHECK: return let val = match () { () if if if if true { true } else { false } { true } else { false } { true @@ -66,42 +71,170 @@ fn match_nested_if() -> bool { val } +// # Fold switchInt into IntToInt. +// To simplify writing and checking these test cases, I use the first character of +// each case to distinguish the sign of the number: +// 'u' for unsigned, '_' for negative, and 'o' for non-negative. +// Followed by a decimal number, and add the corresponding radix representation. +// For example, o127_0x7f represents 127i8, and _1_0xff represents -1i8. + +// ## Cast but without numeric conversion. + #[repr(u8)] enum EnumAu8 { - A = 1, - B = 2, + u0_0x00 = 0, + u127_0x7f = 127, + u128_0x80 = 128, + u255_0xff = 255, +} + +#[repr(i8)] +enum EnumAi8 { + _128_0x80 = -128, + _1_0xff = -1, + o0_0x00 = 0, + o1_0x01 = 1, + o127_0x7f = 127, } -// EMIT_MIR matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff -fn match_u8_i16(i: EnumAu8) -> i16 { - // CHECK-LABEL: fn match_u8_i16( +// EMIT_MIR matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff +fn match_u8_i8(i: EnumAu8) -> i8 { + // CHECK-LABEL: fn match_u8_i8( + // CHECK-NOT: switchInt + // CHECK: return + match i { + EnumAu8::u0_0x00 => 0, + EnumAu8::u127_0x7f => 127, + EnumAu8::u128_0x80 => -128, + EnumAu8::u255_0xff => -1, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff +fn match_u8_i8_failed(i: EnumAu8) -> i8 { + // CHECK-LABEL: fn match_u8_i8_failed( // CHECK: switchInt + // CHECK: return match i { - EnumAu8::A => 1, - EnumAu8::B => 2, + EnumAu8::u0_0x00 => 0, + EnumAu8::u127_0x7f => 127, + EnumAu8::u128_0x80 => -128, + EnumAu8::u255_0xff => 1, // failed } } -// EMIT_MIR matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff +// EMIT_MIR matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff +fn match_u8_i8_2(i: EnumAu8) -> (i8, i8) { + // CHECK-LABEL: fn match_u8_i8_2( + // CHECK-NOT: switchInt + // CHECK: IntToInt + // CHECK: IntToInt + // CHECK: return + let a: i8; + let b: i8; + match i { + EnumAu8::u0_0x00 => { + a = 0; + b = 0; + () + } + EnumAu8::u127_0x7f => { + a = 127; + b = 127; + () + } + EnumAu8::u128_0x80 => { + a = -128; + b = -128; + () + } + EnumAu8::u255_0xff => { + a = -1; + b = -1; + () + } + }; + (a, b) +} + +// EMIT_MIR matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff +fn match_u8_i8_2_failed(i: EnumAu8) -> (i8, i8) { + // CHECK-LABEL: fn match_u8_i8_2_failed( + // CHECK: switchInt + // CHECK: return + let a: i8; + let b: i8; + match i { + EnumAu8::u0_0x00 => { + a = 0; + b = 0; + () + } + EnumAu8::u127_0x7f => { + a = 127; + b = 127; + () + } + EnumAu8::u128_0x80 => { + a = -128; + b = -128; + () + } + EnumAu8::u255_0xff => { + a = -1; + b = 1; // failed + () + } + }; + (a, b) +} + +// EMIT_MIR matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff +fn match_u8_i8_fallback(i: EnumAu8) -> i8 { + // CHECK-LABEL: fn match_u8_i8_fallback( + // CHECK: switchInt + // CHECK: return + match i { + EnumAu8::u0_0x00 => 0, + EnumAu8::u127_0x7f => 127, + EnumAu8::u128_0x80 => -128, + _ => -1, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff // Check for different instruction lengths #[custom_mir(dialect = "built")] -fn match_u8_i16_2(i: EnumAu8) -> i16 { - // CHECK-LABEL: fn match_u8_i16_2( +fn match_u8_i8_failed_len_1(i: EnumAu8) -> i8 { + // CHECK-LABEL: fn match_u8_i8_failed_len_1( // CHECK: switchInt + // CHECK: return mir! { { let a = Discriminant(i); match a { - 1 => bb1, - 2 => bb2, + 0 => bb1, + 127 => bb2, + 128 => bb3, + 255 => bb4, _ => unreachable_bb, } } bb1 = { + RET = 0; Goto(ret) } bb2 = { - RET = 2; + RET = 127; + RET = 127; + Goto(ret) + } + bb3 = { + RET = -128; + Goto(ret) + } + bb4 = { + RET = -1; Goto(ret) } unreachable_bb = { @@ -113,72 +246,39 @@ fn match_u8_i16_2(i: EnumAu8) -> i16 { } } -// EMIT_MIR matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff -fn match_u8_i16_failed(i: EnumAu8) -> i16 { - // CHECK-LABEL: fn match_u8_i16_failed( - // CHECK: switchInt - match i { - EnumAu8::A => 1, - EnumAu8::B => 3, - } -} - -// EMIT_MIR matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff -fn match_u8_i16_fallback(i: u8) -> i16 { - // CHECK-LABEL: fn match_u8_i16_fallback( - // CHECK: switchInt - match i { - 1 => 1, - 2 => 2, - _ => 3, - } -} - -#[repr(u8)] -enum EnumBu8 { - A = 1, - B = 2, - C = 5, -} - -// EMIT_MIR matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff -fn match_u8_u16(i: EnumBu8) -> u16 { - // CHECK-LABEL: fn match_u8_u16( - // CHECK: switchInt - match i { - EnumBu8::A => 1, - EnumBu8::B => 2, - EnumBu8::C => 5, - } -} - -// EMIT_MIR matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff +// EMIT_MIR matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff // Check for different instruction lengths #[custom_mir(dialect = "built")] -fn match_u8_u16_2(i: EnumBu8) -> i16 { - // CHECK-LABEL: fn match_u8_u16_2( +fn match_u8_i8_failed_len_2(i: EnumAu8) -> i8 { + // CHECK-LABEL: fn match_u8_i8_failed_len_2( // CHECK: switchInt + // CHECK: return mir! { { let a = Discriminant(i); match a { - 1 => bb1, - 2 => bb2, - 5 => bb5, + 0 => bb1, + 127 => bb2, + 128 => bb3, + 255 => bb4, _ => unreachable_bb, } } bb1 = { - RET = 1; + RET = 0; Goto(ret) } bb2 = { - RET = 2; + RET = 127; Goto(ret) } - bb5 = { - RET = 5; - RET = 5; + bb3 = { + RET = -128; + Goto(ret) + } + bb4 = { + RET = -1; + RET = -1; Goto(ret) } unreachable_bb = { @@ -190,50 +290,309 @@ fn match_u8_u16_2(i: EnumBu8) -> i16 { } } -#[repr(i8)] -enum EnumAi8 { - A = -1, - B = 2, - C = -3, +// ## Cast with sext. + +// EMIT_MIR matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff +fn match_sext_i8_i16(i: EnumAi8) -> i16 { + // CHECK-LABEL: fn match_sext_i8_i16( + // CHECK-NOT: switchInt + // CHECK: return + match i { + EnumAi8::_128_0x80 => -128, + EnumAi8::_1_0xff => -1, + EnumAi8::o0_0x00 => 0, + EnumAi8::o1_0x01 => 1, + EnumAi8::o127_0x7f => 127, + } +} + +// EMIT_MIR matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff +// Converting `-1i8` to `255i16` is zext. +fn match_sext_i8_i16_failed(i: EnumAi8) -> i16 { + // CHECK-LABEL: fn match_sext_i8_i16_failed( + // CHECK: switchInt + // CHECK: return + match i { + EnumAi8::_128_0x80 => -128, + EnumAi8::_1_0xff => 255, // failed + EnumAi8::o0_0x00 => 0, + EnumAi8::o1_0x01 => 1, + EnumAi8::o127_0x7f => 127, + } +} + +// EMIT_MIR matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff +fn match_sext_i8_u16(i: EnumAi8) -> u16 { + // CHECK-LABEL: fn match_sext_i8_u16( + // CHECK-NOT: switchInt + // CHECK: return + match i { + EnumAi8::_128_0x80 => 0xff80, + EnumAi8::_1_0xff => 0xffff, + EnumAi8::o0_0x00 => 0, + EnumAi8::o1_0x01 => 1, + EnumAi8::o127_0x7f => 127, + } +} + +// EMIT_MIR matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff +// Converting `-1i8` to `255u16` is zext. +fn match_sext_i8_u16_failed(i: EnumAi8) -> u16 { + // CHECK-LABEL: fn match_sext_i8_u16_failed( + // CHECK: switchInt + // CHECK: return + match i { + EnumAi8::_128_0x80 => 0xff80, + EnumAi8::_1_0xff => 0x00ff, // failed + EnumAi8::o0_0x00 => 0, + EnumAi8::o1_0x01 => 1, + EnumAi8::o127_0x7f => 127, + } +} + +// ## Cast with zext. + +// EMIT_MIR matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff +fn match_zext_u8_u16(i: EnumAu8) -> u16 { + // CHECK-LABEL: fn match_zext_u8_u16( + // CHECK-NOT: switchInt + // CHECK: return + match i { + EnumAu8::u0_0x00 => 0, + EnumAu8::u127_0x7f => 0x7f, + EnumAu8::u128_0x80 => 128, + EnumAu8::u255_0xff => 255, + } } -// EMIT_MIR matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff -fn match_i8_i16(i: EnumAi8) -> i16 { - // CHECK-LABEL: fn match_i8_i16( +// EMIT_MIR matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff +fn match_zext_u8_u16_failed(i: EnumAu8) -> u16 { + // CHECK-LABEL: fn match_zext_u8_u16_failed( // CHECK: switchInt + // CHECK: return + match i { + EnumAu8::u0_0x00 => 0, + EnumAu8::u127_0x7f => 0xff7f, // failed + EnumAu8::u128_0x80 => 128, + EnumAu8::u255_0xff => 255, + } +} + +// EMIT_MIR matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff +fn match_zext_u8_i16(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_zext_u8_i16( + // CHECK-NOT: switchInt + // CHECK: return match i { - EnumAi8::A => -1, - EnumAi8::B => 2, - EnumAi8::C => -3, + EnumAu8::u0_0x00 => 0, + EnumAu8::u127_0x7f => 127, + EnumAu8::u128_0x80 => 128, + EnumAu8::u255_0xff => 255, } } -// EMIT_MIR matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff -fn match_i8_i16_failed(i: EnumAi8) -> i16 { - // CHECK-LABEL: fn match_i8_i16_failed( +// EMIT_MIR matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff +fn match_zext_u8_i16_failed(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_zext_u8_i16_failed( // CHECK: switchInt + // CHECK: return match i { - EnumAi8::A => -1, - EnumAi8::B => 2, - EnumAi8::C => 3, + EnumAu8::u0_0x00 => 0, + EnumAu8::u127_0x7f => -127, // failed + EnumAu8::u128_0x80 => 128, + EnumAu8::u255_0xff => 255, } } +// ## Cast with trunc. + +#[repr(u16)] +enum EnumAu16 { + // 0x00nn + u0_0x0000 = 0, + u127_0x007f = 127, + u128_0x0080 = 128, + u255_0x00ff = 255, + // 0xffnn + u65280_0xff00 = 65280, + u65407_0xff7f = 65407, + u65408_0xff80 = 65408, + u65535_0xffff = 65535, +} + #[repr(i16)] enum EnumAi16 { - A = -1, - B = 2, - C = -3, + // 0x00nn + o128_0x0080 = 128, + o255_0x00ff = 255, + o0_0x0000 = 0, + o1_0x0001 = 1, + o127_0x007f = 127, + // 0xffnn + _128_0xff80 = -128, + _1_0xffff = -1, + o0_0xff00 = -256, + o1_0xff01 = -255, + o127_0xff7f = -129, } -// EMIT_MIR matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff -fn match_i16_i8(i: EnumAi16) -> i8 { - // CHECK-LABEL: fn match_i16_i8( +// EMIT_MIR matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff +fn match_trunc_i16_i8(i: EnumAi16) -> i8 { + // CHECK-LABEL: fn match_trunc_i16_i8( + // CHECK-NOT: switchInt + // CHECK: return + match i { + // 0x00nn + EnumAi16::o128_0x0080 => -128, + EnumAi16::o255_0x00ff => -1, + EnumAi16::o0_0x0000 => 0, + EnumAi16::o1_0x0001 => 1, + EnumAi16::o127_0x007f => 127, + // 0xffnn + EnumAi16::_128_0xff80 => -128, + EnumAi16::_1_0xffff => -1, + EnumAi16::o0_0xff00 => 0, + EnumAi16::o1_0xff01 => 1, + EnumAi16::o127_0xff7f => 127, + } +} + +// EMIT_MIR matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff +fn match_trunc_i16_i8_failed(i: EnumAi16) -> i8 { + // CHECK-LABEL: fn match_trunc_i16_i8_failed( // CHECK: switchInt + // CHECK: return match i { - EnumAi16::A => -1, - EnumAi16::B => 2, - EnumAi16::C => -3, + // 0x00nn + EnumAi16::o128_0x0080 => -128, + EnumAi16::o255_0x00ff => -1, + EnumAi16::o0_0x0000 => 0, + EnumAi16::o1_0x0001 => 1, + EnumAi16::o127_0x007f => 127, + // 0xffnn + EnumAi16::_128_0xff80 => -128, + EnumAi16::_1_0xffff => -1, + EnumAi16::o0_0xff00 => 0, + EnumAi16::o1_0xff01 => 1, + EnumAi16::o127_0xff7f => -127, // failed + } +} + +// EMIT_MIR matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff +fn match_trunc_i16_u8(i: EnumAi16) -> u8 { + // CHECK-LABEL: fn match_trunc_i16_u8( + // CHECK-NOT: switchInt + // CHECK: return + match i { + // 0x00nn + EnumAi16::o128_0x0080 => 128, + EnumAi16::o255_0x00ff => 255, + EnumAi16::o0_0x0000 => 0, + EnumAi16::o1_0x0001 => 1, + EnumAi16::o127_0x007f => 127, + // 0xffnn + EnumAi16::_128_0xff80 => 128, + EnumAi16::_1_0xffff => 255, + EnumAi16::o0_0xff00 => 0, + EnumAi16::o1_0xff01 => 1, + EnumAi16::o127_0xff7f => 127, + } +} + +// EMIT_MIR matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff +fn match_trunc_i16_u8_failed(i: EnumAi16) -> u8 { + // CHECK-LABEL: fn match_trunc_i16_u8_failed( + // CHECK: switchInt + // CHECK: return + match i { + // 0x00nn + EnumAi16::o128_0x0080 => 128, + EnumAi16::o255_0x00ff => 255, + EnumAi16::o0_0x0000 => 0, + EnumAi16::o1_0x0001 => 1, + EnumAi16::o127_0x007f => 127, + // 0xffnn + EnumAi16::_128_0xff80 => 128, + EnumAi16::_1_0xffff => 255, + EnumAi16::o0_0xff00 => 0, + EnumAi16::o1_0xff01 => 1, + EnumAi16::o127_0xff7f => -127i8 as u8, // failed + } +} + +// EMIT_MIR matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff +fn match_trunc_u16_u8(i: EnumAu16) -> u8 { + // CHECK-LABEL: fn match_trunc_u16_u8( + // CHECK-NOT: switchInt + // CHECK: return + match i { + // 0x00nn + EnumAu16::u0_0x0000 => 0, + EnumAu16::u127_0x007f => 127, + EnumAu16::u128_0x0080 => 128, + EnumAu16::u255_0x00ff => 255, + // 0xffnn + EnumAu16::u65280_0xff00 => 0, + EnumAu16::u65407_0xff7f => 127, + EnumAu16::u65408_0xff80 => 128, + EnumAu16::u65535_0xffff => 255, + } +} + +// EMIT_MIR matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff +fn match_trunc_u16_u8_failed(i: EnumAu16) -> u8 { + // CHECK-LABEL: fn match_trunc_u16_u8_failed( + // CHECK: switchInt + // CHECK: return + match i { + // 0x00nn + EnumAu16::u0_0x0000 => 0, + EnumAu16::u127_0x007f => 127, + EnumAu16::u128_0x0080 => 128, + EnumAu16::u255_0x00ff => 255, + // 0xffnn + EnumAu16::u65280_0xff00 => 0, + EnumAu16::u65407_0xff7f => 127, + EnumAu16::u65408_0xff80 => 128, + EnumAu16::u65535_0xffff => 127, // failed + } +} + +// EMIT_MIR matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff +fn match_trunc_u16_i8(i: EnumAu16) -> i8 { + // CHECK-LABEL: fn match_trunc_u16_i8( + // CHECK-NOT: switchInt + // CHECK: return + match i { + // 0x00nn + EnumAu16::u0_0x0000 => 0, + EnumAu16::u127_0x007f => 127, + EnumAu16::u128_0x0080 => -128, + EnumAu16::u255_0x00ff => -1, + // 0xffnn + EnumAu16::u65280_0xff00 => 0, + EnumAu16::u65407_0xff7f => 127, + EnumAu16::u65408_0xff80 => -128, + EnumAu16::u65535_0xffff => -1, + } +} + +// EMIT_MIR matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff +fn match_trunc_u16_i8_failed(i: EnumAu16) -> i8 { + // CHECK-LABEL: fn match_trunc_u16_i8_failed( + // CHECK: switchInt + // CHECK: return + match i { + // 0x00nn + EnumAu16::u0_0x0000 => 0, + EnumAu16::u127_0x007f => 127, + EnumAu16::u128_0x0080 => -128, + EnumAu16::u255_0x00ff => -1, + // 0xffnn + EnumAu16::u65280_0xff00 => 0, + EnumAu16::u65407_0xff7f => 127, + EnumAu16::u65408_0xff80 => -128, + EnumAu16::u65535_0xffff => 1, } } @@ -248,7 +607,8 @@ enum EnumAi128 { // EMIT_MIR matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff fn match_i128_u128(i: EnumAi128) -> u128 { // CHECK-LABEL: fn match_i128_u128( - // CHECK: switchInt + // CHECK-NOT: switchInt + // CHECK: return match i { EnumAi128::A => 1, EnumAi128::B => 2, @@ -262,15 +622,34 @@ fn main() { let _ = foo(Some(())); let _ = bar(0); let _ = match_nested_if(); - let _ = match_u8_i16(EnumAu8::A); - let _ = match_u8_i16_2(EnumAu8::A); - let _ = match_u8_i16_failed(EnumAu8::A); - let _ = match_u8_i16_fallback(1); - let _ = match_u8_u16(EnumBu8::A); - let _ = match_u8_u16_2(EnumBu8::A); - let _ = match_i8_i16(EnumAi8::A); - let _ = match_i8_i16_failed(EnumAi8::A); - let _ = match_i8_i16(EnumAi8::A); - let _ = match_i16_i8(EnumAi16::A); + + let _: i8 = match_u8_i8(EnumAu8::u0_0x00); + let _: i8 = match_u8_i8_failed(EnumAu8::u0_0x00); + let _: (i8, i8) = match_u8_i8_2(EnumAu8::u0_0x00); + let _: (i8, i8) = match_u8_i8_2_failed(EnumAu8::u0_0x00); + let _: i8 = match_u8_i8_fallback(EnumAu8::u0_0x00); + let _: i8 = match_u8_i8_failed_len_1(EnumAu8::u0_0x00); + let _: i8 = match_u8_i8_failed_len_2(EnumAu8::u0_0x00); + + let _: i16 = match_sext_i8_i16(EnumAi8::o0_0x00); + let _: i16 = match_sext_i8_i16_failed(EnumAi8::o0_0x00); + let _: u16 = match_sext_i8_u16(EnumAi8::o0_0x00); + let _: u16 = match_sext_i8_u16_failed(EnumAi8::o0_0x00); + + let _: u16 = match_zext_u8_u16(EnumAu8::u0_0x00); + let _: u16 = match_zext_u8_u16_failed(EnumAu8::u0_0x00); + let _: i16 = match_zext_u8_i16(EnumAu8::u0_0x00); + let _: i16 = match_zext_u8_i16_failed(EnumAu8::u0_0x00); + + let _: i8 = match_trunc_i16_i8(EnumAi16::o0_0x0000); + let _: i8 = match_trunc_i16_i8_failed(EnumAi16::o0_0x0000); + let _: u8 = match_trunc_i16_u8(EnumAi16::o0_0x0000); + let _: u8 = match_trunc_i16_u8_failed(EnumAi16::o0_0x0000); + + let _: i8 = match_trunc_u16_i8(EnumAu16::u0_0x0000); + let _: i8 = match_trunc_u16_i8_failed(EnumAu16::u0_0x0000); + let _: u8 = match_trunc_u16_u8(EnumAu16::u0_0x0000); + let _: u8 = match_trunc_u16_u8_failed(EnumAu16::u0_0x0000); + let _ = match_i128_u128(EnumAi128::A); } diff --git a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff index 157f9c98353e7..11a18f58e3a1f 100644 --- a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff @@ -5,27 +5,32 @@ debug e => _1; let mut _0: u8; let mut _2: isize; ++ let mut _3: isize; bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 1_u8; - goto -> bb4; - } - - bb3: { - _0 = const 0_u8; - goto -> bb4; - } - - bb4: { +- switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 1_u8; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 0_u8; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u8 (IntToInt); ++ StorageDead(_3); return; } } diff --git a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff index 19083771fd954..809badc41ba71 100644 --- a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff @@ -5,27 +5,32 @@ debug e => _1; let mut _0: i8; let mut _2: isize; ++ let mut _3: isize; bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 1_i8; - goto -> bb4; - } - - bb3: { - _0 = const 0_i8; - goto -> bb4; - } - - bb4: { +- switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 1_i8; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 0_i8; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); return; } } diff --git a/tests/mir-opt/matches_u8.rs b/tests/mir-opt/matches_u8.rs index 86d6462567428..89deead461ee8 100644 --- a/tests/mir-opt/matches_u8.rs +++ b/tests/mir-opt/matches_u8.rs @@ -1,5 +1,6 @@ // skip-filecheck //@ test-mir-pass: MatchBranchSimplification +//@ compile-flags: -Zunsound-mir-opts // EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff // EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff From 1f9d9603c05a1fb56825b4fc54ea28aa04485024 Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 31 Jul 2024 07:58:39 +0800 Subject: [PATCH 17/41] Re-enable SimplifyToExp in match_branches. --- compiler/rustc_mir_transform/src/match_branches.rs | 5 +---- tests/mir-opt/matches_reduce_branches.rs | 1 - tests/mir-opt/matches_u8.rs | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 68000fe0ef889..47758b56f8c90 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -44,10 +44,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { should_cleanup = true; continue; } - // unsound: https://github.com/rust-lang/rust/issues/124150 - if tcx.sess.opts.unstable_opts.unsound_mir_opts - && SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() - { + if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() { should_cleanup = true; continue; } diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs index 9328c616127a8..6787e5816a309 100644 --- a/tests/mir-opt/matches_reduce_branches.rs +++ b/tests/mir-opt/matches_reduce_branches.rs @@ -1,5 +1,4 @@ //@ test-mir-pass: MatchBranchSimplification -//@ compile-flags: -Zunsound-mir-opts #![feature(repr128)] #![feature(core_intrinsics)] diff --git a/tests/mir-opt/matches_u8.rs b/tests/mir-opt/matches_u8.rs index 89deead461ee8..86d6462567428 100644 --- a/tests/mir-opt/matches_u8.rs +++ b/tests/mir-opt/matches_u8.rs @@ -1,6 +1,5 @@ // skip-filecheck //@ test-mir-pass: MatchBranchSimplification -//@ compile-flags: -Zunsound-mir-opts // EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff // EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff From 5ce554f4ecaffe1161eaecc9111a06da3a95cc12 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 3 Aug 2024 09:31:21 +0300 Subject: [PATCH 18/41] allow setting `link-shared` and `static-libstdcpp` with CI LLVM These options also affect `compiler/rustc_llvm` builds. They should be configurable even when using CI LLVM. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1343e257efe08..39a17754c4f6b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1840,6 +1840,23 @@ impl Config { config.llvm_from_ci = config.parse_download_ci_llvm(download_ci_llvm, asserts); if config.llvm_from_ci { + let warn = |option: &str| { + println!( + "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." + ); + println!( + "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." + ); + }; + + if static_libstdcpp.is_some() { + warn("static-libstdcpp"); + } + + if link_shared.is_some() { + warn("link-shared"); + } + // None of the LLVM options, except assertions, are supported // when using downloaded LLVM. We could just ignore these but // that's potentially confusing, so force them to not be @@ -1849,9 +1866,6 @@ impl Config { check_ci_llvm!(optimize_toml); check_ci_llvm!(thin_lto); check_ci_llvm!(release_debuginfo); - // CI-built LLVM can be either dynamic or static. We won't know until we download it. - check_ci_llvm!(link_shared); - check_ci_llvm!(static_libstdcpp); check_ci_llvm!(targets); check_ci_llvm!(experimental_targets); check_ci_llvm!(clang_cl); From 21c02517c31e90ec1c001f3997abcea2caa36f0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2024 10:29:52 +0200 Subject: [PATCH 19/41] Miri: add a flag to do recursive validity checking --- .../src/const_eval/eval_queries.rs | 2 +- .../rustc_const_eval/src/interpret/machine.rs | 7 + .../rustc_const_eval/src/interpret/memory.rs | 5 +- .../rustc_const_eval/src/interpret/place.rs | 15 +- .../src/interpret/validity.rs | 176 +++++++++++------- .../src/util/check_validity_requirement.rs | 2 +- src/tools/miri/README.md | 2 + src/tools/miri/src/bin/miri.rs | 6 +- src/tools/miri/src/eval.rs | 16 +- src/tools/miri/src/intrinsics/mod.rs | 2 +- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/machine.rs | 36 ++-- .../validity/recursive-validity-ref-bool.rs | 8 + .../recursive-validity-ref-bool.stderr | 15 ++ 14 files changed, 186 insertions(+), 107 deletions(-) create mode 100644 src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs create mode 100644 src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ba4b80d102697..6d5bca5731331 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -396,7 +396,7 @@ fn const_validate_mplace<'tcx>( let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); let mut ref_tracking = RefTracking::new(mplace.clone()); let mut inner = false; - while let Some((mplace, path)) = ref_tracking.todo.pop() { + while let Some((mplace, path)) = ref_tracking.next() { let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) { _ if cid.promoted.is_some() => CtfeValidationMode::Promoted, Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static` diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 4620b15d8d985..bdce8253b2e76 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -165,6 +165,13 @@ pub trait Machine<'tcx>: Sized { /// Whether to enforce the validity invariant for a specific layout. fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool; + /// Whether to enforce the validity invariant *recursively*. + fn enforce_validity_recursively( + _ecx: &InterpCx<'tcx, Self>, + _layout: TyAndLayout<'tcx>, + ) -> bool { + false + } /// Whether function calls should be [ABI](CallAbi)-checked. fn enforce_abi(_ecx: &InterpCx<'tcx, Self>) -> bool { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index b71e6ed8d2b65..2e5d0ae773654 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1006,8 +1006,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }) } - /// Runs the close in "validation" mode, which means the machine's memory read hooks will be + /// Runs the closure in "validation" mode, which means the machine's memory read hooks will be /// suppressed. Needless to say, this must only be set with great care! Cannot be nested. + /// + /// We do this so Miri's allocation access tracking does not show the validation + /// reads as spurious accesses. pub(super) fn run_for_validation(&self, f: impl FnOnce() -> R) -> R { // This deliberately uses `==` on `bool` to follow the pattern // `assert!(val.replace(new) == old)`. diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 242f36363a58e..470a62026b943 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -572,7 +572,10 @@ where if M::enforce_validity(self, dest.layout()) { // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.to_op(self)?)?; + self.validate_operand( + &dest.to_op(self)?, + M::enforce_validity_recursively(self, dest.layout()), + )?; } Ok(()) @@ -811,7 +814,10 @@ where // Generally for transmutation, data must be valid both at the old and new type. // But if the types are the same, the 2nd validation below suffices. if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) { - self.validate_operand(&src.to_op(self)?)?; + self.validate_operand( + &src.to_op(self)?, + M::enforce_validity_recursively(self, src.layout()), + )?; } // Do the actual copy. @@ -819,7 +825,10 @@ where if validate_dest && M::enforce_validity(self, dest.layout()) { // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.to_op(self)?)?; + self.validate_operand( + &dest.to_op(self)?, + M::enforce_validity_recursively(self, dest.layout()), + )?; } Ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index c8d59c5648da0..460f5448634b5 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -155,8 +155,8 @@ impl CtfeValidationMode { /// State for tracking recursive validation of references pub struct RefTracking { - pub seen: FxHashSet, - pub todo: Vec<(T, PATH)>, + seen: FxHashSet, + todo: Vec<(T, PATH)>, } impl RefTracking { @@ -169,8 +169,11 @@ impl RefTracking ref_tracking_for_consts.seen.insert(op); ref_tracking_for_consts } + pub fn next(&mut self) -> Option<(T, PATH)> { + self.todo.pop() + } - pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { + fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { if self.seen.insert(op.clone()) { trace!("Recursing below ptr {:#?}", op); let path = path(); @@ -435,88 +438,96 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? { throw_validation_failure!(self.path, NullPtr { ptr_kind }) } - // Do not allow pointers to uninhabited types. + // Do not allow references to uninhabited types. if place.layout.abi.is_uninhabited() { let ty = place.layout.ty; throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty }) } // Recursive checking if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { - // Determine whether this pointer expects to be pointing to something mutable. - let ptr_expected_mutbl = match ptr_kind { - PointerKind::Box => Mutability::Mut, - PointerKind::Ref(mutbl) => { - // We do not take into account interior mutability here since we cannot know if - // there really is an `UnsafeCell` inside `Option` -- so we check - // that in the recursive descent behind this reference (controlled by - // `allow_immutable_unsafe_cell`). - mutbl - } - }; // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. - if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr(), 0) { + if let Some(ctfe_mode) = self.ctfe_mode { let mut skip_recursive_check = false; - if let Some(GlobalAlloc::Static(did)) = self.ecx.tcx.try_get_global_alloc(alloc_id) + // CTFE imposes restrictions on what references can point to. + if let Ok((alloc_id, _offset, _prov)) = + self.ecx.ptr_try_get_alloc_id(place.ptr(), 0) { - let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() }; - // Special handling for pointers to statics (irrespective of their type). - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - // Mode-specific checks - match self.ctfe_mode { - Some( - CtfeValidationMode::Static { .. } | CtfeValidationMode::Promoted { .. }, - ) => { - // We skip recursively checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us (potentially through a promoted). - // This could miss some UB, but that's fine. - // We still walk nested allocations, as they are fundamentally part of this validation run. - // This means we will also recurse into nested statics of *other* - // statics, even though we do not recurse into other statics directly. - // That's somewhat inconsistent but harmless. - skip_recursive_check = !nested; - } - Some(CtfeValidationMode::Const { .. }) => { - // We can't recursively validate `extern static`, so we better reject them. - if self.ecx.tcx.is_foreign_item(did) { - throw_validation_failure!(self.path, ConstRefToExtern); + if let Some(GlobalAlloc::Static(did)) = + self.ecx.tcx.try_get_global_alloc(alloc_id) + { + let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { + bug!() + }; + // Special handling for pointers to statics (irrespective of their type). + assert!(!self.ecx.tcx.is_thread_local_static(did)); + assert!(self.ecx.tcx.is_static(did)); + // Mode-specific checks + match ctfe_mode { + CtfeValidationMode::Static { .. } + | CtfeValidationMode::Promoted { .. } => { + // We skip recursively checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us (potentially through a promoted). + // This could miss some UB, but that's fine. + // We still walk nested allocations, as they are fundamentally part of this validation run. + // This means we will also recurse into nested statics of *other* + // statics, even though we do not recurse into other statics directly. + // That's somewhat inconsistent but harmless. + skip_recursive_check = !nested; + } + CtfeValidationMode::Const { .. } => { + // We can't recursively validate `extern static`, so we better reject them. + if self.ecx.tcx.is_foreign_item(did) { + throw_validation_failure!(self.path, ConstRefToExtern); + } } } - None => {} } - } - // Dangling and Mutability check. - let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); - if alloc_kind == AllocKind::Dead { - // This can happen for zero-sized references. We can't have *any* references to non-existing - // allocations though, interning rejects them all as the rest of rustc isn't happy with them... - // so we throw an error, even though this isn't really UB. - // A potential future alternative would be to resurrect this as a zero-sized allocation - // (which codegen will then compile to an aligned dummy pointer anyway). - throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); - } - // If this allocation has size zero, there is no actual mutability here. - if size != Size::ZERO { - let alloc_actual_mutbl = mutability(self.ecx, alloc_id); - // Mutable pointer to immutable memory is no good. - if ptr_expected_mutbl == Mutability::Mut - && alloc_actual_mutbl == Mutability::Not - { - throw_validation_failure!(self.path, MutableRefToImmutable); + // Dangling and Mutability check. + let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); + if alloc_kind == AllocKind::Dead { + // This can happen for zero-sized references. We can't have *any* references to + // non-existing allocations in const-eval though, interning rejects them all as + // the rest of rustc isn't happy with them... so we throw an error, even though + // this isn't really UB. + // A potential future alternative would be to resurrect this as a zero-sized allocation + // (which codegen will then compile to an aligned dummy pointer anyway). + throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); } - // In a const, everything must be completely immutable. - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { + // If this allocation has size zero, there is no actual mutability here. + if size != Size::ZERO { + // Determine whether this pointer expects to be pointing to something mutable. + let ptr_expected_mutbl = match ptr_kind { + PointerKind::Box => Mutability::Mut, + PointerKind::Ref(mutbl) => { + // We do not take into account interior mutability here since we cannot know if + // there really is an `UnsafeCell` inside `Option` -- so we check + // that in the recursive descent behind this reference (controlled by + // `allow_immutable_unsafe_cell`). + mutbl + } + }; + // Determine what it actually points to. + let alloc_actual_mutbl = mutability(self.ecx, alloc_id); + // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut - || alloc_actual_mutbl == Mutability::Mut + && alloc_actual_mutbl == Mutability::Not { - throw_validation_failure!(self.path, ConstRefToMutable); + throw_validation_failure!(self.path, MutableRefToImmutable); + } + // In a const, everything must be completely immutable. + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { + if ptr_expected_mutbl == Mutability::Mut + || alloc_actual_mutbl == Mutability::Mut + { + throw_validation_failure!(self.path, ConstRefToMutable); + } } } } @@ -524,6 +535,15 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if skip_recursive_check { return Ok(()); } + } else { + // This is not CTFE, so it's Miri with recursive checking. + // FIXME: we do *not* check behind boxes, since creating a new box first creates it uninitialized + // and then puts the value in there, so briefly we have a box with uninit contents. + // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not + // needed since validation reads bypass Stacked Borrows and data race checks. + if matches!(ptr_kind, PointerKind::Box) { + return Ok(()); + } } let path = &self.path; ref_tracking.track(place, || { @@ -1072,11 +1092,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// `op` is assumed to cover valid memory if it is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] - pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + pub fn validate_operand( + &self, + op: &OpTy<'tcx, M::Provenance>, + recursive: bool, + ) -> InterpResult<'tcx> { // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's // still correct to not use `ctfe_mode`: that mode is for validation of the final constant - // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking - // recurse through references which, for now, we don't want here, either. - self.validate_operand_internal(op, vec![], None, None) + // value, it rules out things like `UnsafeCell` in awkward places. + if !recursive { + return self.validate_operand_internal(op, vec![], None, None); + } + // Do a recursive check. + let mut ref_tracking = RefTracking::empty(); + self.validate_operand_internal(op, vec![], Some(&mut ref_tracking), None)?; + while let Some((mplace, path)) = ref_tracking.todo.pop() { + self.validate_operand_internal(&mplace.into(), path, Some(&mut ref_tracking), None)?; + } + Ok(()) } } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index daf57285ebe6d..4b6b1e453b82e 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -67,7 +67,7 @@ fn might_permit_raw_init_strict<'tcx>( // This does *not* actually check that references are dereferenceable, but since all types that // require dereferenceability also require non-null, we don't actually get any false negatives // due to this. - Ok(cx.validate_operand(&ot).is_ok()) + Ok(cx.validate_operand(&ot, /*recursive*/ false).is_ok()) } /// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index b1be596c00679..ff0f162822c45 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -398,6 +398,8 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. +* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking + recurse below references. * `-Zmiri-retag-fields[=]` controls when Stacked Borrows retagging recurses into fields. `all` means it always recurses (the default, and equivalent to `-Zmiri-retag-fields` without an explicit value), `none` means it never recurses, `scalar` means it only recurses for diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 25b154a8206c9..4b3c97e248f41 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -44,7 +44,7 @@ use rustc_session::config::{CrateType, ErrorOutputType, OptLevel}; use rustc_session::search_paths::PathKind; use rustc_session::{CtfeBacktrace, EarlyDiagCtxt}; -use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields}; +use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields, ValidationMode}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -421,7 +421,9 @@ fn main() { } else if arg == "--" { after_dashdash = true; } else if arg == "-Zmiri-disable-validation" { - miri_config.validate = false; + miri_config.validation = ValidationMode::No; + } else if arg == "-Zmiri-recursive-validation" { + miri_config.validation = ValidationMode::Deep; } else if arg == "-Zmiri-disable-stacked-borrows" { miri_config.borrow_tracker = None; } else if arg == "-Zmiri-tree-borrows" { diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 2184a4426c8dc..53e877517089c 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -68,7 +68,7 @@ pub enum IsolatedOp { Allow, } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum BacktraceStyle { /// Prints a terser backtrace which ideally only contains relevant information. Short, @@ -78,6 +78,16 @@ pub enum BacktraceStyle { Off, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ValidationMode { + /// Do not perform any kind of validation. + No, + /// Validate the interior of the value, but not things behind references. + Shallow, + /// Fully recursively validate references. + Deep, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -85,7 +95,7 @@ pub struct MiriConfig { /// (This is still subject to isolation as well as `forwarded_env_vars`.) pub env: Vec<(OsString, OsString)>, /// Determine if validity checking is enabled. - pub validate: bool, + pub validation: ValidationMode, /// Determines if Stacked Borrows or Tree Borrows is enabled. pub borrow_tracker: Option, /// Whether `core::ptr::Unique` receives special treatment. @@ -162,7 +172,7 @@ impl Default for MiriConfig { fn default() -> MiriConfig { MiriConfig { env: vec![], - validate: true, + validation: ValidationMode::Shallow, borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows), unique_is_unique: false, check_alignment: AlignmentCheck::Int, diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9cd776c937101..d60119e75f16d 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -153,7 +153,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Would not be considered UB, or the other way around (`is_val_statically_known(0)`). "is_val_statically_known" => { let [arg] = check_arg_count(args)?; - this.validate_operand(arg)?; + this.validate_operand(arg, /*recursive*/ false)?; let branch: bool = this.machine.rng.get_mut().gen(); this.write_scalar(Scalar::from_bool(branch), dest)?; } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 24909f21eb2b3..2b3ae6df5de8a 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -142,6 +142,7 @@ pub use crate::diagnostics::{ }; pub use crate::eval::{ create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, + ValidationMode, }; pub use crate::helpers::{AccessKind, EvalContextExt as _}; pub use crate::machine::{ diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 5f4aa9d2f5d21..fec345c8de1da 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -187,7 +187,11 @@ impl fmt::Display for MiriMemoryKind { pub type MemoryKind = interpret::MemoryKind; /// Pointer provenance. -#[derive(Clone, Copy)] +// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking +// *might* be recursive and then it has to track which places have already been visited. +// These implementations are a bit questionable, and it means we may check the same place multiple +// times with different provenance, but that is in general not wrong. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum Provenance { /// For pointers with concrete provenance. we exactly know which allocation they are attached to /// and what their borrow tag is. @@ -215,24 +219,6 @@ pub enum Provenance { Wildcard, } -// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking -// *might* be recursive and then it has to track which places have already been visited. -// However, comparing provenance is meaningless, since `Wildcard` might be any provenance -- and of -// course we don't actually do recursive checking. -// We could change `RefTracking` to strip provenance for its `seen` set but that type is generic so that is quite annoying. -// Instead owe add the required instances but make them panic. -impl PartialEq for Provenance { - fn eq(&self, _other: &Self) -> bool { - panic!("Provenance must not be compared") - } -} -impl Eq for Provenance {} -impl std::hash::Hash for Provenance { - fn hash(&self, _state: &mut H) { - panic!("Provenance must not be hashed") - } -} - /// The "extra" information a pointer has over a regular AllocId. #[derive(Copy, Clone, PartialEq)] pub enum ProvenanceExtra { @@ -460,7 +446,7 @@ pub struct MiriMachine<'tcx> { pub(crate) isolated_op: IsolatedOp, /// Whether to enforce the validity invariant. - pub(crate) validate: bool, + pub(crate) validation: ValidationMode, /// The table of file descriptors. pub(crate) fds: shims::FdTable, @@ -659,7 +645,7 @@ impl<'tcx> MiriMachine<'tcx> { cmd_line: None, tls: TlsData::default(), isolated_op: config.isolated_op, - validate: config.validate, + validation: config.validation, fds: shims::FdTable::init(config.mute_stdout_stderr), dirs: Default::default(), layouts, @@ -801,7 +787,7 @@ impl VisitProvenance for MiriMachine<'_> { fds, tcx: _, isolated_op: _, - validate: _, + validation: _, clock: _, layouts: _, static_roots: _, @@ -943,7 +929,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { #[inline(always)] fn enforce_validity(ecx: &MiriInterpCx<'tcx>, _layout: TyAndLayout<'tcx>) -> bool { - ecx.machine.validate + ecx.machine.validation != ValidationMode::No + } + #[inline(always)] + fn enforce_validity_recursively(ecx: &InterpCx<'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { + ecx.machine.validation == ValidationMode::Deep } #[inline(always)] diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs new file mode 100644 index 0000000000000..17b81f29cfe9a --- /dev/null +++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs @@ -0,0 +1,8 @@ +//@compile-flags: -Zmiri-recursive-validation + +fn main() { + let x = 3u8; + let xref = &x; + let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; //~ERROR: encountered 0x03, but expected a boolean + let _val = *xref_wrong_type; +} diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr new file mode 100644 index 0000000000000..2b2fa9b8a206d --- /dev/null +++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at .: encountered 0x03, but expected a boolean + --> $DIR/recursive-validity-ref-bool.rs:LL:CC + | +LL | let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x03, but expected a boolean + | + = 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 + = note: BACKTRACE: + = note: inside `main` at $DIR/recursive-validity-ref-bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 35977b47cc80e54af8e8559231945bada6fe1c01 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 29 Jul 2024 22:17:25 +0300 Subject: [PATCH 20/41] linker: Pass fewer search directories to the linker --- compiler/rustc_codegen_ssa/src/back/link.rs | 94 ++++++++++++--------- compiler/rustc_session/src/filesearch.rs | 5 ++ 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7d457526380d9..93ddd1ef04412 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2065,17 +2065,57 @@ fn add_local_crate_metadata_objects( } /// Add sysroot and other globally set directories to the directory search list. -fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) { - // The default library location, we need this to find the runtime. - // The location of crates will be determined as needed. - let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); - cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); +fn add_library_search_dirs( + cmd: &mut dyn Linker, + sess: &Session, + self_contained_components: LinkSelfContainedComponents, + apple_sdk_root: Option<&Path>, +) { + if !sess.opts.unstable_opts.link_native_libraries { + return; + } - // Special directory with libraries used only in self-contained linkage mode - if self_contained { - let lib_path = sess.target_filesearch(PathKind::All).get_self_contained_lib_path(); + // Library search paths explicitly supplied by user (`-L` on the command line). + for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() { + cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)); + } + for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() { + // Contrary to the `-L` docs only framework-specific paths are considered here. + if search_path.kind != PathKind::All { + cmd.framework_path(&search_path.dir); + } + } + + // The toolchain ships some native library components and self-contained linking was enabled. + // Add the self-contained library directory to search paths. + if self_contained_components.intersects( + LinkSelfContainedComponents::LIBC + | LinkSelfContainedComponents::UNWIND + | LinkSelfContainedComponents::MINGW, + ) { + let lib_path = sess.target_filesearch(PathKind::Native).get_self_contained_lib_path(); cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); } + + // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot + // library directory instead of the self-contained directories. + // The targets here should be in sync with `copy_third_party_objects` in bootstrap. + // FIXME: implement `-Clink-self-contained=+/-unwind`, move the shipped libunwind + // to self-contained directory, and stop adding this search path. + if sess.target.vendor == "fortanix" || sess.target.os == "linux" || sess.target.os == "fuchsia" + { + let lib_path = sess.target_filesearch(PathKind::Native).get_lib_path(); + cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); + } + + // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks + // we must have the support library stubs in the library search path (#121430). + if let Some(sdk_root) = apple_sdk_root + && sess.target.llvm_target.contains("macabi") + { + cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib")); + cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks")); + } } /// Add options making relocation sections in the produced ELF files read-only @@ -2367,7 +2407,7 @@ fn add_order_independent_options( // Take care of the flavors and CLI options requesting the `lld` linker. add_lld_args(cmd, sess, flavor, self_contained_components); - add_apple_sdk(cmd, sess, flavor); + let apple_sdk_root = add_apple_sdk(cmd, sess, flavor); add_link_script(cmd, sess, tmpdir, crate_type); @@ -2423,7 +2463,7 @@ fn add_order_independent_options( cmd.linker_plugin_lto(); - add_library_search_dirs(cmd, sess, self_contained_components.are_any_components_enabled()); + add_library_search_dirs(cmd, sess, self_contained_components, apple_sdk_root.as_deref()); cmd.output_filename(out_filename); @@ -2637,19 +2677,6 @@ fn add_local_native_libraries( tmpdir: &Path, link_output_kind: LinkOutputKind, ) { - if sess.opts.unstable_opts.link_native_libraries { - // User-supplied library search paths (-L on the command line). These are the same paths - // used to find Rust crates, so some of them may have been added already by the previous - // crate linking code. This only allows them to be found at compile time so it is still - // entirely up to outside forces to make sure that library can be found at runtime. - for search_path in sess.target_filesearch(PathKind::All).search_paths() { - match search_path.kind { - PathKind::Framework => cmd.framework_path(&search_path.dir), - _ => cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)), - } - } - } - // All static and dynamic native library dependencies are linked to the local crate. let link_static = true; let link_dynamic = true; @@ -2944,7 +2971,7 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool } } -fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { +fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option { let arch = &sess.target.arch; let os = &sess.target.os; let llvm_target = &sess.target.llvm_target; @@ -2952,11 +2979,11 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos") || !matches!(flavor, LinkerFlavor::Darwin(..)) { - return; + return None; } if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) { - return; + return None; } let sdk_name = match (arch.as_ref(), os.as_ref()) { @@ -2980,14 +3007,14 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { (_, "macos") => "macosx", _ => { sess.dcx().emit_err(errors::UnsupportedArch { arch, os }); - return; + return None; } }; let sdk_root = match get_apple_sdk_root(sdk_name) { Ok(s) => s, Err(e) => { sess.dcx().emit_err(e); - return; + return None; } }; @@ -3007,16 +3034,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { _ => unreachable!(), } - if llvm_target.contains("macabi") { - // Mac Catalyst uses the macOS SDK, but to link to iOS-specific - // frameworks, we must have the support library stubs in the library - // search path. - - // The flags are called `-L` and `-F` both in Clang, ld64 and ldd. - let sdk_root = Path::new(&sdk_root); - cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib")); - cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks")); - } + Some(sdk_root.into()) } fn get_apple_sdk_root(sdk_name: &str) -> Result> { diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 0c3ec36fed5a7..63ca5fefd9faf 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -19,6 +19,11 @@ pub struct FileSearch<'a> { } impl<'a> FileSearch<'a> { + pub fn cli_search_paths(&self) -> impl Iterator { + let kind = self.kind; + self.cli_search_paths.iter().filter(move |sp| sp.kind.matches(kind)) + } + pub fn search_paths(&self) -> impl Iterator { let kind = self.kind; self.cli_search_paths From 1f873f9cf1e6307d1f0bee85f7a866f9531b8a98 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 3 Aug 2024 14:18:55 +0300 Subject: [PATCH 21/41] Fix linking to sanitizers on Apple targets --- compiler/rustc_codegen_ssa/src/back/link.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 93ddd1ef04412..653895380bebc 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2099,10 +2099,14 @@ fn add_library_search_dirs( // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot // library directory instead of the self-contained directories. + // Sanitizer libraries have the same issue and are also linked by name on Apple targets. // The targets here should be in sync with `copy_third_party_objects` in bootstrap. - // FIXME: implement `-Clink-self-contained=+/-unwind`, move the shipped libunwind - // to self-contained directory, and stop adding this search path. - if sess.target.vendor == "fortanix" || sess.target.os == "linux" || sess.target.os == "fuchsia" + // FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind + // and sanitizers to self-contained directory, and stop adding this search path. + if sess.target.vendor == "fortanix" + || sess.target.os == "linux" + || sess.target.os == "fuchsia" + || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty() { let lib_path = sess.target_filesearch(PathKind::Native).get_lib_path(); cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); From 361ab1af0c74820ff74cd48dd7817c308da62642 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:28:57 -0400 Subject: [PATCH 22/41] Revert "Rollup merge of #128104 - mu001999-contrib:fix/128053, r=petrochenkov" This reverts commit 91b18a058c4661f82e420b633dc0a3e1ccd14b88, reversing changes made to 9aedec9313dc8ecf9bdcb5f09c4eb0ad8b9a4875. --- compiler/rustc_passes/src/dead.rs | 36 +++++++++---------- ...lone-debug-dead-code-in-the-same-struct.rs | 4 +-- ...-debug-dead-code-in-the-same-struct.stderr | 16 ++------- .../dead-code/unconstructible-pub-struct.rs | 35 ------------------ .../unconstructible-pub-struct.stderr | 14 -------- 5 files changed, 22 insertions(+), 83 deletions(-) delete mode 100644 tests/ui/lint/dead-code/unconstructible-pub-struct.rs delete mode 100644 tests/ui/lint/dead-code/unconstructible-pub-struct.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 8a931fc4158e3..3b1a796130c43 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -73,26 +73,24 @@ fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> { } fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool { - let adt_def = tcx.adt_def(id); - - // skip types contain fields of unit and never type, - // it's usually intentional to make the type not constructible - let not_require_constructor = adt_def.all_fields().any(|field| { + // treat PhantomData and positional ZST as public, + // we don't want to lint types which only have them, + // cause it's a common way to use such types to check things like well-formedness + tcx.adt_def(id).all_fields().all(|field| { let field_type = tcx.type_of(field.did).instantiate_identity(); - field_type.is_unit() || field_type.is_never() - }); - - not_require_constructor - || adt_def.all_fields().all(|field| { - let field_type = tcx.type_of(field.did).instantiate_identity(); - // skip fields of PhantomData, - // cause it's a common way to check things like well-formedness - if field_type.is_phantom_data() { - return true; - } - - field.vis.is_public() - }) + if field_type.is_phantom_data() { + return true; + } + let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit()); + if is_positional + && tcx + .layout_of(tcx.param_env(field.did).and(field_type)) + .map_or(true, |layout| layout.is_zst()) + { + return true; + } + field.vis.is_public() + }) } /// check struct and its fields are public or not, diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs index 6ab1fb7b039bd..885dacc727af6 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs @@ -1,9 +1,9 @@ #![forbid(dead_code)] #[derive(Debug)] -pub struct Whatever { +pub struct Whatever { //~ ERROR struct `Whatever` is never constructed pub field0: (), - field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read + field1: (), field2: (), field3: (), field4: (), diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr index e9b757b6bae72..e10d28ad03a4e 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr @@ -1,19 +1,9 @@ -error: fields `field1`, `field2`, `field3`, and `field4` are never read - --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5 +error: struct `Whatever` is never constructed + --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12 | LL | pub struct Whatever { - | -------- fields in this struct -LL | pub field0: (), -LL | field1: (), - | ^^^^^^ -LL | field2: (), - | ^^^^^^ -LL | field3: (), - | ^^^^^^ -LL | field4: (), - | ^^^^^^ + | ^^^^^^^^ | - = note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis note: the lint level is defined here --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11 | diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.rs b/tests/ui/lint/dead-code/unconstructible-pub-struct.rs deleted file mode 100644 index 2202cbb673098..0000000000000 --- a/tests/ui/lint/dead-code/unconstructible-pub-struct.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![feature(never_type)] -#![deny(dead_code)] - -pub struct T1(!); -pub struct T2(()); -pub struct T3(std::marker::PhantomData); - -pub struct T4 { - _x: !, -} - -pub struct T5 { - _x: !, - _y: X, -} - -pub struct T6 { - _x: (), -} - -pub struct T7 { - _x: (), - _y: X, -} - -pub struct T8 { - _x: std::marker::PhantomData, -} - -pub struct T9 { //~ ERROR struct `T9` is never constructed - _x: std::marker::PhantomData, - _y: i32, -} - -fn main() {} diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr b/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr deleted file mode 100644 index a3dde042bbe15..0000000000000 --- a/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: struct `T9` is never constructed - --> $DIR/unconstructible-pub-struct.rs:30:12 - | -LL | pub struct T9 { - | ^^ - | -note: the lint level is defined here - --> $DIR/unconstructible-pub-struct.rs:2:9 - | -LL | #![deny(dead_code)] - | ^^^^^^^^^ - -error: aborting due to 1 previous error - From c6b6c1270a25ee05c4e1f6a9daaf48ef60317f2c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:28:58 -0400 Subject: [PATCH 23/41] Revert "Rollup merge of #127017 - mu001999-contrib:dead/enhance, r=pnkfelix" This reverts commit a70dc297a899b76793a14c5705f6ec78fd7a57a7, reversing changes made to ceae37188b9f1be527bb16c9d657a161be7dbbe3. --- compiler/rustc_passes/src/dead.rs | 32 +++++-------- .../dead-code/unused-impl-for-non-adts.rs | 45 ------------------- .../dead-code/unused-impl-for-non-adts.stderr | 20 --------- 3 files changed, 10 insertions(+), 87 deletions(-) delete mode 100644 tests/ui/lint/dead-code/unused-impl-for-non-adts.rs delete mode 100644 tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 3b1a796130c43..9c475c9fbf462 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -55,24 +55,7 @@ impl Publicness { } } -fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> { - match ty.kind { - TyKind::Path(hir::QPath::Resolved(_, path)) => { - if let Res::Def(def_kind, def_id) = path.res - && let Some(local_def_id) = def_id.as_local() - { - Some((local_def_id, def_kind)) - } else { - None - } - } - TyKind::Slice(ty) | TyKind::Array(ty, _) => adt_of(ty), - TyKind::Ptr(ty) | TyKind::Ref(_, ty) => adt_of(ty.ty), - _ => None, - } -} - -fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool { +fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { // treat PhantomData and positional ZST as public, // we don't want to lint types which only have them, // cause it's a common way to use such types to check things like well-formedness @@ -97,7 +80,10 @@ fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool { /// for enum and union, just check they are public, /// and doesn't solve types like &T for now, just skip them fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { - if let Some((def_id, def_kind)) = adt_of(ty) { + if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind + && let Res::Def(def_kind, def_id) = path.res + && def_id.is_local() + { return match def_kind { DefKind::Enum | DefKind::Union => { let ty_is_public = tcx.visibility(def_id).is_public(); @@ -580,8 +566,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool { - if let Some((local_def_id, def_kind)) = - adt_of(self.tcx.hir().item(impl_id).expect_impl().self_ty) + if let TyKind::Path(hir::QPath::Resolved(_, path)) = + self.tcx.hir().item(impl_id).expect_impl().self_ty.kind + && let Res::Def(def_kind, def_id) = path.res + && let Some(local_def_id) = def_id.as_local() && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id @@ -928,7 +916,7 @@ fn create_and_seed_worklist( match tcx.def_kind(id) { DefKind::Impl { .. } => false, DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), + DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) .map(|id| (id, ComesFromAllowExpect::No)) diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs b/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs deleted file mode 100644 index 46065dcee81e0..0000000000000 --- a/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![deny(dead_code)] - -struct Foo; //~ ERROR struct `Foo` is never constructed - -trait Trait { //~ ERROR trait `Trait` is never used - fn foo(&self) {} -} - -impl Trait for Foo {} - -impl Trait for [Foo] {} -impl Trait for [Foo; N] {} - -impl Trait for *const Foo {} -impl Trait for *mut Foo {} - -impl Trait for &Foo {} -impl Trait for &&Foo {} -impl Trait for &mut Foo {} - -impl Trait for [&Foo] {} -impl Trait for &[Foo] {} -impl Trait for &*const Foo {} - -pub trait Trait2 { - fn foo(&self) {} -} - -impl Trait2 for Foo {} - -impl Trait2 for [Foo] {} -impl Trait2 for [Foo; N] {} - -impl Trait2 for *const Foo {} -impl Trait2 for *mut Foo {} - -impl Trait2 for &Foo {} -impl Trait2 for &&Foo {} -impl Trait2 for &mut Foo {} - -impl Trait2 for [&Foo] {} -impl Trait2 for &[Foo] {} -impl Trait2 for &*const Foo {} - -fn main() {} diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr b/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr deleted file mode 100644 index e61fc403e810d..0000000000000 --- a/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: struct `Foo` is never constructed - --> $DIR/unused-impl-for-non-adts.rs:3:8 - | -LL | struct Foo; - | ^^^ - | -note: the lint level is defined here - --> $DIR/unused-impl-for-non-adts.rs:1:9 - | -LL | #![deny(dead_code)] - | ^^^^^^^^^ - -error: trait `Trait` is never used - --> $DIR/unused-impl-for-non-adts.rs:5:7 - | -LL | trait Trait { - | ^^^^^ - -error: aborting due to 2 previous errors - From 5f5b4ee12859e9ba54a862a07c02be272be27d50 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:28:59 -0400 Subject: [PATCH 24/41] Revert "Rollup merge of #127107 - mu001999-contrib:dead/enhance-2, r=pnkfelix" This reverts commit 31fe9628cf830a08e7194a446f66c668aaea86e9, reversing changes made to f20307851ead9fbbb9fa88bbffb3258a069230a6. --- compiler/rustc_passes/src/dead.rs | 40 +++++++++++++------ library/core/src/default.rs | 1 + tests/ui-fulldeps/deriving-global.rs | 3 -- tests/ui-fulldeps/deriving-hygiene.rs | 1 - .../ui/const-generics/issues/issue-86535-2.rs | 1 - tests/ui/const-generics/issues/issue-86535.rs | 1 - .../impl-trait/extra-impl-in-trait-impl.fixed | 2 - .../ui/impl-trait/extra-impl-in-trait-impl.rs | 2 - .../extra-impl-in-trait-impl.stderr | 8 ++-- tests/ui/lint/dead-code/issue-59003.rs | 2 +- .../lint-unused-adt-appeared-in-pattern.rs | 37 ----------------- ...lint-unused-adt-appeared-in-pattern.stderr | 20 ---------- .../not-lint-used-adt-appeared-in-pattern.rs | 32 --------------- ...sed-adt-impl-pub-trait-with-assoc-const.rs | 36 ++++++----------- ...adt-impl-pub-trait-with-assoc-const.stderr | 24 ++--------- .../dead-code/unused-struct-derive-default.rs | 1 - .../unused-struct-derive-default.stderr | 1 + tests/ui/parser/issues/issue-105366.fixed | 1 - tests/ui/parser/issues/issue-105366.rs | 1 - tests/ui/parser/issues/issue-105366.stderr | 2 +- 20 files changed, 52 insertions(+), 164 deletions(-) delete mode 100644 tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs delete mode 100644 tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr delete mode 100644 tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 9c475c9fbf462..78fbcc1f40623 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -278,10 +278,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { pats: &[hir::PatField<'_>], ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => { - self.check_def_id(adt.did()); - adt.variant_of_res(res) - } + ty::Adt(adt, _) => adt.variant_of_res(res), _ => span_bug!(lhs.span, "non-ADT in struct pattern"), }; for pat in pats { @@ -301,10 +298,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { dotdot: hir::DotDotPos, ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => { - self.check_def_id(adt.did()); - adt.variant_of_res(res) - } + ty::Adt(adt, _) => adt.variant_of_res(res), _ => { self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern"); return; @@ -409,6 +403,31 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { return false; } + // don't ignore impls for Enums and pub Structs whose methods don't have self receiver, + // cause external crate may call such methods to construct values of these types + if let Some(local_impl_of) = impl_of.as_local() + && let Some(local_def_id) = def_id.as_local() + && let Some(fn_sig) = + self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id)) + && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None) + && let TyKind::Path(hir::QPath::Resolved(_, path)) = + self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind + && let Res::Def(def_kind, did) = path.res + { + match def_kind { + // for example, #[derive(Default)] pub struct T(i32); + // external crate can call T::default() to construct T, + // so that don't ignore impl Default for pub Enum and Structs + DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => { + return false; + } + // don't ignore impl Default for Enums, + // cause we don't know which variant is constructed + DefKind::Enum => return false, + _ => (), + }; + } + if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { @@ -672,9 +691,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.handle_field_pattern_match(pat, res, fields); } PatKind::Path(ref qpath) => { - if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() { - self.check_def_id(adt.did()); - } let res = self.typeck_results().qpath_res(qpath, pat.hir_id); self.handle_res(res); } @@ -830,7 +846,7 @@ fn check_item<'tcx>( // mark the method live if the self_ty is public, // or the method is public and may construct self if tcx.visibility(local_def_id).is_public() - && (ty_and_all_fields_are_public || (ty_is_public && may_construct_self)) + && (ty_and_all_fields_are_public || may_construct_self) { // if the impl item is public, // and the ty may be constructed or can be constructed in foreign crates, diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 4524b352ec817..5cacedcb241a5 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -103,6 +103,7 @@ use crate::ascii::Char as AsciiChar; /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "Default")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)] pub trait Default: Sized { /// Returns the "default value" for a type. /// diff --git a/tests/ui-fulldeps/deriving-global.rs b/tests/ui-fulldeps/deriving-global.rs index 0ba149c9ad654..7783010be441d 100644 --- a/tests/ui-fulldeps/deriving-global.rs +++ b/tests/ui-fulldeps/deriving-global.rs @@ -17,21 +17,18 @@ mod submod { // if any of these are implemented without global calls for any // function calls, then being in a submodule will (correctly) // cause errors about unrecognised module `std` (or `extra`) - #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] enum A { A1(usize), A2(isize), } - #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] struct B { x: usize, y: isize, } - #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] struct C(usize, isize); } diff --git a/tests/ui-fulldeps/deriving-hygiene.rs b/tests/ui-fulldeps/deriving-hygiene.rs index f948d6ac544e5..a3a6f9e022ebb 100644 --- a/tests/ui-fulldeps/deriving-hygiene.rs +++ b/tests/ui-fulldeps/deriving-hygiene.rs @@ -20,7 +20,6 @@ pub const s: u8 = 1; pub const state: u8 = 1; pub const cmp: u8 = 1; -#[allow(dead_code)] #[derive(Ord, Eq, PartialOrd, PartialEq, Debug, Decodable, Encodable, Hash)] struct Foo {} diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs index ab68c6b78df34..8d064f3eeb1b7 100644 --- a/tests/ui/const-generics/issues/issue-86535-2.rs +++ b/tests/ui/const-generics/issues/issue-86535-2.rs @@ -9,7 +9,6 @@ pub trait Foo { [(); Self::ASSOC_C]:; } -#[allow(dead_code)] struct Bar; impl Foo for Bar { const ASSOC_C: usize = 3; diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs index 9aaf7ddc9e86e..62454f4a388a0 100644 --- a/tests/ui/const-generics/issues/issue-86535.rs +++ b/tests/ui/const-generics/issues/issue-86535.rs @@ -2,7 +2,6 @@ #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features, unused_variables)] -#[allow(dead_code)] struct F; impl X for F<{ S }> { const W: usize = 3; diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed index 3c4499f017337..886fc1d005802 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed @@ -1,8 +1,6 @@ //@ run-rustfix -#[allow(dead_code)] struct S(T); -#[allow(dead_code)] struct S2; impl Default for S { diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs index ac0783295242e..f3271993867cb 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs @@ -1,8 +1,6 @@ //@ run-rustfix -#[allow(dead_code)] struct S(T); -#[allow(dead_code)] struct S2; impl impl Default for S { diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr index 91c7da5a04fb4..5aafc8b64d4ff 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr @@ -1,23 +1,23 @@ error: unexpected `impl` keyword - --> $DIR/extra-impl-in-trait-impl.rs:8:18 + --> $DIR/extra-impl-in-trait-impl.rs:6:18 | LL | impl impl Default for S { | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position - --> $DIR/extra-impl-in-trait-impl.rs:8:18 + --> $DIR/extra-impl-in-trait-impl.rs:6:18 | LL | impl impl Default for S { | ^^^^^^^^^^^^ error: unexpected `impl` keyword - --> $DIR/extra-impl-in-trait-impl.rs:14:6 + --> $DIR/extra-impl-in-trait-impl.rs:12:6 | LL | impl impl Default for S2 { | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position - --> $DIR/extra-impl-in-trait-impl.rs:14:6 + --> $DIR/extra-impl-in-trait-impl.rs:12:6 | LL | impl impl Default for S2 { | ^^^^^^^^^^^^ diff --git a/tests/ui/lint/dead-code/issue-59003.rs b/tests/ui/lint/dead-code/issue-59003.rs index 319cf2db1495f..e3dcaca577889 100644 --- a/tests/ui/lint/dead-code/issue-59003.rs +++ b/tests/ui/lint/dead-code/issue-59003.rs @@ -4,8 +4,8 @@ #![deny(dead_code)] -#[allow(dead_code)] struct Foo { + #[allow(dead_code)] inner: u32, } diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs deleted file mode 100644 index 25777438456b6..0000000000000 --- a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![deny(dead_code)] - -struct Foo(u8); //~ ERROR struct `Foo` is never constructed - -enum Bar { //~ ERROR enum `Bar` is never used - Var1(u8), - Var2(u8), -} - -pub trait Tr1 { - fn f1() -> Self; -} - -impl Tr1 for Foo { - fn f1() -> Foo { - let f = Foo(0); - let Foo(tag) = f; - Foo(tag) - } -} - -impl Tr1 for Bar { - fn f1() -> Bar { - let b = Bar::Var1(0); - let b = if let Bar::Var1(_) = b { - Bar::Var1(0) - } else { - Bar::Var2(0) - }; - match b { - Bar::Var1(_) => Bar::Var2(0), - Bar::Var2(_) => Bar::Var1(0), - } - } -} - -fn main() {} diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr deleted file mode 100644 index 7c1a4b4597755..0000000000000 --- a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: struct `Foo` is never constructed - --> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8 - | -LL | struct Foo(u8); - | ^^^ - | -note: the lint level is defined here - --> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9 - | -LL | #![deny(dead_code)] - | ^^^^^^^^^ - -error: enum `Bar` is never used - --> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6 - | -LL | enum Bar { - | ^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs deleted file mode 100644 index 43a2e43190433..0000000000000 --- a/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ check-pass - -#![deny(dead_code)] - -#[repr(u8)] -#[derive(Copy, Clone, Debug)] -pub enum RecordField { - Target = 1, - Level, - Module, - File, - Line, - NumArgs, -} - -unsafe trait Pod {} - -#[repr(transparent)] -struct RecordFieldWrapper(RecordField); - -unsafe impl Pod for RecordFieldWrapper {} - -fn try_read(buf: &[u8]) -> T { - unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) } -} - -pub fn foo(buf: &[u8]) -> RecordField { - let RecordFieldWrapper(tag) = try_read(buf); - tag -} - -fn main() {} diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs index 658cc3d6c613a..bf2fc243e8194 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs @@ -1,9 +1,8 @@ #![deny(dead_code)] struct T1; //~ ERROR struct `T1` is never constructed -struct T2; //~ ERROR struct `T2` is never constructed -pub struct T3(i32); //~ ERROR struct `T3` is never constructed -pub struct T4(i32); //~ ERROR field `0` is never read +pub struct T2(i32); //~ ERROR struct `T2` is never constructed +struct T3; trait Trait1 { //~ ERROR trait `Trait1` is never used const UNUSED: i32; @@ -12,13 +11,13 @@ trait Trait1 { //~ ERROR trait `Trait1` is never used } pub trait Trait2 { - const MAY_USED: i32; - fn may_used(&self) {} + const USED: i32; + fn used(&self) {} } pub trait Trait3 { - const MAY_USED: i32; - fn may_used() -> Self; + const USED: i32; + fn construct_self() -> Self; } impl Trait1 for T1 { @@ -31,34 +30,23 @@ impl Trait1 for T1 { impl Trait1 for T2 { const UNUSED: i32 = 0; fn construct_self() -> Self { - Self + T2(0) } } impl Trait2 for T1 { - const MAY_USED: i32 = 0; + const USED: i32 = 0; } impl Trait2 for T2 { - const MAY_USED: i32 = 0; -} - -impl Trait2 for T3 { - const MAY_USED: i32 = 0; + const USED: i32 = 0; } -impl Trait3 for T2 { - const MAY_USED: i32 = 0; - fn may_used() -> Self { +impl Trait3 for T3 { + const USED: i32 = 0; + fn construct_self() -> Self { Self } } -impl Trait3 for T4 { - const MAY_USED: i32 = 0; - fn may_used() -> Self { - T4(0) - } -} - fn main() {} diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr index 08c7a5cb4b062..174096d939883 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr @@ -11,32 +11,16 @@ LL | #![deny(dead_code)] | ^^^^^^^^^ error: struct `T2` is never constructed - --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:8 + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:12 | -LL | struct T2; - | ^^ - -error: struct `T3` is never constructed - --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:12 - | -LL | pub struct T3(i32); +LL | pub struct T2(i32); | ^^ -error: field `0` is never read - --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:6:15 - | -LL | pub struct T4(i32); - | -- ^^^ - | | - | field in this struct - | - = help: consider removing this field - error: trait `Trait1` is never used - --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:8:7 + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7 | LL | trait Trait1 { | ^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.rs b/tests/ui/lint/dead-code/unused-struct-derive-default.rs index f20b7cb66ee51..330ad32dd5709 100644 --- a/tests/ui/lint/dead-code/unused-struct-derive-default.rs +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.rs @@ -22,5 +22,4 @@ pub struct T2 { fn main() { let _x: Used = Default::default(); - let _e: E = Default::default(); } diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr index 7422f9a39f312..bbb0bd7be7064 100644 --- a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr @@ -4,6 +4,7 @@ error: struct `T` is never constructed LL | struct T; | ^ | + = note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis note: the lint level is defined here --> $DIR/unused-struct-derive-default.rs:1:9 | diff --git a/tests/ui/parser/issues/issue-105366.fixed b/tests/ui/parser/issues/issue-105366.fixed index 95419dc07f2cc..7157b647524dd 100644 --- a/tests/ui/parser/issues/issue-105366.fixed +++ b/tests/ui/parser/issues/issue-105366.fixed @@ -1,6 +1,5 @@ //@ run-rustfix -#[allow(dead_code)] struct Foo; impl From for Foo { diff --git a/tests/ui/parser/issues/issue-105366.rs b/tests/ui/parser/issues/issue-105366.rs index 3278b73799125..dc3cb8b343d32 100644 --- a/tests/ui/parser/issues/issue-105366.rs +++ b/tests/ui/parser/issues/issue-105366.rs @@ -1,6 +1,5 @@ //@ run-rustfix -#[allow(dead_code)] struct Foo; fn From for Foo { diff --git a/tests/ui/parser/issues/issue-105366.stderr b/tests/ui/parser/issues/issue-105366.stderr index 195305a2ec889..18c04dfaf2088 100644 --- a/tests/ui/parser/issues/issue-105366.stderr +++ b/tests/ui/parser/issues/issue-105366.stderr @@ -1,5 +1,5 @@ error: you might have meant to write `impl` instead of `fn` - --> $DIR/issue-105366.rs:6:1 + --> $DIR/issue-105366.rs:5:1 | LL | fn From for Foo { | ^^ From 22da61624590a413c98df5087ff4454fcc618dbf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:29:01 -0400 Subject: [PATCH 25/41] Revert "Rollup merge of #126618 - mu001999-contrib:dead/enhance, r=pnkfelix" This reverts commit 2724aeaaeb127a8073e39461caacbe21a128ce7b, reversing changes made to d929a42a664c026167800801b26d734db925314f. --- compiler/rustc_passes/src/dead.rs | 41 ++++++++----------- .../ui/const-generics/cross_crate_complex.rs | 1 - .../missing-bounds.fixed | 4 -- .../missing-bounds.rs | 4 -- .../missing-bounds.stderr | 18 ++++---- .../dead-code/unused-trait-with-assoc-ty.rs | 11 ----- .../unused-trait-with-assoc-ty.stderr | 20 --------- tests/ui/pattern/issue-22546.rs | 2 +- tests/ui/pattern/issue-22546.stderr | 10 +++++ 9 files changed, 36 insertions(+), 75 deletions(-) delete mode 100644 tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs delete mode 100644 tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr create mode 100644 tests/ui/pattern/issue-22546.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 78fbcc1f40623..d4ce9b02473b0 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -156,10 +156,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn handle_res(&mut self, res: Res) { match res { - Res::Def( - DefKind::Const | DefKind::AssocConst | DefKind::AssocTy | DefKind::TyAlias, - def_id, - ) => { + Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => { self.check_def_id(def_id); } _ if self.in_pat => {} @@ -470,7 +467,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_item(self, item) } hir::ItemKind::ForeignMod { .. } => {} - hir::ItemKind::Trait(_, _, _, _, trait_item_refs) => { + hir::ItemKind::Trait(..) => { for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) { if let Some(local_def_id) = impl_def_id.as_local() && let ItemKind::Impl(impl_ref) = @@ -483,12 +480,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_path(self, impl_ref.of_trait.unwrap().path); } } - // mark assoc ty live if the trait is live - for trait_item in trait_item_refs { - if let hir::AssocItemKind::Type = trait_item.kind { - self.check_def_id(trait_item.id.owner_id.to_def_id()); - } - } + intravisit::walk_item(self, item) } _ => intravisit::walk_item(self, item), @@ -505,8 +497,9 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && let ItemKind::Impl(impl_ref) = self.tcx.hir().expect_item(local_impl_id).kind { - if !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) - .ty_and_all_fields_are_public + if !matches!(trait_item.kind, hir::TraitItemKind::Type(..)) + && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) + .ty_and_all_fields_are_public { // skip impl-items of non pure pub ty, // cause we don't know the ty is constructed or not, @@ -845,8 +838,9 @@ fn check_item<'tcx>( // for trait impl blocks, // mark the method live if the self_ty is public, // or the method is public and may construct self - if tcx.visibility(local_def_id).is_public() - && (ty_and_all_fields_are_public || may_construct_self) + if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy) + || tcx.visibility(local_def_id).is_public() + && (ty_and_all_fields_are_public || may_construct_self) { // if the impl item is public, // and the ty may be constructed or can be constructed in foreign crates, @@ -883,13 +877,10 @@ fn check_trait_item( worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>, id: hir::TraitItemId, ) { - use hir::TraitItemKind::{Const, Fn, Type}; - if matches!( - tcx.def_kind(id.owner_id), - DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn - ) { + use hir::TraitItemKind::{Const, Fn}; + if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Type(_, Some(_)) | Fn(..)) + if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..)) && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { @@ -931,7 +922,7 @@ fn create_and_seed_worklist( // checks impls, impl-items and pub structs with all public fields later match tcx.def_kind(id) { DefKind::Impl { .. } => false, - DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), + DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) @@ -1218,7 +1209,6 @@ impl<'tcx> DeadVisitor<'tcx> { } match self.tcx.def_kind(def_id) { DefKind::AssocConst - | DefKind::AssocTy | DefKind::AssocFn | DefKind::Fn | DefKind::Static { .. } @@ -1260,14 +1250,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) { for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { - // We have diagnosed unused assocs in traits + // We have diagnosed unused assoc consts and fns in traits if matches!(def_kind, DefKind::Impl { of_trait: true }) - && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn) + && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn) // skip unused public inherent methods, // cause we have diagnosed unconstructed struct || matches!(def_kind, DefKind::Impl { of_trait: false }) && tcx.visibility(def_id).is_public() && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public + || def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy { continue; } diff --git a/tests/ui/const-generics/cross_crate_complex.rs b/tests/ui/const-generics/cross_crate_complex.rs index b44d889f5e99e..d13b69aa0cfb4 100644 --- a/tests/ui/const-generics/cross_crate_complex.rs +++ b/tests/ui/const-generics/cross_crate_complex.rs @@ -11,7 +11,6 @@ async fn foo() { async_in_foo(async_out_foo::<4>().await).await; } -#[allow(dead_code)] struct Faz; impl Foo for Faz {} diff --git a/tests/ui/generic-associated-types/missing-bounds.fixed b/tests/ui/generic-associated-types/missing-bounds.fixed index ff69016d8626d..703d3c1e0fb17 100644 --- a/tests/ui/generic-associated-types/missing-bounds.fixed +++ b/tests/ui/generic-associated-types/missing-bounds.fixed @@ -2,7 +2,6 @@ use std::ops::Add; -#[allow(dead_code)] struct A(B); impl Add for A where B: Add { @@ -13,7 +12,6 @@ impl Add for A where B: Add { } } -#[allow(dead_code)] struct C(B); impl> Add for C { @@ -24,7 +22,6 @@ impl> Add for C { } } -#[allow(dead_code)] struct D(B); impl> Add for D { @@ -35,7 +32,6 @@ impl> Add for D { } } -#[allow(dead_code)] struct E(B); impl> Add for E where B: Add { diff --git a/tests/ui/generic-associated-types/missing-bounds.rs b/tests/ui/generic-associated-types/missing-bounds.rs index 1f83356c2fa6b..f40b422887311 100644 --- a/tests/ui/generic-associated-types/missing-bounds.rs +++ b/tests/ui/generic-associated-types/missing-bounds.rs @@ -2,7 +2,6 @@ use std::ops::Add; -#[allow(dead_code)] struct A(B); impl Add for A where B: Add { @@ -13,7 +12,6 @@ impl Add for A where B: Add { } } -#[allow(dead_code)] struct C(B); impl Add for C { @@ -24,7 +22,6 @@ impl Add for C { } } -#[allow(dead_code)] struct D(B); impl Add for D { @@ -35,7 +32,6 @@ impl Add for D { } } -#[allow(dead_code)] struct E(B); impl Add for E where ::Output = B { diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr index 0f0dc24c06c0f..1d7d80d1b0768 100644 --- a/tests/ui/generic-associated-types/missing-bounds.stderr +++ b/tests/ui/generic-associated-types/missing-bounds.stderr @@ -1,5 +1,5 @@ error: equality constraints are not yet supported in `where` clauses - --> $DIR/missing-bounds.rs:41:33 + --> $DIR/missing-bounds.rs:37:33 | LL | impl Add for E where ::Output = B { | ^^^^^^^^^^^^^^^^^^^^^^ not supported @@ -11,7 +11,7 @@ LL | impl Add for E where B: Add { | ~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:12:11 + --> $DIR/missing-bounds.rs:11:11 | LL | impl Add for A where B: Add { | - expected this type parameter @@ -24,14 +24,14 @@ LL | A(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` help: the type constructed contains `::Output` due to the type of the argument passed - --> $DIR/missing-bounds.rs:12:9 + --> $DIR/missing-bounds.rs:11:9 | LL | A(self.0 + rhs.0) | ^^--------------^ | | | this argument influences the type of `A` note: tuple struct defined here - --> $DIR/missing-bounds.rs:6:8 + --> $DIR/missing-bounds.rs:5:8 | LL | struct A(B); | ^ @@ -41,7 +41,7 @@ LL | impl Add for A where B: Add { | ++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:23:14 + --> $DIR/missing-bounds.rs:21:14 | LL | impl Add for C { | - expected this type parameter @@ -54,7 +54,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:17:8 + --> $DIR/missing-bounds.rs:15:8 | LL | struct C(B); | ^ @@ -64,7 +64,7 @@ LL | impl> Add for C { | ++++++++++++ error[E0369]: cannot add `B` to `B` - --> $DIR/missing-bounds.rs:34:21 + --> $DIR/missing-bounds.rs:31:21 | LL | Self(self.0 + rhs.0) | ------ ^ ----- B @@ -77,7 +77,7 @@ LL | impl> Add for D { | +++++++++++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:46:14 + --> $DIR/missing-bounds.rs:42:14 | LL | impl Add for E where ::Output = B { | - expected this type parameter @@ -90,7 +90,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:39:8 + --> $DIR/missing-bounds.rs:35:8 | LL | struct E(B); | ^ diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs deleted file mode 100644 index e8116d83ebf1c..0000000000000 --- a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![deny(dead_code)] - -struct T1; //~ ERROR struct `T1` is never constructed - -trait Foo { type Unused; } //~ ERROR trait `Foo` is never used -impl Foo for T1 { type Unused = Self; } - -pub trait Bar { type Used; } -impl Bar for T1 { type Used = Self; } - -fn main() {} diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr deleted file mode 100644 index ab73c64063431..0000000000000 --- a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: struct `T1` is never constructed - --> $DIR/unused-trait-with-assoc-ty.rs:3:8 - | -LL | struct T1; - | ^^ - | -note: the lint level is defined here - --> $DIR/unused-trait-with-assoc-ty.rs:1:9 - | -LL | #![deny(dead_code)] - | ^^^^^^^^^ - -error: trait `Foo` is never used - --> $DIR/unused-trait-with-assoc-ty.rs:5:7 - | -LL | trait Foo { type Unused; } - | ^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs index d5c5b68be78d7..fd1d5fb6c4775 100644 --- a/tests/ui/pattern/issue-22546.rs +++ b/tests/ui/pattern/issue-22546.rs @@ -15,7 +15,7 @@ impl Foo { } } -trait Tr { +trait Tr { //~ WARN trait `Tr` is never used type U; } diff --git a/tests/ui/pattern/issue-22546.stderr b/tests/ui/pattern/issue-22546.stderr new file mode 100644 index 0000000000000..e067a95e4226c --- /dev/null +++ b/tests/ui/pattern/issue-22546.stderr @@ -0,0 +1,10 @@ +warning: trait `Tr` is never used + --> $DIR/issue-22546.rs:18:7 + | +LL | trait Tr { + | ^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + From d29818c9f552d6941bc00770e7aa1e2768e02e07 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:29:02 -0400 Subject: [PATCH 26/41] Revert "Rollup merge of #126315 - mu001999-contrib:fix/126289, r=petrochenkov" This reverts commit 977c5fd419ade52467f7de79d5bfc25c0c893275, reversing changes made to 24c94f0e4f5aa333c665fbbba423172c30176624. --- compiler/rustc_passes/src/dead.rs | 2 +- .../allow-unconstructed-pub-struct.rs | 33 ------------------- 2 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d4ce9b02473b0..90f436a6fc1ae 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -923,7 +923,7 @@ fn create_and_seed_worklist( match tcx.def_kind(id) { DefKind::Impl { .. } => false, DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), + DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()), _ => true }) .map(|id| (id, ComesFromAllowExpect::No)) diff --git a/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs deleted file mode 100644 index 8cd1524045b15..0000000000000 --- a/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ check-pass - -mod ffi { - use super::*; - - extern "C" { - pub fn DomPromise_AddRef(promise: *const Promise); - pub fn DomPromise_Release(promise: *const Promise); - } -} - -#[repr(C)] -#[allow(unused)] -pub struct Promise { - private: [u8; 0], - __nosync: ::std::marker::PhantomData<::std::rc::Rc>, -} - -pub unsafe trait RefCounted { - unsafe fn addref(&self); - unsafe fn release(&self); -} - -unsafe impl RefCounted for Promise { - unsafe fn addref(&self) { - ffi::DomPromise_AddRef(self) - } - unsafe fn release(&self) { - ffi::DomPromise_Release(self) - } -} - -fn main() {} From ac56007ea7ba6f5bdf9c018f6561617fc5626e3d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:29:20 -0400 Subject: [PATCH 27/41] Revert "Rollup merge of #125572 - mu001999-contrib:dead/enhance, r=pnkfelix" This reverts commit 13314df21b0bb0cdd02c6760581d1b9f1052fa7e, reversing changes made to 6e534c73c35f569492ed5fb5f349075d58ed8b7e. --- compiler/rustc_passes/src/dead.rs | 121 ++++-------------- .../item-collection/generic-impl.rs | 10 +- .../item-collection/overloaded-operators.rs | 24 ++-- tests/ui/coherence/re-rebalance-coherence.rs | 1 - .../defaults/repr-c-issue-82792.rs | 1 - .../generic_const_exprs/associated-consts.rs | 3 +- .../transparent-maybeunit-array-wrapper.rs | 1 - ...lone-debug-dead-code-in-the-same-struct.rs | 4 +- ...-debug-dead-code-in-the-same-struct.stderr | 16 ++- tests/ui/issues/issue-5708.rs | 1 - tests/ui/lint/dead-code/lint-dead-code-1.rs | 5 +- .../ui/lint/dead-code/lint-dead-code-1.stderr | 26 +--- tests/ui/lint/dead-code/unused-assoc-const.rs | 20 --- .../lint/dead-code/unused-assoc-const.stderr | 16 --- tests/ui/lint/dead-code/unused-pub-struct.rs | 48 ------- .../lint/dead-code/unused-pub-struct.stderr | 14 -- ...re-clause-before-tuple-struct-body-0.fixed | 3 +- ...where-clause-before-tuple-struct-body-0.rs | 3 +- ...e-clause-before-tuple-struct-body-0.stderr | 10 +- tests/ui/pub/pub-ident-struct-4.fixed | 3 +- tests/ui/pub/pub-ident-struct-4.rs | 3 +- tests/ui/pub/pub-ident-struct-4.stderr | 8 +- tests/ui/regions/regions-issue-21422.rs | 1 - .../structs-enums/newtype-struct-with-dtor.rs | 2 - .../ui/structs-enums/uninstantiable-struct.rs | 3 +- .../ui/suggestions/derive-clone-for-eq.fixed | 1 - tests/ui/suggestions/derive-clone-for-eq.rs | 1 - .../ui/suggestions/derive-clone-for-eq.stderr | 4 +- .../ui/suggestions/option-content-move.fixed | 2 - tests/ui/suggestions/option-content-move.rs | 2 - .../ui/suggestions/option-content-move.stderr | 4 +- tests/ui/traits/object/generics.rs | 1 - 32 files changed, 89 insertions(+), 273 deletions(-) delete mode 100644 tests/ui/lint/dead-code/unused-assoc-const.rs delete mode 100644 tests/ui/lint/dead-code/unused-assoc-const.stderr delete mode 100644 tests/ui/lint/dead-code/unused-pub-struct.rs delete mode 100644 tests/ui/lint/dead-code/unused-pub-struct.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 90f436a6fc1ae..7ae5c9040042c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -17,7 +17,7 @@ use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, AssocItemContainer, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; @@ -44,63 +44,16 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { ) } -struct Publicness { - ty_is_public: bool, - ty_and_all_fields_are_public: bool, -} - -impl Publicness { - fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self { - Self { ty_is_public, ty_and_all_fields_are_public } - } -} - -fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { - // treat PhantomData and positional ZST as public, - // we don't want to lint types which only have them, - // cause it's a common way to use such types to check things like well-formedness - tcx.adt_def(id).all_fields().all(|field| { - let field_type = tcx.type_of(field.did).instantiate_identity(); - if field_type.is_phantom_data() { - return true; - } - let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit()); - if is_positional - && tcx - .layout_of(tcx.param_env(field.did).and(field_type)) - .map_or(true, |layout| layout.is_zst()) - { - return true; - } - field.vis.is_public() - }) -} - -/// check struct and its fields are public or not, -/// for enum and union, just check they are public, -/// and doesn't solve types like &T for now, just skip them -fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { +fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool { if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind && let Res::Def(def_kind, def_id) = path.res && def_id.is_local() + && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { - return match def_kind { - DefKind::Enum | DefKind::Union => { - let ty_is_public = tcx.visibility(def_id).is_public(); - Publicness::new(ty_is_public, ty_is_public) - } - DefKind::Struct => { - let ty_is_public = tcx.visibility(def_id).is_public(); - Publicness::new( - ty_is_public, - ty_is_public && struct_all_fields_are_public(tcx, def_id), - ) - } - _ => Publicness::new(true, true), - }; + tcx.visibility(def_id).is_public() + } else { + true } - - Publicness::new(true, true) } /// Determine if a work from the worklist is coming from a `#[allow]` @@ -499,11 +452,9 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { { if !matches!(trait_item.kind, hir::TraitItemKind::Type(..)) && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) - .ty_and_all_fields_are_public { - // skip impl-items of non pure pub ty, - // cause we don't know the ty is constructed or not, - // check these later in `solve_rest_impl_items` + // skip methods of private ty, + // they would be solved in `solve_rest_impl_items` continue; } @@ -584,21 +535,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && let Some(local_def_id) = def_id.as_local() && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { + if self.tcx.visibility(impl_item_id).is_public() { + // for the public method, we don't know the trait item is used or not, + // so we mark the method live if the self is used + return self.live_symbols.contains(&local_def_id); + } + if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id && let Some(local_id) = trait_item_id.as_local() { - // for the local impl item, we can know the trait item is used or not, + // for the private method, we can know the trait item is used or not, // so we mark the method live if the self is used and the trait item is used - self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id) - } else { - // for the foreign method and inherent pub method, - // we don't know the trait item or the method is used or not, - // so we mark the method live if the self is used - self.live_symbols.contains(&local_def_id) + return self.live_symbols.contains(&local_id) + && self.live_symbols.contains(&local_def_id); } - } else { - false } + false } } @@ -820,9 +772,7 @@ fn check_item<'tcx>( .iter() .filter_map(|def_id| def_id.as_local()); - let self_ty = tcx.hir().item(id).expect_impl().self_ty; - let Publicness { ty_is_public, ty_and_all_fields_are_public } = - ty_ref_to_pub_struct(tcx, self_ty); + let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty); // And we access the Map here to get HirId from LocalDefId for local_def_id in local_def_ids { @@ -838,20 +788,18 @@ fn check_item<'tcx>( // for trait impl blocks, // mark the method live if the self_ty is public, // or the method is public and may construct self - if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy) - || tcx.visibility(local_def_id).is_public() - && (ty_and_all_fields_are_public || may_construct_self) + if of_trait + && (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn) + || tcx.visibility(local_def_id).is_public() + && (ty_is_pub || may_construct_self)) { - // if the impl item is public, - // and the ty may be constructed or can be constructed in foreign crates, - // mark the impl item live worklist.push((local_def_id, ComesFromAllowExpect::No)); } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, local_def_id) { worklist.push((local_def_id, comes_from_allow)); - } else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public { - // private impl items of traits || public impl items not constructs self + } else if of_trait { + // private method || public method not constructs self unsolved_impl_items.push((id, local_def_id)); } } @@ -918,14 +866,6 @@ fn create_and_seed_worklist( effective_vis .is_public_at_level(Level::Reachable) .then_some(id) - .filter(|&id| - // checks impls, impl-items and pub structs with all public fields later - match tcx.def_kind(id) { - DefKind::Impl { .. } => false, - DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()), - _ => true - }) .map(|id| (id, ComesFromAllowExpect::No)) }) // Seed entry point @@ -1250,15 +1190,10 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) { for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { - // We have diagnosed unused assoc consts and fns in traits + // We have diagnosed unused methods in traits if matches!(def_kind, DefKind::Impl { of_trait: true }) - && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn) - // skip unused public inherent methods, - // cause we have diagnosed unconstructed struct - || matches!(def_kind, DefKind::Impl { of_trait: false }) - && tcx.visibility(def_id).is_public() - && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public - || def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy + && tcx.def_kind(def_id) == DefKind::AssocFn + || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn { continue; } diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs index b4cd99272b152..23d09e0d8af3e 100644 --- a/tests/codegen-units/item-collection/generic-impl.rs +++ b/tests/codegen-units/item-collection/generic-impl.rs @@ -22,16 +22,16 @@ impl Struct { } } -pub struct _LifeTimeOnly<'a> { +pub struct LifeTimeOnly<'a> { _a: &'a u32, } -impl<'a> _LifeTimeOnly<'a> { - //~ MONO_ITEM fn _LifeTimeOnly::<'_>::foo +impl<'a> LifeTimeOnly<'a> { + //~ MONO_ITEM fn LifeTimeOnly::<'_>::foo pub fn foo(&self) {} - //~ MONO_ITEM fn _LifeTimeOnly::<'_>::bar + //~ MONO_ITEM fn LifeTimeOnly::<'_>::bar pub fn bar(&'a self) {} - //~ MONO_ITEM fn _LifeTimeOnly::<'_>::baz + //~ MONO_ITEM fn LifeTimeOnly::<'_>::baz pub fn baz<'b>(&'b self) {} pub fn non_instantiated(&self) {} diff --git a/tests/codegen-units/item-collection/overloaded-operators.rs b/tests/codegen-units/item-collection/overloaded-operators.rs index e00e22dbab996..69b55695d3d30 100644 --- a/tests/codegen-units/item-collection/overloaded-operators.rs +++ b/tests/codegen-units/item-collection/overloaded-operators.rs @@ -5,44 +5,44 @@ use std::ops::{Add, Deref, Index, IndexMut}; -pub struct _Indexable { +pub struct Indexable { data: [u8; 3], } -impl Index for _Indexable { +impl Index for Indexable { type Output = u8; - //~ MONO_ITEM fn <_Indexable as std::ops::Index>::index + //~ MONO_ITEM fn >::index fn index(&self, index: usize) -> &Self::Output { if index >= 3 { &self.data[0] } else { &self.data[index] } } } -impl IndexMut for _Indexable { - //~ MONO_ITEM fn <_Indexable as std::ops::IndexMut>::index_mut +impl IndexMut for Indexable { + //~ MONO_ITEM fn >::index_mut fn index_mut(&mut self, index: usize) -> &mut Self::Output { if index >= 3 { &mut self.data[0] } else { &mut self.data[index] } } } -//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::eq -//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::ne +//~ MONO_ITEM fn ::eq +//~ MONO_ITEM fn ::ne #[derive(PartialEq)] -pub struct _Equatable(u32); +pub struct Equatable(u32); -impl Add for _Equatable { +impl Add for Equatable { type Output = u32; - //~ MONO_ITEM fn <_Equatable as std::ops::Add>::add + //~ MONO_ITEM fn >::add fn add(self, rhs: u32) -> u32 { self.0 + rhs } } -impl Deref for _Equatable { +impl Deref for Equatable { type Target = u32; - //~ MONO_ITEM fn <_Equatable as std::ops::Deref>::deref + //~ MONO_ITEM fn ::deref fn deref(&self) -> &Self::Target { &self.0 } diff --git a/tests/ui/coherence/re-rebalance-coherence.rs b/tests/ui/coherence/re-rebalance-coherence.rs index 5383a634617f4..9c176d5b1b12b 100644 --- a/tests/ui/coherence/re-rebalance-coherence.rs +++ b/tests/ui/coherence/re-rebalance-coherence.rs @@ -4,7 +4,6 @@ extern crate re_rebalance_coherence_lib as lib; use lib::*; -#[allow(dead_code)] struct Oracle; impl Backend for Oracle {} impl<'a, T:'a, Tab> QueryFragment for BatchInsert<'a, T, Tab> {} diff --git a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs index 4bf2fa761eae8..c23187598bceb 100644 --- a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs +++ b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs @@ -2,7 +2,6 @@ //@ run-pass -#[allow(dead_code)] #[repr(C)] pub struct Loaf { head: [T; N], diff --git a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs index 50a6102c605a9..5d2198f50ad92 100644 --- a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs +++ b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs @@ -16,8 +16,7 @@ impl BlockCipher for BarCipher { const BLOCK_SIZE: usize = 32; } -#[allow(dead_code)] -pub struct Block(C); +pub struct Block(#[allow(dead_code)] C); pub fn test() where diff --git a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs index 35c41ae461520..419d605d0c875 100644 --- a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs +++ b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs @@ -6,7 +6,6 @@ use std::mem::MaybeUninit; -#[allow(dead_code)] #[repr(transparent)] pub struct MaybeUninitWrapper(MaybeUninit<[u64; N]>); diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs index 885dacc727af6..6ab1fb7b039bd 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs @@ -1,9 +1,9 @@ #![forbid(dead_code)] #[derive(Debug)] -pub struct Whatever { //~ ERROR struct `Whatever` is never constructed +pub struct Whatever { pub field0: (), - field1: (), + field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read field2: (), field3: (), field4: (), diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr index e10d28ad03a4e..e9b757b6bae72 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr @@ -1,9 +1,19 @@ -error: struct `Whatever` is never constructed - --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12 +error: fields `field1`, `field2`, `field3`, and `field4` are never read + --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5 | LL | pub struct Whatever { - | ^^^^^^^^ + | -------- fields in this struct +LL | pub field0: (), +LL | field1: (), + | ^^^^^^ +LL | field2: (), + | ^^^^^^ +LL | field3: (), + | ^^^^^^ +LL | field4: (), + | ^^^^^^ | + = note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis note: the lint level is defined here --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11 | diff --git a/tests/ui/issues/issue-5708.rs b/tests/ui/issues/issue-5708.rs index 89ea9fbdcd8fe..ce9ef78ffcd9c 100644 --- a/tests/ui/issues/issue-5708.rs +++ b/tests/ui/issues/issue-5708.rs @@ -44,7 +44,6 @@ pub trait MyTrait { fn dummy(&self, t: T) -> T { panic!() } } -#[allow(dead_code)] pub struct MyContainer<'a, T:'a> { foos: Vec<&'a (dyn MyTrait+'a)> , } diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.rs b/tests/ui/lint/dead-code/lint-dead-code-1.rs index 3386dfa47470f..ddcafedf7bc5f 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-1.rs +++ b/tests/ui/lint/dead-code/lint-dead-code-1.rs @@ -46,10 +46,11 @@ struct SemiUsedStruct; impl SemiUsedStruct { fn la_la_la() {} } -struct StructUsedAsField; //~ ERROR struct `StructUsedAsField` is never constructed +struct StructUsedAsField; pub struct StructUsedInEnum; struct StructUsedInGeneric; -pub struct PubStruct2 { //~ ERROR struct `PubStruct2` is never constructed +pub struct PubStruct2 { + #[allow(dead_code)] struct_used_as_field: *const StructUsedAsField } diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.stderr b/tests/ui/lint/dead-code/lint-dead-code-1.stderr index b0163df8855cd..eb728b5b93055 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-1.stderr +++ b/tests/ui/lint/dead-code/lint-dead-code-1.stderr @@ -22,26 +22,14 @@ error: struct `PrivStruct` is never constructed LL | struct PrivStruct; | ^^^^^^^^^^ -error: struct `StructUsedAsField` is never constructed - --> $DIR/lint-dead-code-1.rs:49:8 - | -LL | struct StructUsedAsField; - | ^^^^^^^^^^^^^^^^^ - -error: struct `PubStruct2` is never constructed - --> $DIR/lint-dead-code-1.rs:52:12 - | -LL | pub struct PubStruct2 { - | ^^^^^^^^^^ - error: enum `priv_enum` is never used - --> $DIR/lint-dead-code-1.rs:63:6 + --> $DIR/lint-dead-code-1.rs:64:6 | LL | enum priv_enum { foo2, bar2 } | ^^^^^^^^^ error: variant `bar3` is never constructed - --> $DIR/lint-dead-code-1.rs:66:5 + --> $DIR/lint-dead-code-1.rs:67:5 | LL | enum used_enum { | --------- variant in this enum @@ -50,25 +38,25 @@ LL | bar3 | ^^^^ error: function `priv_fn` is never used - --> $DIR/lint-dead-code-1.rs:87:4 + --> $DIR/lint-dead-code-1.rs:88:4 | LL | fn priv_fn() { | ^^^^^^^ error: function `foo` is never used - --> $DIR/lint-dead-code-1.rs:92:4 + --> $DIR/lint-dead-code-1.rs:93:4 | LL | fn foo() { | ^^^ error: function `bar` is never used - --> $DIR/lint-dead-code-1.rs:97:4 + --> $DIR/lint-dead-code-1.rs:98:4 | LL | fn bar() { | ^^^ error: function `baz` is never used - --> $DIR/lint-dead-code-1.rs:101:4 + --> $DIR/lint-dead-code-1.rs:102:4 | LL | fn baz() -> impl Copy { | ^^^ @@ -79,5 +67,5 @@ error: struct `Bar` is never constructed LL | pub struct Bar; | ^^^ -error: aborting due to 12 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/lint/dead-code/unused-assoc-const.rs b/tests/ui/lint/dead-code/unused-assoc-const.rs deleted file mode 100644 index 36e8315ad3605..0000000000000 --- a/tests/ui/lint/dead-code/unused-assoc-const.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![deny(dead_code)] - -trait Trait { - const UNUSED_CONST: i32; //~ ERROR associated constant `UNUSED_CONST` is never used - const USED_CONST: i32; - - fn foo(&self) {} -} - -pub struct T(()); - -impl Trait for T { - const UNUSED_CONST: i32 = 0; - const USED_CONST: i32 = 1; -} - -fn main() { - T(()).foo(); - T::USED_CONST; -} diff --git a/tests/ui/lint/dead-code/unused-assoc-const.stderr b/tests/ui/lint/dead-code/unused-assoc-const.stderr deleted file mode 100644 index 78296d706638b..0000000000000 --- a/tests/ui/lint/dead-code/unused-assoc-const.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: associated constant `UNUSED_CONST` is never used - --> $DIR/unused-assoc-const.rs:4:11 - | -LL | trait Trait { - | ----- associated constant in this trait -LL | const UNUSED_CONST: i32; - | ^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/unused-assoc-const.rs:1:9 - | -LL | #![deny(dead_code)] - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/lint/dead-code/unused-pub-struct.rs b/tests/ui/lint/dead-code/unused-pub-struct.rs deleted file mode 100644 index aaf4dd612de4d..0000000000000 --- a/tests/ui/lint/dead-code/unused-pub-struct.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![deny(dead_code)] - -pub struct NotLint1(()); -pub struct NotLint2(std::marker::PhantomData); - -pub struct NeverConstructed(i32); //~ ERROR struct `NeverConstructed` is never constructed - -impl NeverConstructed { - pub fn not_construct_self(&self) {} -} - -impl Clone for NeverConstructed { - fn clone(&self) -> NeverConstructed { - NeverConstructed(0) - } -} - -pub trait Trait { - fn not_construct_self(&self); -} - -impl Trait for NeverConstructed { - fn not_construct_self(&self) { - self.0; - } -} - -pub struct Constructed(i32); - -impl Constructed { - pub fn construct_self() -> Self { - Constructed(0) - } -} - -impl Clone for Constructed { - fn clone(&self) -> Constructed { - Constructed(0) - } -} - -impl Trait for Constructed { - fn not_construct_self(&self) { - self.0; - } -} - -fn main() {} diff --git a/tests/ui/lint/dead-code/unused-pub-struct.stderr b/tests/ui/lint/dead-code/unused-pub-struct.stderr deleted file mode 100644 index 3667ddb97bd3e..0000000000000 --- a/tests/ui/lint/dead-code/unused-pub-struct.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: struct `NeverConstructed` is never constructed - --> $DIR/unused-pub-struct.rs:6:12 - | -LL | pub struct NeverConstructed(i32); - | ^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/unused-pub-struct.rs:1:9 - | -LL | #![deny(dead_code)] - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed index e9c89807fa566..a851300a9828e 100644 --- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed +++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed @@ -1,8 +1,7 @@ // Regression test for issues #100790 and #106439. //@ run-rustfix -#[allow(dead_code)] -pub struct Example(usize) +pub struct Example(#[allow(dead_code)] usize) where (): Sized; //~^^^ ERROR where clauses are not allowed before tuple struct bodies diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs index 3bd0f51ec2cbe..10f435859f15a 100644 --- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs +++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs @@ -1,11 +1,10 @@ // Regression test for issues #100790 and #106439. //@ run-rustfix -#[allow(dead_code)] pub struct Example where (): Sized, -(usize); +(#[allow(dead_code)] usize); //~^^^ ERROR where clauses are not allowed before tuple struct bodies struct _Demo diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr index 77eafa6bea336..ddbf237e8662b 100644 --- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr +++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr @@ -1,23 +1,23 @@ error: where clauses are not allowed before tuple struct bodies - --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:6:1 + --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1 | LL | pub struct Example | ------- while parsing this tuple struct LL | / where LL | | (): Sized, | |______________^ unexpected where clause -LL | (usize); - | ------- the struct body +LL | (#[allow(dead_code)] usize); + | --------------------------- the struct body | help: move the body before the where clause | -LL ~ pub struct Example(usize) +LL ~ pub struct Example(#[allow(dead_code)] usize) LL | where LL ~ (): Sized; | error: where clauses are not allowed before tuple struct bodies - --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:12:1 + --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1 | LL | struct _Demo | ----- while parsing this tuple struct diff --git a/tests/ui/pub/pub-ident-struct-4.fixed b/tests/ui/pub/pub-ident-struct-4.fixed index a62ece43eced3..5fedbb7243749 100644 --- a/tests/ui/pub/pub-ident-struct-4.fixed +++ b/tests/ui/pub/pub-ident-struct-4.fixed @@ -1,7 +1,6 @@ //@ run-rustfix -#[allow(dead_code)] -pub struct T(String); +pub struct T(#[allow(dead_code)] String); //~^ ERROR missing `struct` for struct definition fn main() {} diff --git a/tests/ui/pub/pub-ident-struct-4.rs b/tests/ui/pub/pub-ident-struct-4.rs index 0d56a31beaf1c..5c721c25a7815 100644 --- a/tests/ui/pub/pub-ident-struct-4.rs +++ b/tests/ui/pub/pub-ident-struct-4.rs @@ -1,7 +1,6 @@ //@ run-rustfix -#[allow(dead_code)] -pub T(String); +pub T(#[allow(dead_code)] String); //~^ ERROR missing `struct` for struct definition fn main() {} diff --git a/tests/ui/pub/pub-ident-struct-4.stderr b/tests/ui/pub/pub-ident-struct-4.stderr index d3072464e05cd..e04fff1ebf4a9 100644 --- a/tests/ui/pub/pub-ident-struct-4.stderr +++ b/tests/ui/pub/pub-ident-struct-4.stderr @@ -1,12 +1,12 @@ error: missing `struct` for struct definition - --> $DIR/pub-ident-struct-4.rs:4:1 + --> $DIR/pub-ident-struct-4.rs:3:4 | -LL | pub T(String); - | ^^^^^ +LL | pub T(#[allow(dead_code)] String); + | ^ | help: add `struct` here to parse `T` as a struct | -LL | pub struct T(String); +LL | pub struct T(#[allow(dead_code)] String); | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/regions/regions-issue-21422.rs b/tests/ui/regions/regions-issue-21422.rs index 67852a6f5de0d..54beed9b3ac2b 100644 --- a/tests/ui/regions/regions-issue-21422.rs +++ b/tests/ui/regions/regions-issue-21422.rs @@ -5,7 +5,6 @@ //@ pretty-expanded FIXME #23616 -#[allow(dead_code)] pub struct P<'a> { _ptr: *const &'a u8, } diff --git a/tests/ui/structs-enums/newtype-struct-with-dtor.rs b/tests/ui/structs-enums/newtype-struct-with-dtor.rs index 16439a7fedd3e..19672e41c9a30 100644 --- a/tests/ui/structs-enums/newtype-struct-with-dtor.rs +++ b/tests/ui/structs-enums/newtype-struct-with-dtor.rs @@ -3,10 +3,8 @@ #![allow(unused_variables)] //@ pretty-expanded FIXME #23616 -#[allow(dead_code)] pub struct Fd(u32); -#[allow(dead_code)] fn foo(a: u32) {} impl Drop for Fd { diff --git a/tests/ui/structs-enums/uninstantiable-struct.rs b/tests/ui/structs-enums/uninstantiable-struct.rs index 1074dbcd6e6b5..97bc7d8414e7f 100644 --- a/tests/ui/structs-enums/uninstantiable-struct.rs +++ b/tests/ui/structs-enums/uninstantiable-struct.rs @@ -1,5 +1,4 @@ //@ run-pass -#[allow(dead_code)] -pub struct Z(&'static Z); +pub struct Z(#[allow(dead_code)] &'static Z); pub fn main() {} diff --git a/tests/ui/suggestions/derive-clone-for-eq.fixed b/tests/ui/suggestions/derive-clone-for-eq.fixed index cf800c6e47d87..4dc362f947875 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.fixed +++ b/tests/ui/suggestions/derive-clone-for-eq.fixed @@ -1,7 +1,6 @@ //@ run-rustfix // https://github.com/rust-lang/rust/issues/79076 -#[allow(dead_code)] #[derive(Clone, Eq)] //~ ERROR [E0277] pub struct Struct(T); diff --git a/tests/ui/suggestions/derive-clone-for-eq.rs b/tests/ui/suggestions/derive-clone-for-eq.rs index 84736426bac0d..b3635000f1658 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.rs +++ b/tests/ui/suggestions/derive-clone-for-eq.rs @@ -1,7 +1,6 @@ //@ run-rustfix // https://github.com/rust-lang/rust/issues/79076 -#[allow(dead_code)] #[derive(Clone, Eq)] //~ ERROR [E0277] pub struct Struct(T); diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr index 54670fbffcfb9..6fae6e1316df0 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.stderr +++ b/tests/ui/suggestions/derive-clone-for-eq.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: Clone` is not satisfied - --> $DIR/derive-clone-for-eq.rs:5:17 + --> $DIR/derive-clone-for-eq.rs:4:17 | LL | #[derive(Clone, Eq)] | ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct: PartialEq` | note: required for `Struct` to implement `PartialEq` - --> $DIR/derive-clone-for-eq.rs:8:19 + --> $DIR/derive-clone-for-eq.rs:7:19 | LL | impl PartialEq for Struct | ----- ^^^^^^^^^^^^ ^^^^^^^^^ diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed index ef07d55871e7e..4a5a9483c20c8 100644 --- a/tests/ui/suggestions/option-content-move.fixed +++ b/tests/ui/suggestions/option-content-move.fixed @@ -1,5 +1,4 @@ //@ run-rustfix -#[allow(dead_code)] pub struct LipogramCorpora { selections: Vec<(char, Option)>, } @@ -18,7 +17,6 @@ impl LipogramCorpora { } } -#[allow(dead_code)] pub struct LipogramCorpora2 { selections: Vec<(char, Result)>, } diff --git a/tests/ui/suggestions/option-content-move.rs b/tests/ui/suggestions/option-content-move.rs index 5be6358fd6a57..90d05c7439970 100644 --- a/tests/ui/suggestions/option-content-move.rs +++ b/tests/ui/suggestions/option-content-move.rs @@ -1,5 +1,4 @@ //@ run-rustfix -#[allow(dead_code)] pub struct LipogramCorpora { selections: Vec<(char, Option)>, } @@ -18,7 +17,6 @@ impl LipogramCorpora { } } -#[allow(dead_code)] pub struct LipogramCorpora2 { selections: Vec<(char, Result)>, } diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr index b4ec5b180d210..a382a04344aeb 100644 --- a/tests/ui/suggestions/option-content-move.stderr +++ b/tests/ui/suggestions/option-content-move.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:11:20 + --> $DIR/option-content-move.rs:10:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call @@ -19,7 +19,7 @@ LL | if selection.1.clone().unwrap().contains(selection.0) { | ++++++++ error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:30:20 + --> $DIR/option-content-move.rs:28:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call diff --git a/tests/ui/traits/object/generics.rs b/tests/ui/traits/object/generics.rs index 0ae562c0d30a0..462b0bc5bb77f 100644 --- a/tests/ui/traits/object/generics.rs +++ b/tests/ui/traits/object/generics.rs @@ -7,7 +7,6 @@ pub trait Trait2 { fn doit(&self) -> A; } -#[allow(dead_code)] pub struct Impl { m1: marker::PhantomData<(A1,A2,A3)>, /* From cbd27db9a996661792bbbd1dde7ac476eded8340 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:16:33 -0400 Subject: [PATCH 28/41] Suppress new false-negatives that were masked by dead code analysis changes --- library/std/src/sys/pal/unix/pipe.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs index 8762af614f17e..f0ebc767badad 100644 --- a/library/std/src/sys/pal/unix/pipe.rs +++ b/library/std/src/sys/pal/unix/pipe.rs @@ -47,6 +47,8 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { } impl AnonPipe { + #[allow(dead_code)] + // FIXME: This function seems legitimately unused. pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(Self) } @@ -85,6 +87,8 @@ impl AnonPipe { self.0.is_write_vectored() } + #[allow(dead_code)] + // FIXME: This function seems legitimately unused. pub fn as_file_desc(&self) -> &FileDesc { &self.0 } From a57b8b91dbcb1cc3768c0a2a2a0c4971ed01b2f0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 12:23:41 -0400 Subject: [PATCH 29/41] Bless test fallout --- tests/ui-fulldeps/deriving-global.rs | 3 +++ tests/ui-fulldeps/deriving-hygiene.rs | 1 + .../unused-adt-impl-pub-trait-with-assoc-const.rs | 2 +- .../unused-adt-impl-pub-trait-with-assoc-const.stderr | 10 +++++++--- tests/ui/pub/pub-ident-struct-4.stderr | 4 ++-- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/ui-fulldeps/deriving-global.rs b/tests/ui-fulldeps/deriving-global.rs index 7783010be441d..0ba149c9ad654 100644 --- a/tests/ui-fulldeps/deriving-global.rs +++ b/tests/ui-fulldeps/deriving-global.rs @@ -17,18 +17,21 @@ mod submod { // if any of these are implemented without global calls for any // function calls, then being in a submodule will (correctly) // cause errors about unrecognised module `std` (or `extra`) + #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] enum A { A1(usize), A2(isize), } + #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] struct B { x: usize, y: isize, } + #[allow(dead_code)] #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)] struct C(usize, isize); } diff --git a/tests/ui-fulldeps/deriving-hygiene.rs b/tests/ui-fulldeps/deriving-hygiene.rs index a3a6f9e022ebb..f948d6ac544e5 100644 --- a/tests/ui-fulldeps/deriving-hygiene.rs +++ b/tests/ui-fulldeps/deriving-hygiene.rs @@ -20,6 +20,7 @@ pub const s: u8 = 1; pub const state: u8 = 1; pub const cmp: u8 = 1; +#[allow(dead_code)] #[derive(Ord, Eq, PartialOrd, PartialEq, Debug, Decodable, Encodable, Hash)] struct Foo {} diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs index bf2fc243e8194..5b755d62a0598 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs @@ -1,7 +1,7 @@ #![deny(dead_code)] struct T1; //~ ERROR struct `T1` is never constructed -pub struct T2(i32); //~ ERROR struct `T2` is never constructed +pub struct T2(i32); //~ ERROR field `0` is never read struct T3; trait Trait1 { //~ ERROR trait `Trait1` is never used diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr index 174096d939883..2441a3f868dc2 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr @@ -10,11 +10,15 @@ note: the lint level is defined here LL | #![deny(dead_code)] | ^^^^^^^^^ -error: struct `T2` is never constructed - --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:12 +error: field `0` is never read + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:15 | LL | pub struct T2(i32); - | ^^ + | -- ^^^ + | | + | field in this struct + | + = help: consider removing this field error: trait `Trait1` is never used --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7 diff --git a/tests/ui/pub/pub-ident-struct-4.stderr b/tests/ui/pub/pub-ident-struct-4.stderr index e04fff1ebf4a9..04965a1a73720 100644 --- a/tests/ui/pub/pub-ident-struct-4.stderr +++ b/tests/ui/pub/pub-ident-struct-4.stderr @@ -1,8 +1,8 @@ error: missing `struct` for struct definition - --> $DIR/pub-ident-struct-4.rs:3:4 + --> $DIR/pub-ident-struct-4.rs:3:1 | LL | pub T(#[allow(dead_code)] String); - | ^ + | ^^^^^ | help: add `struct` here to parse `T` as a struct | From 106cf7bec2019aa92912e1df1f4d045f6435bc9a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Aug 2024 07:57:23 -0400 Subject: [PATCH 30/41] Remove another false-negative hidden by dead code changes --- src/bootstrap/src/core/build_steps/check.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 8b71300cf85e7..7f7faf077d047 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -31,10 +31,6 @@ pub struct Std { } impl Std { - pub fn new(target: TargetSelection) -> Self { - Self::new_with_build_kind(target, None) - } - pub fn new_with_build_kind(target: TargetSelection, kind: Option) -> Self { Self { target, crates: vec![], override_build_kind: kind } } From b564b70d1cb3678108f9045e8fcf2627270d544b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 3 Aug 2024 12:26:50 +0000 Subject: [PATCH 31/41] Update run-make/used to use `any_symbol_contains` --- tests/run-make/used/rmake.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs index 56ef5c6b9cc0c..eb5d026feda1f 100644 --- a/tests/run-make/used/rmake.rs +++ b/tests/run-make/used/rmake.rs @@ -4,12 +4,11 @@ // It comes from #39987 which implements this RFC for the #[used] attribute: // https://rust-lang.github.io/rfcs/2386-used.html -//@ ignore-msvc - -use run_make_support::{cmd, rustc}; +use run_make_support::rustc; +use run_make_support::symbols::any_symbol_contains; fn main() { rustc().opt_level("3").emit("obj").input("used.rs").run(); - - cmd("nm").arg("used.o").run().assert_stdout_contains("FOO"); + assert!(any_symbol_contains("used.o", &["FOO"])); + assert!(!any_symbol_contains("used.o", &["BAR"])); } From eb451464a7557f2d8115183a92e6a300d20d75e5 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 3 Aug 2024 13:01:34 +0000 Subject: [PATCH 32/41] Remove BAR for run-make/used.rs --- tests/run-make/used/rmake.rs | 1 - tests/run-make/used/used.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs index eb5d026feda1f..39f36b2eea8f6 100644 --- a/tests/run-make/used/rmake.rs +++ b/tests/run-make/used/rmake.rs @@ -10,5 +10,4 @@ use run_make_support::symbols::any_symbol_contains; fn main() { rustc().opt_level("3").emit("obj").input("used.rs").run(); assert!(any_symbol_contains("used.o", &["FOO"])); - assert!(!any_symbol_contains("used.o", &["BAR"])); } diff --git a/tests/run-make/used/used.rs b/tests/run-make/used/used.rs index dca0a5e1167a8..133f8121a8e91 100644 --- a/tests/run-make/used/used.rs +++ b/tests/run-make/used/used.rs @@ -2,5 +2,3 @@ #[used] static FOO: u32 = 0; - -static BAR: u32 = 0; From a3a09b488fde8fbe66c2be44491cdb87201d32a2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Aug 2024 00:14:45 +0200 Subject: [PATCH 33/41] Simplify `body` usage in rustdoc --- src/librustdoc/html/static/js/main.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index e0ea234f9e710..ee771a40595ab 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1115,8 +1115,7 @@ function preLoadCss(cssUrl) { wrapper.style.left = 0; wrapper.style.right = "auto"; wrapper.style.visibility = "hidden"; - const body = document.getElementsByTagName("body")[0]; - body.appendChild(wrapper); + document.body.appendChild(wrapper); const wrapperPos = wrapper.getBoundingClientRect(); // offset so that the arrow points at the center of the "(i)" const finalPos = pos.left + window.scrollX - wrapperPos.width + 24; @@ -1235,8 +1234,7 @@ function preLoadCss(cssUrl) { } window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false; } - const body = document.getElementsByTagName("body")[0]; - body.removeChild(window.CURRENT_TOOLTIP_ELEMENT); + document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT); clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); window.CURRENT_TOOLTIP_ELEMENT = null; } @@ -1833,7 +1831,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm let elem = event.target; while (!hasClass(elem, "example-wrap")) { elem = elem.parentElement; - if (elem.tagName === "body" || hasClass(elem, "docblock")) { + if (elem === document.body || hasClass(elem, "docblock")) { return null; } } From eb2de64aa1cb0d3eded99458566e8eee8333a751 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 3 Aug 2024 12:30:38 -0700 Subject: [PATCH 34/41] rustdoc: make the hover trail for doc anchors a bit bigger https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/Weird.20markdown.20heading.20rendering.3F --- src/librustdoc/html/static/css/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index f4e231327a8c2..02a6bb8f5487a 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -930,7 +930,7 @@ a.doc-anchor { left: -17px; /* We add this padding so that when the cursor moves from the heading's text to the anchor, the anchor doesn't disappear. */ - padding-right: 5px; + padding-right: 10px; /* And this padding is used to make the anchor larger and easier to click on. */ padding-left: 3px; } From 2cde11f2d145d031b26fe22a3e7d2e278bc0e6ba Mon Sep 17 00:00:00 2001 From: sayantn Date: Sun, 4 Aug 2024 02:32:03 +0530 Subject: [PATCH 35/41] Chore: add `x86_amx_intrinsics` feature flag to `core/lib.rs` and remove `issue-120720-reduce-nan.rs` --- library/core/src/lib.rs | 1 + tests/codegen/simd/issue-120720-reduce-nan.rs | 21 ------------------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 tests/codegen/simd/issue-120720-reduce-nan.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9306581dca93d..e74900ff7471b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -264,6 +264,7 @@ #![feature(sse4a_target_feature)] #![feature(tbm_target_feature)] #![feature(wasm_target_feature)] +#![feature(x86_amx_intrinsics)] // tidy-alphabetical-end // allow using `core::` in intra-doc links diff --git a/tests/codegen/simd/issue-120720-reduce-nan.rs b/tests/codegen/simd/issue-120720-reduce-nan.rs deleted file mode 100644 index 13af0bb076e6a..0000000000000 --- a/tests/codegen/simd/issue-120720-reduce-nan.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C opt-level=3 -C target-cpu=cannonlake -//@ only-x86_64 - -// In a previous implementation, _mm512_reduce_add_pd did the reduction with all fast-math flags -// enabled, making it UB to reduce a vector containing a NaN. - -#![crate_type = "lib"] -#![feature(stdarch_x86_avx512, avx512_target_feature)] -use std::arch::x86_64::*; - -// CHECK-LABEL: @demo( -#[no_mangle] -#[target_feature(enable = "avx512f")] // Function-level target feature mismatches inhibit inlining -pub unsafe fn demo() -> bool { - // CHECK: %0 = tail call reassoc double @llvm.vector.reduce.fadd.v8f64( - // CHECK: %_0.i = fcmp uno double %0, 0.000000e+00 - // CHECK: ret i1 %_0.i - let res = - unsafe { _mm512_reduce_add_pd(_mm512_set_pd(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, f64::NAN)) }; - res.is_nan() -} From 01bda01e3374d73e98806f8e27cbb7f6ceb9ad98 Mon Sep 17 00:00:00 2001 From: sayantn Date: Sun, 4 Aug 2024 03:07:12 +0530 Subject: [PATCH 36/41] Update stdarch --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index df3618d9f3516..47b929ddc521a 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit df3618d9f35165f4bc548114e511c49c29e1fd9b +Subproject commit 47b929ddc521a78b0f699ba8d5c274d28593448a From cb7c596681c3c5718c7fd0fbe15c487cd36c65c3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 4 Aug 2024 01:08:10 +0200 Subject: [PATCH 37/41] Update rinja version to 0.3.0 --- Cargo.lock | 15 +++++++++------ src/librustdoc/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b5aa7db3190c..13b8eaea06804 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3282,20 +3282,22 @@ dependencies = [ [[package]] name = "rinja" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d47a46d7729e891c8accf260e9daa02ae6d570aa2a94fb1fb27eb5364a2323" +checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd" dependencies = [ + "itoa", "rinja_derive", ] [[package]] name = "rinja_derive" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dae9afe59d58ed8d988d67d1945f3638125d2fd2104058399382e11bd3ea2a" +checksum = "fd01fd8e15e7d19c8b8052c1d428325131e02ff1633cdcf695190c2e56ab682c" dependencies = [ "basic-toml", + "memchr", "mime", "mime_guess", "once_map", @@ -3308,10 +3310,11 @@ dependencies = [ [[package]] name = "rinja_parser" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1771c78cd5d3b1646ef8d8f2ed100db936e8b291d3cc06e92a339ff346858c" +checksum = "a2f6bf7cef118c6de21206edf0b3f19f5ede60006be674a58ca21b6e003a1b57" dependencies = [ + "memchr", "nom", ] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index dfd7414652fa7..b3fccbf6456e0 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -8,7 +8,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } -rinja = { version = "0.2", default-features = false, features = ["config"] } +rinja = { version = "0.3", default-features = false, features = ["config"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" From 3a41a11a8f8af11867c0401027235215cac643ca Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Wed, 17 Jul 2024 16:40:01 -0400 Subject: [PATCH 38/41] Migrate `run-make/print-calling-conventions` to ui-test --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../print-calling-conventions/Makefile | 4 --- tests/ui/print-calling-conventions.rs | 2 ++ tests/ui/print-calling-conventions.stdout | 34 +++++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) delete mode 100644 tests/run-make/print-calling-conventions/Makefile create mode 100644 tests/ui/print-calling-conventions.rs create mode 100644 tests/ui/print-calling-conventions.stdout diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index a04e239abb0e1..93226c41a235f 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/no-alloc-shim/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-indirect-call-promotion/Makefile -run-make/print-calling-conventions/Makefile run-make/print-target-list/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile diff --git a/tests/run-make/print-calling-conventions/Makefile b/tests/run-make/print-calling-conventions/Makefile deleted file mode 100644 index 27b87e610862d..0000000000000 --- a/tests/run-make/print-calling-conventions/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --print calling-conventions diff --git a/tests/ui/print-calling-conventions.rs b/tests/ui/print-calling-conventions.rs new file mode 100644 index 0000000000000..302ed088142d8 --- /dev/null +++ b/tests/ui/print-calling-conventions.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --print calling-conventions +//@ build-pass diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout new file mode 100644 index 0000000000000..da67a57f420d7 --- /dev/null +++ b/tests/ui/print-calling-conventions.stdout @@ -0,0 +1,34 @@ +C +C-cmse-nonsecure-call +C-unwind +Rust +aapcs +aapcs-unwind +avr-interrupt +avr-non-blocking-interrupt +cdecl +cdecl-unwind +efiapi +fastcall +fastcall-unwind +msp430-interrupt +ptx-kernel +riscv-interrupt-m +riscv-interrupt-s +rust-call +rust-cold +rust-intrinsic +stdcall +stdcall-unwind +system +system-unwind +sysv64 +sysv64-unwind +thiscall +thiscall-unwind +unadjusted +vectorcall +vectorcall-unwind +win64 +win64-unwind +x86-interrupt From 1ca959e3f00fcf01395b18bb6e3b9dd86b3e478c Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Wed, 17 Jul 2024 16:55:13 -0400 Subject: [PATCH 39/41] Migrate `print-target-list` to `rmake` --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/print-target-list/Makefile | 8 ------- tests/run-make/print-target-list/rmake.rs | 21 +++++++++++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) delete mode 100644 tests/run-make/print-target-list/Makefile create mode 100644 tests/run-make/print-target-list/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 93226c41a235f..088d5ba0c2b37 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/no-alloc-shim/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-indirect-call-promotion/Makefile -run-make/print-target-list/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile run-make/redundant-libs/Makefile diff --git a/tests/run-make/print-target-list/Makefile b/tests/run-make/print-target-list/Makefile deleted file mode 100644 index f23c40d4281e3..0000000000000 --- a/tests/run-make/print-target-list/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../tools.mk - -# Checks that all the targets returned by `rustc --print target-list` are valid -# target specifications -all: - for target in $(shell $(BARE_RUSTC) --print target-list); do \ - $(BARE_RUSTC) --target $$target --print sysroot; \ - done diff --git a/tests/run-make/print-target-list/rmake.rs b/tests/run-make/print-target-list/rmake.rs new file mode 100644 index 0000000000000..743ed52069dea --- /dev/null +++ b/tests/run-make/print-target-list/rmake.rs @@ -0,0 +1,21 @@ +// Checks that all the targets returned by `rustc --print target-list` are valid +// target specifications + +use run_make_support::bare_rustc; + +// FIXME(127877): certain experimental targets fail with creating a 'LLVM TargetMachine' +// in CI, so we skip them +const EXPERIMENTAL_TARGETS: &[&str] = &["avr", "m68k", "csky", "xtensa"]; + +fn main() { + let targets = bare_rustc().print("target-list").run().stdout_utf8(); + + for target in targets.lines() { + // skip experimental targets that would otherwise fail + if EXPERIMENTAL_TARGETS.iter().any(|experimental| target.contains(experimental)) { + continue; + } + + bare_rustc().target(target).print("sysroot").run(); + } +} From 36cf385e886da13b5b1f98a8b62b1aa63f7e1722 Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Wed, 17 Jul 2024 17:54:06 -0400 Subject: [PATCH 40/41] Ensure `Rustc::print` use in `rmake` tests --- tests/run-make/print-cfg/rmake.rs | 5 +---- tests/run-make/print-check-cfg/rmake.rs | 2 +- tests/run-make/print-to-output/rmake.rs | 5 +---- tests/run-make/rustdoc-scrape-examples-macros/rmake.rs | 3 +-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index d83e8a36f2c08..471a99b90d982 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -6,7 +6,6 @@ //! It also checks that some targets have the correct set cfgs. use std::collections::HashSet; -use std::ffi::OsString; use std::iter::FromIterator; use std::path::PathBuf; @@ -91,10 +90,8 @@ fn check(PrintCfg { target, includes, disallow }: PrintCfg) { // --print=cfg=PATH { let tmp_path = PathBuf::from(format!("{target}.cfg")); - let mut print_arg = OsString::from("--print=cfg="); - print_arg.push(tmp_path.as_os_str()); - rustc().target(target).arg(print_arg).run(); + rustc().target(target).print(&format!("cfg={}", tmp_path.display())).run(); let output = rfs::read_to_string(&tmp_path); diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs index 4a79910c8e05e..b10336f88c649 100644 --- a/tests/run-make/print-check-cfg/rmake.rs +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -87,7 +87,7 @@ fn main() { fn check(CheckCfg { args, contains }: CheckCfg) { let output = - rustc().input("lib.rs").arg("-Zunstable-options").arg("--print=check-cfg").args(args).run(); + rustc().input("lib.rs").arg("-Zunstable-options").print("check-cfg").args(args).run(); let stdout = output.stdout_utf8(); diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs index d0cba725b3679..db2a291f8e737 100644 --- a/tests/run-make/print-to-output/rmake.rs +++ b/tests/run-make/print-to-output/rmake.rs @@ -1,7 +1,6 @@ //! This checks the output of some `--print` options when //! output to a file (instead of stdout) -use std::ffi::OsString; use std::path::PathBuf; use run_make_support::{rfs, rustc, target}; @@ -44,10 +43,8 @@ fn check(args: Option) { // --print={option}=PATH let output = { let tmp_path = PathBuf::from(format!("{}.txt", args.option)); - let mut print_arg = OsString::from(format!("--print={}=", args.option)); - print_arg.push(tmp_path.as_os_str()); - rustc().target(args.target).arg(print_arg).run(); + rustc().target(args.target).print(&format!("{}={}", args.option, tmp_path.display())).run(); rfs::read_to_string(&tmp_path) }; diff --git a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs index bfe4a1df4569d..b77df7adc8d9e 100644 --- a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs @@ -11,8 +11,7 @@ fn main() { let dylib_name = rustc() .crate_name(proc_crate_name) .crate_type("dylib") - .arg("--print") - .arg("file-names") + .print("file-names") .arg("-") .run() .stdout_utf8(); From 007d9e1c26da1e509ff7887604e6685f1445982a Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 3 Aug 2024 20:51:28 -0700 Subject: [PATCH 41/41] rustdoc: Re-add missing `stripped_mod` check; explain orphan impls Co-authored-by: Michael Howell --- src/librustdoc/formats/cache.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index d2d0f5a4380b6..3fdc878647175 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -486,10 +486,30 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It ParentStackItem::Type(item_id) => item_id.as_def_id(), }; let Some(parent_did) = parent_did else { return }; - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. + // The current stack reflects the CacheBuilder's recursive + // walk over HIR. For associated items, this is the module + // where the `impl` block is defined. That's an implementation + // detail that we don't want to affect the search engine. + // + // In particular, you can arrange things like this: + // + // #![crate_name="me"] + // mod private_mod { + // impl Clone for MyThing { fn clone(&self) -> MyThing { MyThing } } + // } + // pub struct MyThing; + // + // When that happens, we need to: + // - ignore the `cache.stripped_mod` flag, since the Clone impl is actually + // part of the public API even though it's defined in a private module + // - present the method as `me::MyThing::clone`, its publicly-visible path + // - deal with the fact that the recursive walk hasn't actually reached `MyThing` + // until it's already past `private_mod`, since that's first, and doesn't know + // yet if `MyThing` will actually be public or not (it could be re-exported) + // + // We accomplish the last two points by recording children of "orphan impls" + // in a field of the cache whose elements are added to the search index later, + // after cache building is complete (see `handle_orphan_impl_child`). match cache.paths.get(&parent_did) { Some((fqp, _)) => (Some(parent_did), &fqp[..fqp.len() - 1]), None => { @@ -500,7 +520,8 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It } _ => { // Don't index if item is crate root, which is inserted later on when serializing the index. - if item_def_id.is_crate_root() { + // Don't index if containing module is stripped (i.e., private), + if item_def_id.is_crate_root() || cache.stripped_mod { return; } (None, &*cache.stack)