From de0cb6cb6e7cdc3d0f47378ec54b37c9f011a49e Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Wed, 13 Nov 2024 00:38:53 -0500 Subject: [PATCH 01/23] Start work on dangling pointers lint --- compiler/rustc_lint/messages.ftl | 5 ++++- compiler/rustc_lint/src/lints.rs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 49e6b763590b0..da8401ebaf8c9 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -209,7 +209,10 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help = for more information, see + .help_info = you must make sure that the variable you bind the `{$typ}` to lives at least as long as the pointer returned by the call to `{$callee}` + .help_info = in particular, if this pointer is returned from the current function, binding the `{$typ}` inside the function will not suffice + .help_visit = for more information, see + lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 20822f23bf15d..382fac9c3d013 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1148,6 +1148,7 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { #[diag(lint_dangling_pointers_from_temporaries)] #[note] #[help] +#[help(lint_info)] // FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub callee: Symbol, From 6d95b5baefd2b310db223c865dd96571269fe976 Mon Sep 17 00:00:00 2001 From: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com> Date: Thu, 5 Dec 2024 06:06:38 -0500 Subject: [PATCH 02/23] Update compiler/rustc_lint/src/lints.rs Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- compiler/rustc_lint/src/lints.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 382fac9c3d013..0dcea967bbe6b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1147,8 +1147,9 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { #[derive(LintDiagnostic)] #[diag(lint_dangling_pointers_from_temporaries)] #[note] -#[help] -#[help(lint_info)] +#[help(lint_help_bind)] +#[help(lint_help_returned)] +#[help(lint_help_visit)] // FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub callee: Symbol, From bab8a413348e838d8ca0b369ebdc586f8542a120 Mon Sep 17 00:00:00 2001 From: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com> Date: Thu, 5 Dec 2024 06:06:51 -0500 Subject: [PATCH 03/23] Update compiler/rustc_lint/messages.ftl Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- compiler/rustc_lint/messages.ftl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index da8401ebaf8c9..3570126de7427 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -209,11 +209,10 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help_info = you must make sure that the variable you bind the `{$typ}` to lives at least as long as the pointer returned by the call to `{$callee}` - .help_info = in particular, if this pointer is returned from the current function, binding the `{$typ}` inside the function will not suffice + .help_bind = you must make sure that the variable you bind the `{$typ}` to lives at least as long as the pointer returned by the call to `{$callee}` + .help_returned = in particular, if this pointer is returned from the current function, binding the `{$typ}` inside the function will not suffice .help_visit = for more information, see - lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary From 3a83422c136533592618da1ec0a2abee0ef5e5d9 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 12 Jan 2025 14:10:26 +0000 Subject: [PATCH 04/23] Fix ICE-133063 If all subcandidates have never-pattern, the parent candidate should have otherwise_block because some methods expect the candidate has the block. Signed-off-by: Shunpoco --- .../src/builder/matches/mod.rs | 8 ++-- ...ICE-133063-never-arm-no-otherwise-block.rs | 21 +++++++++++ ...133063-never-arm-no-otherwise-block.stderr | 37 +++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index b944d13fb0d24..4b8d33c0dd636 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1958,7 +1958,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This candidate is about to become a leaf, so unset `or_span`. let or_span = candidate.or_span.take().unwrap(); let source_info = self.source_info(or_span); - + if candidate.false_edge_start_block.is_none() { candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; } @@ -2000,8 +2000,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }); if candidate.subcandidates.is_empty() { - // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`. - candidate.pre_binding_block = Some(self.cfg.start_new_block()); + // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block` and `otherwise_block`. + let next_block = self.cfg.start_new_block(); + candidate.pre_binding_block = Some(next_block); + candidate.otherwise_block = Some(next_block); } } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs new file mode 100644 index 0000000000000..a9527d7d0c445 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs @@ -0,0 +1,21 @@ +#![feature(never_patterns)] +#![feature(if_let_guard)] +#![allow(incomplete_features)] + +fn split_last(_: &()) -> Option<(&i32, &i32)> { + None +} + +fn assign_twice() { + loop { + match () { + (!| //~ ERROR: mismatched types + !) if let _ = split_last(&()) => {} //~ ERROR a never pattern is always unreachable + //~^ ERROR: mismatched types + //~^^ WARNING: irrefutable `if let` guard pattern [irrefutable_let_patterns] + _ => {} + } + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr new file mode 100644 index 0000000000000..896c95f1866fe --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr @@ -0,0 +1,37 @@ +error: a never pattern is always unreachable + --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:13:46 + | +LL | !) if let _ = split_last(&()) => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: mismatched types + --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:12:14 + | +LL | (!| + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `()` + +error: mismatched types + --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:13:13 + | +LL | !) if let _ = split_last(&()) => {} + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `()` + +warning: irrefutable `if let` guard pattern + --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:13:19 + | +LL | !) if let _ = split_last(&()) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm + = note: `#[warn(irrefutable_let_patterns)]` on by default + +error: aborting due to 3 previous errors; 1 warning emitted + From 8a57fa634c46273dab0a283d2ee151735342c514 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 12 Jan 2025 14:44:36 +0000 Subject: [PATCH 05/23] Fix ICE-133117 If all subcandidates have never-pattern, we should assign false_edge_start_block to the parent candidate if it doesn't have. merge_trivial_subcandidates does so, but if the candidate has guard it returns before the assignment. Signed-off-by: Shunpoco --- .../src/builder/matches/mod.rs | 8 ++--- .../ICE-133117-duplicate-never-arm.rs | 12 +++++++ .../ICE-133117-duplicate-never-arm.stderr | 36 +++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 4b8d33c0dd636..7e7c5ceee937e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1940,6 +1940,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// in match tree lowering. fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { assert!(!candidate.subcandidates.is_empty()); + if candidate.false_edge_start_block.is_none() { + candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; + } + if candidate.has_guard { // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. return; @@ -1958,10 +1962,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This candidate is about to become a leaf, so unset `or_span`. let or_span = candidate.or_span.take().unwrap(); let source_info = self.source_info(or_span); - - if candidate.false_edge_start_block.is_none() { - candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; - } // Remove the (known-trivial) subcandidates from the candidate tree, // so that they aren't visible after match tree lowering, and wire them diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs new file mode 100644 index 0000000000000..884dbacbaa98f --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs @@ -0,0 +1,12 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +fn main() { + match () { + (!| + //~^ ERROR: mismatched types + !) if true => {} //~ ERROR a never pattern is always unreachable + //~^ ERROR: mismatched types + (!|!) if true => {} //~ ERROR a never pattern is always unreachable + } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr new file mode 100644 index 0000000000000..4b8de102a7b55 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr @@ -0,0 +1,36 @@ +error: a never pattern is always unreachable + --> $DIR/ICE-133117-duplicate-never-arm.rs:8:23 + | +LL | !) if true => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: a never pattern is always unreachable + --> $DIR/ICE-133117-duplicate-never-arm.rs:10:26 + | +LL | (!|!) if true => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: mismatched types + --> $DIR/ICE-133117-duplicate-never-arm.rs:6:10 + | +LL | (!| + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `()` + +error: mismatched types + --> $DIR/ICE-133117-duplicate-never-arm.rs:8:9 + | +LL | !) if true => {} + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `()` + +error: aborting due to 4 previous errors + From 8c0c149bb007d3a8b8305c7a4ccaf4c30acfc9c2 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 12 Jan 2025 15:16:24 +0000 Subject: [PATCH 06/23] Remove solved crashes Signed-off-by: Shunpoco --- tests/crashes/130779.rs | 11 ----------- tests/crashes/133063.rs | 8 -------- tests/crashes/133117.rs | 8 -------- 3 files changed, 27 deletions(-) delete mode 100644 tests/crashes/130779.rs delete mode 100644 tests/crashes/133063.rs delete mode 100644 tests/crashes/133117.rs diff --git a/tests/crashes/130779.rs b/tests/crashes/130779.rs deleted file mode 100644 index f0fd81fff4449..0000000000000 --- a/tests/crashes/130779.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #130779 -#![feature(never_patterns)] - -enum E { A } - -fn main() { - match E::A { - ! | - if true => {} - } -} diff --git a/tests/crashes/133063.rs b/tests/crashes/133063.rs deleted file mode 100644 index 132b5486170a8..0000000000000 --- a/tests/crashes/133063.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #133063 - -fn foo(x: !) { - match x { - (! | !) if false => {} - _ => {} - } -} diff --git a/tests/crashes/133117.rs b/tests/crashes/133117.rs deleted file mode 100644 index 751c82626d574..0000000000000 --- a/tests/crashes/133117.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #133117 - -fn main() { - match () { - (!|!) if true => {} - (!|!) if true => {} - } -} From 0385dd4719e0ca1ab1a16b6f060bc6a3d1bf2dd9 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 12 Jan 2025 15:21:24 +0000 Subject: [PATCH 07/23] Fix ICE-130779 Signed-off-by: Shunpoco --- ...CE-130779-never-arm-no-oatherwise-block.rs | 12 +++++++ ...30779-never-arm-no-oatherwise-block.stderr | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs new file mode 100644 index 0000000000000..2a7e730af16ba --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs @@ -0,0 +1,12 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum E { A } + +fn main() { + match E::A { + ! | //~ ERROR: a trailing `|` is not allowed in an or-pattern + //~^ ERROR: mismatched types + if true => {} //~ ERROR: a never pattern is always unreachable + } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr new file mode 100644 index 0000000000000..26731e29ffc57 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr @@ -0,0 +1,33 @@ +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:11 + | +LL | ! | + | - ^ + | | + | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - ! | +LL + ! + | + +error: a never pattern is always unreachable + --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:10:20 + | +LL | if true => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: mismatched types + --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:9 + | +LL | ! | + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `E` + +error: aborting due to 3 previous errors + From be56f10a694d4a34c9d02b90f44788040b325a8a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 16 Jan 2025 18:37:45 +0000 Subject: [PATCH 08/23] Properly note when query stack is being cut off --- compiler/rustc_driver_impl/src/lib.rs | 4 ++-- compiler/rustc_interface/src/interface.rs | 17 +++++++++++------ compiler/rustc_query_system/src/query/job.rs | 6 +++--- .../generic_const_exprs/issue-80742.stderr | 2 +- tests/ui/layout/valid_range_oob.stderr | 2 +- ...ultiple_definitions_attribute_merging.stderr | 2 +- .../resolve/proc_macro_generated_packed.stderr | 2 +- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 0413e5e86348b..190c0a0ebfeff 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1530,9 +1530,9 @@ fn report_ice( // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0"); - let num_frames = if backtrace { None } else { Some(2) }; + let limit_frames = if backtrace { None } else { Some(2) }; - interface::try_print_query_stack(dcx, num_frames, file); + interface::try_print_query_stack(dcx, limit_frames, file); // We don't trust this callback not to panic itself, so run it at the end after we're sure we've // printed all the relevant info. diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 1456255ea14cd..df97d53f19d72 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -533,7 +533,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se pub fn try_print_query_stack( dcx: DiagCtxtHandle<'_>, - num_frames: Option, + limit_frames: Option, file: Option, ) { eprintln!("query stack during panic:"); @@ -541,13 +541,13 @@ pub fn try_print_query_stack( // Be careful relying on global state here: this code is called from // a panic hook, which means that the global `DiagCtxt` may be in a weird // state if it was responsible for triggering the panic. - let i = ty::tls::with_context_opt(|icx| { + let all_frames = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { ty::print::with_no_queries!(print_query_stack( QueryCtxt::new(icx.tcx), icx.query, dcx, - num_frames, + limit_frames, file, )) } else { @@ -555,9 +555,14 @@ pub fn try_print_query_stack( } }); - if num_frames == None || num_frames >= Some(i) { - eprintln!("end of query stack"); + if let Some(limit_frames) = limit_frames + && all_frames > limit_frames + { + eprintln!( + "... and {} other queries... use `env RUST_BACKTRACE=1` to see the full query stack", + all_frames - limit_frames + ); } else { - eprintln!("we're just showing a limited slice of the query stack"); + eprintln!("end of query stack"); } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 3e179c61f3921..a8c2aa98cd083 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -567,7 +567,7 @@ pub fn print_query_stack( qcx: Qcx, mut current_query: Option, dcx: DiagCtxtHandle<'_>, - num_frames: Option, + limit_frames: Option, mut file: Option, ) -> usize { // Be careful relying on global state here: this code is called from @@ -584,7 +584,7 @@ pub fn print_query_stack( let Some(query_info) = query_map.get(&query) else { break; }; - if Some(count_printed) < num_frames || num_frames.is_none() { + if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. // FIXME: needs translation #[allow(rustc::diagnostic_outside_of_impl)] @@ -615,5 +615,5 @@ pub fn print_query_stack( if let Some(ref mut file) = file { let _ = writeln!(file, "end of query stack"); } - count_printed + count_total } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr index c851a8380f2c4..d90380396c1f3 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr @@ -6,6 +6,6 @@ Box query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `::{constant#0}` #1 [eval_to_valtree] evaluating type-level constant -end of query stack +... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack error: aborting due to 1 previous error diff --git a/tests/ui/layout/valid_range_oob.stderr b/tests/ui/layout/valid_range_oob.stderr index 9c360b2cd6e7e..1a0c384125038 100644 --- a/tests/ui/layout/valid_range_oob.stderr +++ b/tests/ui/layout/valid_range_oob.stderr @@ -5,4 +5,4 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: #0 [layout_of] computing layout of `Foo` #1 [eval_to_allocation_raw] const-evaluating + checking `FOO` -end of query stack +... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack diff --git a/tests/ui/resolve/multiple_definitions_attribute_merging.stderr b/tests/ui/resolve/multiple_definitions_attribute_merging.stderr index 804fa079bb99e..ac6307c7a69eb 100644 --- a/tests/ui/resolve/multiple_definitions_attribute_merging.stderr +++ b/tests/ui/resolve/multiple_definitions_attribute_merging.stderr @@ -21,7 +21,7 @@ Box query stack during panic: #0 [mir_built] building MIR for `::eq` #1 [check_unsafety] unsafety-checking `::eq` -end of query stack +... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/resolve/proc_macro_generated_packed.stderr b/tests/ui/resolve/proc_macro_generated_packed.stderr index a5a02c9c393ae..8b70059503486 100644 --- a/tests/ui/resolve/proc_macro_generated_packed.stderr +++ b/tests/ui/resolve/proc_macro_generated_packed.stderr @@ -12,6 +12,6 @@ Box query stack during panic: #0 [mir_built] building MIR for `::eq` #1 [check_unsafety] unsafety-checking `::eq` -end of query stack +... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack error: aborting due to 1 previous error From cd9dcfc6bc9ef6ceb97f24b47634bb44b9aaf39f Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Tue, 21 Jan 2025 11:42:56 +0100 Subject: [PATCH 09/23] ci: use ghcr buildkit image --- src/ci/docker/run.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index d1bc0519bc1eb..d2697ac27ab7a 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -123,6 +123,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}") fi + GHCR_BUILDKIT_IMAGE="ghcr.io/rust-lang/buildkit:buildx-stable-1" # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci # ghcr.io registry. If it is not possible, we fall back to building the image # locally. @@ -140,7 +141,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then elif [[ "$PR_CI_JOB" == "1" ]]; then # Enable a new Docker driver so that --cache-from works with a registry backend - docker buildx create --use --driver docker-container + # Use a custom image to avoid DockerHub rate limits + docker buildx create --use --driver docker-container \ + --driver-opt image=${GHCR_BUILDKIT_IMAGE} # Build the image using registry caching backend retry docker \ @@ -156,7 +159,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then --password-stdin # Enable a new Docker driver so that --cache-from/to works with a registry backend - docker buildx create --use --driver docker-container + # Use a custom image to avoid DockerHub rate limits + docker buildx create --use --driver docker-container \ + --driver-opt image=${GHCR_BUILDKIT_IMAGE} # Build the image using registry caching backend retry docker \ From a93616acf3118ef233027d74e8c636f9b79c342d Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 18 Jan 2025 21:28:21 +0000 Subject: [PATCH 10/23] rustc_resolve: remove unneeded `return`s --- compiler/rustc_resolve/src/diagnostics.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ba217b7c88a8e..3b6603536c735 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3042,7 +3042,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { self.first_legal_span = Some(inject); } self.first_use_span = search_for_any_use_in_items(&c.items); - return; } else { visit::walk_crate(self, c); } @@ -3056,7 +3055,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { self.first_legal_span = Some(inject); } self.first_use_span = search_for_any_use_in_items(items); - return; } } else { visit::walk_item(self, item); From cf91a93d09db875ba28cd395f9339331324a14c7 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 20 Jan 2025 17:41:03 +0000 Subject: [PATCH 11/23] rustc_resolve: flatten nested `if`s --- .../rustc_resolve/src/build_reduced_graph.rs | 54 ++++---- compiler/rustc_resolve/src/diagnostics.rs | 127 ++++++++---------- compiler/rustc_resolve/src/ident.rs | 98 +++++++------- compiler/rustc_resolve/src/imports.rs | 83 ++++++------ compiler/rustc_resolve/src/late.rs | 65 ++++----- 5 files changed, 198 insertions(+), 229 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3fe1eed243f0a..eec9e9a851503 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -645,10 +645,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let self_spans = items .iter() .filter_map(|(use_tree, _)| { - if let ast::UseTreeKind::Simple(..) = use_tree.kind { - if use_tree.ident().name == kw::SelfLower { - return Some(use_tree.span); - } + if let ast::UseTreeKind::Simple(..) = use_tree.kind + && use_tree.ident().name == kw::SelfLower + { + return Some(use_tree.span); } None @@ -947,19 +947,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let imported_binding = self.r.import(binding, import); if parent == self.r.graph_root { let ident = ident.normalize_to_macros_2_0(); - if let Some(entry) = self.r.extern_prelude.get(&ident) { - if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() { - self.r.dcx().emit_err( - errors::MacroExpandedExternCrateCannotShadowExternArguments { - span: item.span, - }, - ); - // `return` is intended to discard this binding because it's an - // unregistered ambiguity error which would result in a panic - // caused by inconsistency `path_res` - // more details: https://github.com/rust-lang/rust/pull/111761 - return; - } + if let Some(entry) = self.r.extern_prelude.get(&ident) + && expansion != LocalExpnId::ROOT + && orig_name.is_some() + && !entry.is_import() + { + self.r.dcx().emit_err( + errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span }, + ); + // `return` is intended to discard this binding because it's an + // unregistered ambiguity error which would result in a panic + // caused by inconsistency `path_res` + // more details: https://github.com/rust-lang/rust/pull/111761 + return; } let entry = self .r @@ -1040,10 +1040,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span: item.span, }); } - if let ItemKind::ExternCrate(Some(orig_name)) = item.kind { - if orig_name == kw::SelfLower { - self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); - } + if let ItemKind::ExternCrate(Some(orig_name)) = item.kind + && orig_name == kw::SelfLower + { + self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); } let ill_formed = |span| { self.r.dcx().emit_err(errors::BadMacroImport { span }); @@ -1179,14 +1179,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { return Some((MacroKind::Bang, item.ident, item.span)); } else if ast::attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(meta_item_inner) = + } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) + && let Some(meta_item_inner) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) - { - if let Some(ident) = meta_item_inner.ident() { - return Some((MacroKind::Derive, ident, ident.span)); - } - } + && let Some(ident) = meta_item_inner.ident() + { + return Some((MacroKind::Derive, ident, ident.span)); } None } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 3b6603536c735..ef11d4a9a918c 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -225,10 +225,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (name, span) = (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span)); - if let Some(s) = self.name_already_seen.get(&name) { - if s == &span { - return; - } + if self.name_already_seen.get(&name) == Some(&span) { + return; } let old_kind = match (ns, old_binding.module()) { @@ -380,20 +378,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion = Some(format!("self as {suggested_name}")) } ImportKind::Single { source, .. } => { - if let Some(pos) = - source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize) + if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) + && pos as usize <= snippet.len() { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) { - if pos <= snippet.len() { - span = binding_span - .with_lo(binding_span.lo() + BytePos(pos as u32)) - .with_hi( - binding_span.hi() - - BytePos(if snippet.ends_with(';') { 1 } else { 0 }), - ); - suggestion = Some(format!(" as {suggested_name}")); - } - } + span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi( + binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }), + ); + suggestion = Some(format!(" as {suggested_name}")); } } ImportKind::ExternCrate { source, target, .. } => { @@ -510,13 +502,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If the first element of our path was actually resolved to an // `ExternCrate` (also used for `crate::...`) then no need to issue a // warning, this looks all good! - if let Some(binding) = second_binding { - if let NameBindingKind::Import { import, .. } = binding.kind { - // Careful: we still want to rewrite paths from renamed extern crates. - if let ImportKind::ExternCrate { source: None, .. } = import.kind { - return; - } - } + if let Some(binding) = second_binding + && let NameBindingKind::Import { import, .. } = binding.kind + // Careful: we still want to rewrite paths from renamed extern crates. + && let ImportKind::ExternCrate { source: None, .. } = import.kind + { + return; } let diag = BuiltinLintDiag::AbsPathWithModule(root_span); @@ -1215,12 +1206,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // #90113: Do not count an inaccessible reexported item as a candidate. - if let NameBindingKind::Import { binding, .. } = name_binding.kind { - if this.is_accessible_from(binding.vis, parent_scope.module) - && !this.is_accessible_from(name_binding.vis, parent_scope.module) - { - return; - } + if let NameBindingKind::Import { binding, .. } = name_binding.kind + && this.is_accessible_from(binding.vis, parent_scope.module) + && !this.is_accessible_from(name_binding.vis, parent_scope.module) + { + return; } let res = name_binding.res(); @@ -1253,14 +1243,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { segms.push(ast::PathSegment::from_ident(ident)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; - if child_accessible { + if child_accessible // Remove invisible match if exists - if let Some(idx) = candidates + && let Some(idx) = candidates .iter() .position(|v: &ImportSuggestion| v.did == did && !v.accessible) - { - candidates.remove(idx); - } + { + candidates.remove(idx); } if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { @@ -1545,19 +1534,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_kind.descr_expected(), ), }; - if let crate::NameBindingKind::Import { import, .. } = binding.kind { - if !import.span.is_dummy() { - let note = errors::IdentImporterHereButItIsDesc { - span: import.span, - imported_ident: ident, - imported_ident_desc: &desc, - }; - err.subdiagnostic(note); - // Silence the 'unused import' warning we might get, - // since this diagnostic already covers that import. - self.record_use(ident, binding, Used::Other); - return; - } + if let crate::NameBindingKind::Import { import, .. } = binding.kind + && !import.span.is_dummy() + { + let note = errors::IdentImporterHereButItIsDesc { + span: import.span, + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(note); + // Silence the 'unused import' warning we might get, + // since this diagnostic already covers that import. + self.record_use(ident, binding, Used::Other); + return; } let note = errors::IdentInScopeButItIsDesc { imported_ident: ident, @@ -2436,20 +2425,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { debug!(found_closing_brace, ?binding_span); let mut removal_span = binding_span; - if found_closing_brace { - // If the binding span ended with a closing brace, as in the below example: - // ie. `use a::b::{c, d};` - // ^ - // Then expand the span of characters to remove to include the previous - // binding's trailing comma. - // ie. `use a::b::{c, d};` - // ^^^ - if let Some(previous_span) = + + // If the binding span ended with a closing brace, as in the below example: + // ie. `use a::b::{c, d};` + // ^ + // Then expand the span of characters to remove to include the previous + // binding's trailing comma. + // ie. `use a::b::{c, d};` + // ^^^ + if found_closing_brace + && let Some(previous_span) = extend_span_to_previous_binding(self.tcx.sess, binding_span) - { - debug!(?previous_span); - removal_span = removal_span.with_lo(previous_span.lo()); - } + { + debug!(?previous_span); + removal_span = removal_span.with_lo(previous_span.lo()); } debug!(?removal_span); @@ -3064,16 +3053,16 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { fn search_for_any_use_in_items(items: &[P]) -> Option { for item in items { - if let ItemKind::Use(..) = item.kind { - if is_span_suitable_for_use_injection(item.span) { - let mut lo = item.span.lo(); - for attr in &item.attrs { - if attr.span.eq_ctxt(item.span) { - lo = std::cmp::min(lo, attr.span.lo()); - } + if let ItemKind::Use(..) = item.kind + && is_span_suitable_for_use_injection(item.span) + { + let mut lo = item.span.lo(); + for attr in &item.attrs { + if attr.span.eq_ctxt(item.span) { + lo = std::cmp::min(lo, attr.span.lo()); } - return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } + return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } } None diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 45e87edc53e96..a3d3e87ade005 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -246,23 +246,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // ---- end // ``` // So we have to fall back to the module's parent during lexical resolution in this case. - if derive_fallback_lint_id.is_some() { - if let Some(parent) = module.parent { - // Inner module is inside the macro, parent module is outside of the macro. - if module.expansion != parent.expansion - && module.expansion.is_descendant_of(parent.expansion) - { - // The macro is a proc macro derive - if let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = &self.get_macro_by_def_id(def_id).ext; - if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive - && parent.expansion.outer_expn_is_descendant_of(*ctxt) - { - return Some((parent, derive_fallback_lint_id)); - } - } - } + if derive_fallback_lint_id.is_some() + && let Some(parent) = module.parent + // Inner module is inside the macro + && module.expansion != parent.expansion + // Parent module is outside of the macro + && module.expansion.is_descendant_of(parent.expansion) + // The macro is a proc macro derive + && let Some(def_id) = module.expansion.expn_data().macro_def_id + { + let ext = &self.get_macro_by_def_id(def_id).ext; + if ext.builtin_name.is_none() + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(*ctxt) + { + return Some((parent, derive_fallback_lint_id)); } } @@ -593,8 +591,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); - if let Some(prelude) = this.prelude { - if let Ok(binding) = this.resolve_ident_in_module_unadjusted( + if let Some(prelude) = this.prelude + && let Ok(binding) = this.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(prelude), ident, ns, @@ -603,14 +601,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, ignore_binding, ignore_import, - ) { - if matches!(use_prelude, UsePrelude::Yes) - || this.is_builtin_macro(binding.res()) - { - result = Ok((binding, Flags::MISC_FROM_PRELUDE)); - } - } + ) + && (matches!(use_prelude, UsePrelude::Yes) + || this.is_builtin_macro(binding.res())) + { + result = Ok((binding, Flags::MISC_FROM_PRELUDE)); } + result } Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) { @@ -939,10 +936,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; // Items and single imports are not shadowable, if we have one, then it's determined. - if let Some(binding) = binding { - if !binding.is_glob_import() { - return check_usable(self, binding); - } + if let Some(binding) = binding + && !binding.is_glob_import() + { + return check_usable(self, binding); } // --- From now on we either have a glob resolution or no resolution. --- @@ -1437,13 +1434,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); let record_segment_res = |this: &mut Self, res| { - if finalize.is_some() { - if let Some(id) = id { - if !this.partial_res_map.contains_key(&id) { - assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_partial_res(id, PartialRes::new(res)); - } - } + if finalize.is_some() + && let Some(id) = id + && !this.partial_res_map.contains_key(&id) + { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + this.record_partial_res(id, PartialRes::new(res)); } }; @@ -1463,13 +1459,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => None, }, }; - if let Some(self_module) = self_module { - if let Some(parent) = self_module.parent { - module = Some(ModuleOrUniformRoot::Module( - self.resolve_self(&mut ctxt, parent), - )); - continue; - } + if let Some(self_module) = self_module + && let Some(parent) = self_module.parent + { + module = + Some(ModuleOrUniformRoot::Module(self.resolve_self(&mut ctxt, parent))); + continue; } return PathResult::failed( ident, @@ -1644,13 +1639,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Err(Undetermined) => return PathResult::Indeterminate, Err(Determined) => { - if let Some(ModuleOrUniformRoot::Module(module)) = module { - if opt_ns.is_some() && !module.is_normal() { - return PathResult::NonModule(PartialRes::with_unresolved_segments( - module.res().unwrap(), - path.len() - segment_idx, - )); - } + if let Some(ModuleOrUniformRoot::Module(module)) = module + && opt_ns.is_some() + && !module.is_normal() + { + return PathResult::NonModule(PartialRes::with_unresolved_segments( + module.res().unwrap(), + path.len() - segment_idx, + )); } return PathResult::failed( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 29b4d913c82da..2bfb068c839a7 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -287,12 +287,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding.vis }; - if let ImportKind::Glob { ref max_vis, .. } = import.kind { - if vis == import_vis - || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)) - { - max_vis.set(Some(vis.expect_local())) - } + if let ImportKind::Glob { ref max_vis, .. } = import.kind + && (vis == import_vis + || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))) + { + max_vis.set(Some(vis.expect_local())) } self.arenas.alloc_name_binding(NameBindingData { @@ -546,13 +545,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(err) = unresolved_import_error { glob_error |= import.is_glob(); - if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { - if source.name == kw::SelfLower { - // Silence `unresolved import` error if E0429 is already emitted - if let Err(Determined) = source_bindings.value_ns.get() { - continue; - } - } + if let ImportKind::Single { source, ref source_bindings, .. } = import.kind + && source.name == kw::SelfLower + // Silence `unresolved import` error if E0429 is already emitted + && let Err(Determined) = source_bindings.value_ns.get() + { + continue; } if prev_root_id != NodeId::ZERO @@ -1006,21 +1004,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); } - if let ModuleOrUniformRoot::Module(module) = module { - if module == import.parent_scope.module { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { - span: import.span, - label: Some(String::from( - "cannot glob-import a module into itself", - )), - note: None, - suggestion: None, - candidates: None, - segment: None, - module: None, - }); - } + if let ModuleOrUniformRoot::Module(module) = module + && module == import.parent_scope.module + { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from("cannot glob-import a module into itself")), + note: None, + suggestion: None, + candidates: None, + segment: None, + module: None, + }); } if !is_prelude && let Some(max_vis) = max_vis.get() @@ -1081,18 +1077,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Consistency checks, analogous to `finalize_macro_resolutions`. let initial_res = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; - if let Some(target_binding) = target_bindings[ns].get() { - if target.name == kw::Underscore - && initial_binding.is_extern_crate() - && !initial_binding.is_import() - { - let used = if import.module_path.is_empty() { - Used::Scope - } else { - Used::Other - }; - this.record_use(ident, target_binding, used); - } + if let Some(target_binding) = target_bindings[ns].get() + && target.name == kw::Underscore + && initial_binding.is_extern_crate() + && !initial_binding.is_import() + { + let used = if import.module_path.is_empty() { + Used::Scope + } else { + Used::Other + }; + this.record_use(ident, target_binding, used); } initial_binding.res() }); @@ -1250,10 +1245,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Ok(binding) = source_bindings[ns].get() { if !binding.vis.is_at_least(import.vis, this.tcx) { reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis { - if binding_def_id.is_top_level_module() { - crate_private_reexport = true; - } + if let ty::Visibility::Restricted(binding_def_id) = binding.vis + && binding_def_id.is_top_level_module() + { + crate_private_reexport = true; } } else { any_successful_reexport = true; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bbcbb5d1ce474..c1e7f3277f34a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -468,16 +468,12 @@ impl<'a> PathSource<'a> { { "external crate" } - ExprKind::Path(_, path) => { - let mut msg = "function"; - if let Some(segment) = path.segments.iter().last() { - if let Some(c) = segment.ident.to_string().chars().next() { - if c.is_uppercase() { - msg = "function, tuple struct or tuple variant"; - } - } - } - msg + ExprKind::Path(_, path) + if let Some(segment) = path.segments.last() + && let Some(c) = segment.ident.to_string().chars().next() + && c.is_uppercase() => + { + "function, tuple struct or tuple variant" } _ => "function", }, @@ -1182,32 +1178,27 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r // namespace first, and if that fails we try again in the value namespace. If // resolution in the value namespace succeeds, we have an generic const argument on // our hands. - if let TyKind::Path(None, ref path) = ty.kind { + if let TyKind::Path(None, ref path) = ty.kind // We cannot disambiguate multi-segment paths right now as that requires type // checking. - if path.is_potential_trivial_const_arg() { - let mut check_ns = |ns| { - self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) - .is_some() - }; - if !check_ns(TypeNS) && check_ns(ValueNS) { - self.resolve_anon_const_manual( - true, - AnonConstKind::ConstArg(IsRepeatExpr::No), - |this| { - this.smart_resolve_path( - ty.id, - &None, - path, - PathSource::Expr(None), - ); - this.visit_path(path, ty.id); - }, - ); + && path.is_potential_trivial_const_arg() + { + let mut check_ns = |ns| { + self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) + .is_some() + }; + if !check_ns(TypeNS) && check_ns(ValueNS) { + self.resolve_anon_const_manual( + true, + AnonConstKind::ConstArg(IsRepeatExpr::No), + |this| { + this.smart_resolve_path(ty.id, &None, path, PathSource::Expr(None)); + this.visit_path(path, ty.id); + }, + ); - self.diag_metadata.currently_processing_generic_args = prev; - return; - } + self.diag_metadata.currently_processing_generic_args = prev; + return; } } @@ -2460,12 +2451,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for i in (0..self.label_ribs.len()).rev() { let rib = &self.label_ribs[i]; - if let RibKind::MacroDefinition(def) = rib.kind { + if let RibKind::MacroDefinition(def) = rib.kind // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - if def == self.r.macro_def(label.span.ctxt()) { - label.span.remove_mark(); - } + && def == self.r.macro_def(label.span.ctxt()) + { + label.span.remove_mark(); } let ident = label.normalize_to_macro_rules(); From ae87d005bc92cbecc47b554e634d1bd3d22e1068 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 20 Jan 2025 20:35:45 +0000 Subject: [PATCH 12/23] =?UTF-8?q?rustc=5Fresolve:=20reduce=20rightwards=20?= =?UTF-8?q?drift=20with=20`let..else`=20=F0=9F=91=89=F0=9F=92=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compiler/rustc_resolve/src/diagnostics.rs | 394 +++++++++--------- .../src/effective_visibilities.rs | 59 +-- compiler/rustc_resolve/src/imports.rs | 198 ++++----- compiler/rustc_resolve/src/late.rs | 117 +++--- 4 files changed, 387 insertions(+), 381 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ef11d4a9a918c..01496a6aec511 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1038,20 +1038,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - if let Ok((Some(ext), _)) = this.resolve_macro_path( + let Ok((Some(ext), _)) = this.resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, false, false, None, - ) { - suggestions.extend( - ext.helper_attrs - .iter() - .map(|name| TypoSuggestion::typo_from_name(*name, res)), - ); - } + ) else { + continue; + }; + suggestions.extend( + ext.helper_attrs + .iter() + .map(|name| TypoSuggestion::typo_from_name(*name, res)), + ); } } } @@ -1362,48 +1363,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // otherwise cause duplicate suggestions. continue; } - let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)); - if let Some(crate_id) = crate_id { - let crate_def_id = crate_id.as_def_id(); - let crate_root = self.expect_module(crate_def_id); - - // Check if there's already an item in scope with the same name as the crate. - // If so, we have to disambiguate the potential import suggestions by making - // the paths *global* (i.e., by prefixing them with `::`). - let needs_disambiguation = - self.resolutions(parent_scope.module).borrow().iter().any( - |(key, name_resolution)| { - if key.ns == TypeNS - && key.ident == ident - && let Some(binding) = name_resolution.borrow().binding - { - match binding.res() { - // No disambiguation needed if the identically named item we - // found in scope actually refers to the crate in question. - Res::Def(_, def_id) => def_id != crate_def_id, - Res::PrimTy(_) => true, - _ => false, - } - } else { - false - } - }, - ); - let mut crate_path = ThinVec::new(); - if needs_disambiguation { - crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); - } - crate_path.push(ast::PathSegment::from_ident(ident)); + let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)) + else { + continue; + }; - suggestions.extend(self.lookup_import_candidates_from_module( - lookup_ident, - namespace, - parent_scope, - crate_root, - crate_path, - &filter_fn, - )); + let crate_def_id = crate_id.as_def_id(); + let crate_root = self.expect_module(crate_def_id); + + // Check if there's already an item in scope with the same name as the crate. + // If so, we have to disambiguate the potential import suggestions by making + // the paths *global* (i.e., by prefixing them with `::`). + let needs_disambiguation = + self.resolutions(parent_scope.module).borrow().iter().any( + |(key, name_resolution)| { + if key.ns == TypeNS + && key.ident == ident + && let Some(binding) = name_resolution.borrow().binding + { + match binding.res() { + // No disambiguation needed if the identically named item we + // found in scope actually refers to the crate in question. + Res::Def(_, def_id) => def_id != crate_def_id, + Res::PrimTy(_) => true, + _ => false, + } + } else { + false + } + }, + ); + let mut crate_path = ThinVec::new(); + if needs_disambiguation { + crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); } + crate_path.push(ast::PathSegment::from_ident(ident)); + + suggestions.extend(self.lookup_import_candidates_from_module( + lookup_ident, + namespace, + parent_scope, + crate_root, + crate_path, + &filter_fn, + )); } } @@ -1500,7 +1503,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + let Ok(binding) = self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -1508,53 +1511,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false, None, None, - ) { - let desc = match binding.res() { - Res::Def(DefKind::Macro(MacroKind::Bang), _) => { - "a function-like macro".to_string() - } - Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { - format!("an attribute: `#[{ident}]`") - } - Res::Def(DefKind::Macro(MacroKind::Derive), _) => { - format!("a derive macro: `#[derive({ident})]`") - } - Res::ToolMod => { - // Don't confuse the user with tool modules. - continue; - } - Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { - "only a trait, without a derive macro".to_string() - } - res => format!( - "{} {}, not {} {}", - res.article(), - res.descr(), - macro_kind.article(), - macro_kind.descr_expected(), - ), - }; - if let crate::NameBindingKind::Import { import, .. } = binding.kind - && !import.span.is_dummy() - { - let note = errors::IdentImporterHereButItIsDesc { - span: import.span, - imported_ident: ident, - imported_ident_desc: &desc, - }; - err.subdiagnostic(note); - // Silence the 'unused import' warning we might get, - // since this diagnostic already covers that import. - self.record_use(ident, binding, Used::Other); - return; + ) else { + continue; + }; + + let desc = match binding.res() { + Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(), + Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { + format!("an attribute: `#[{ident}]`") } - let note = errors::IdentInScopeButItIsDesc { + Res::Def(DefKind::Macro(MacroKind::Derive), _) => { + format!("a derive macro: `#[derive({ident})]`") + } + Res::ToolMod => { + // Don't confuse the user with tool modules. + continue; + } + Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { + "only a trait, without a derive macro".to_string() + } + res => format!( + "{} {}, not {} {}", + res.article(), + res.descr(), + macro_kind.article(), + macro_kind.descr_expected(), + ), + }; + if let crate::NameBindingKind::Import { import, .. } = binding.kind + && !import.span.is_dummy() + { + let note = errors::IdentImporterHereButItIsDesc { + span: import.span, imported_ident: ident, imported_ident_desc: &desc, }; err.subdiagnostic(note); + // Silence the 'unused import' warning we might get, + // since this diagnostic already covers that import. + self.record_use(ident, binding, Used::Other); return; } + let note = errors::IdentInScopeButItIsDesc { + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(note); + return; } } @@ -1738,15 +1741,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option { - if let NameBindingKind::Res(Res::Def( + let NameBindingKind::Res(Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id, )) = binding.kind - { - let def_id = self.tcx.parent(ctor_def_id); - return self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to); // None for `struct Foo()` - } - None + else { + return None; + }; + + let def_id = self.tcx.parent(ctor_def_id); + self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()` } fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { @@ -2399,115 +2403,115 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let binding_key = BindingKey::new(ident, MacroNS); let resolution = resolutions.get(&binding_key)?; let binding = resolution.borrow().binding()?; - if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { - let module_name = crate_module.kind.name().unwrap(); - let import_snippet = match import.kind { - ImportKind::Single { source, target, .. } if source != target => { - format!("{source} as {target}") - } - _ => format!("{ident}"), - }; + let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { + return None; + }; + let module_name = crate_module.kind.name().unwrap(); + let import_snippet = match import.kind { + ImportKind::Single { source, target, .. } if source != target => { + format!("{source} as {target}") + } + _ => format!("{ident}"), + }; - let mut corrections: Vec<(Span, String)> = Vec::new(); - if !import.is_nested() { - // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove - // intermediate segments. - corrections.push((import.span, format!("{module_name}::{import_snippet}"))); - } else { - // Find the binding span (and any trailing commas and spaces). - // ie. `use a::b::{c, d, e};` - // ^^^ - let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( - self.tcx.sess, - import.span, - import.use_span, - ); - debug!(found_closing_brace, ?binding_span); - - let mut removal_span = binding_span; - - // If the binding span ended with a closing brace, as in the below example: - // ie. `use a::b::{c, d};` - // ^ - // Then expand the span of characters to remove to include the previous - // binding's trailing comma. - // ie. `use a::b::{c, d};` - // ^^^ - if found_closing_brace - && let Some(previous_span) = - extend_span_to_previous_binding(self.tcx.sess, binding_span) - { - debug!(?previous_span); - removal_span = removal_span.with_lo(previous_span.lo()); - } - debug!(?removal_span); - - // Remove the `removal_span`. - corrections.push((removal_span, "".to_string())); - - // Find the span after the crate name and if it has nested imports immediately - // after the crate name already. - // ie. `use a::b::{c, d};` - // ^^^^^^^^^ - // or `use a::{b, c, d}};` - // ^^^^^^^^^^^ - let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( - self.tcx.sess, - module_name, - import.use_span, - ); - debug!(has_nested, ?after_crate_name); + let mut corrections: Vec<(Span, String)> = Vec::new(); + if !import.is_nested() { + // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove + // intermediate segments. + corrections.push((import.span, format!("{module_name}::{import_snippet}"))); + } else { + // Find the binding span (and any trailing commas and spaces). + // ie. `use a::b::{c, d, e};` + // ^^^ + let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( + self.tcx.sess, + import.span, + import.use_span, + ); + debug!(found_closing_brace, ?binding_span); + + let mut removal_span = binding_span; + + // If the binding span ended with a closing brace, as in the below example: + // ie. `use a::b::{c, d};` + // ^ + // Then expand the span of characters to remove to include the previous + // binding's trailing comma. + // ie. `use a::b::{c, d};` + // ^^^ + if found_closing_brace + && let Some(previous_span) = + extend_span_to_previous_binding(self.tcx.sess, binding_span) + { + debug!(?previous_span); + removal_span = removal_span.with_lo(previous_span.lo()); + } + debug!(?removal_span); - let source_map = self.tcx.sess.source_map(); + // Remove the `removal_span`. + corrections.push((removal_span, "".to_string())); - // Make sure this is actually crate-relative. - let is_definitely_crate = import - .module_path - .first() - .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); + // Find the span after the crate name and if it has nested imports immediately + // after the crate name already. + // ie. `use a::b::{c, d};` + // ^^^^^^^^^ + // or `use a::{b, c, d}};` + // ^^^^^^^^^^^ + let (has_nested, after_crate_name) = + find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span); + debug!(has_nested, ?after_crate_name); - // Add the import to the start, with a `{` if required. - let start_point = source_map.start_point(after_crate_name); - if is_definitely_crate - && let Ok(start_snippet) = source_map.span_to_snippet(start_point) - { - corrections.push(( - start_point, - if has_nested { - // In this case, `start_snippet` must equal '{'. - format!("{start_snippet}{import_snippet}, ") - } else { - // In this case, add a `{`, then the moved import, then whatever - // was there before. - format!("{{{import_snippet}, {start_snippet}") - }, - )); + let source_map = self.tcx.sess.source_map(); - // Add a `};` to the end if nested, matching the `{` added at the start. - if !has_nested { - corrections - .push((source_map.end_point(after_crate_name), "};".to_string())); - } - } else { - // If the root import is module-relative, add the import separately - corrections.push(( - import.use_span.shrink_to_lo(), - format!("use {module_name}::{import_snippet};\n"), - )); + // Make sure this is actually crate-relative. + let is_definitely_crate = import + .module_path + .first() + .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); + + // Add the import to the start, with a `{` if required. + let start_point = source_map.start_point(after_crate_name); + if is_definitely_crate + && let Ok(start_snippet) = source_map.span_to_snippet(start_point) + { + corrections.push(( + start_point, + if has_nested { + // In this case, `start_snippet` must equal '{'. + format!("{start_snippet}{import_snippet}, ") + } else { + // In this case, add a `{`, then the moved import, then whatever + // was there before. + format!("{{{import_snippet}, {start_snippet}") + }, + )); + + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), "};".to_string())); } + } else { + // If the root import is module-relative, add the import separately + corrections.push(( + import.use_span.shrink_to_lo(), + format!("use {module_name}::{import_snippet};\n"), + )); } + } - let suggestion = Some(( - corrections, - String::from("a macro with this name exists at the root of the crate"), - Applicability::MaybeIncorrect, - )); - Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \ + let suggestion = Some(( + corrections, + String::from("a macro with this name exists at the root of the crate"), + Applicability::MaybeIncorrect, + )); + Some(( + suggestion, + Some( + "this could be because a macro annotated with `#[macro_export]` will be exported \ at the root of the crate instead of the module where it is defined" - .to_string()))) - } else { - None - } + .to_string(), + ), + )) } /// Finds a cfg-ed out item inside `module` with the matching name. diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index e279d14704e05..6ef4aa407253d 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -118,37 +118,38 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { - if let Some(mut binding) = name_resolution.borrow().binding() { - // Set the given effective visibility level to `Level::Direct` and - // sets the rest of the `use` chain to `Level::Reexported` until - // we hit the actual exported item. - // - // If the binding is ambiguous, put the root ambiguity binding and all reexports - // leading to it into the table. They are used by the `ambiguous_glob_reexports` - // lint. For all bindings added to the table this way `is_ambiguity` returns true. - let is_ambiguity = - |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; - let mut parent_id = ParentId::Def(module_id); - let mut warn_ambiguity = binding.warn_ambiguity; - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { - self.update_import(binding, parent_id); + let Some(mut binding) = name_resolution.borrow().binding() else { + continue; + }; + // Set the given effective visibility level to `Level::Direct` and + // sets the rest of the `use` chain to `Level::Reexported` until + // we hit the actual exported item. + // + // If the binding is ambiguous, put the root ambiguity binding and all reexports + // leading to it into the table. They are used by the `ambiguous_glob_reexports` + // lint. For all bindings added to the table this way `is_ambiguity` returns true. + let is_ambiguity = + |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; + let mut parent_id = ParentId::Def(module_id); + let mut warn_ambiguity = binding.warn_ambiguity; + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { + self.update_import(binding, parent_id); - if is_ambiguity(binding, warn_ambiguity) { - // Stop at the root ambiguity, further bindings in the chain should not - // be reexported because the root ambiguity blocks any access to them. - // (Those further bindings are most likely not ambiguities themselves.) - break; - } - - parent_id = ParentId::Import(binding); - binding = nested_binding; - warn_ambiguity |= nested_binding.warn_ambiguity; - } - if !is_ambiguity(binding, warn_ambiguity) - && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) - { - self.update_def(def_id, binding.vis.expect_local(), parent_id); + if is_ambiguity(binding, warn_ambiguity) { + // Stop at the root ambiguity, further bindings in the chain should not + // be reexported because the root ambiguity blocks any access to them. + // (Those further bindings are most likely not ambiguities themselves.) + break; } + + parent_id = ParentId::Import(binding); + binding = nested_binding; + warn_ambiguity |= nested_binding.warn_ambiguity; + } + if !is_ambiguity(binding, warn_ambiguity) + && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) + { + self.update_def(def_id, binding.vis.expect_local(), parent_id); } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 2bfb068c839a7..d555c93877035 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -542,30 +542,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(*import, is_indeterminate); - if let Some(err) = unresolved_import_error { - glob_error |= import.is_glob(); + let Some(err) = unresolved_import_error else { continue }; - if let ImportKind::Single { source, ref source_bindings, .. } = import.kind - && source.name == kw::SelfLower - // Silence `unresolved import` error if E0429 is already emitted - && let Err(Determined) = source_bindings.value_ns.get() - { - continue; - } + glob_error |= import.is_glob(); - if prev_root_id != NodeId::ZERO - && prev_root_id != import.root_id - && !errors.is_empty() - { - // In the case of a new import line, throw a diagnostic message - // for the previous line. - self.throw_unresolved_import_error(errors, glob_error); - errors = vec![]; - } - if seen_spans.insert(err.span) { - errors.push((*import, err)); - prev_root_id = import.root_id; - } + if let ImportKind::Single { source, ref source_bindings, .. } = import.kind + && source.name == kw::SelfLower + // Silence `unresolved import` error if E0429 is already emitted + && let Err(Determined) = source_bindings.value_ns.get() + { + continue; + } + + if prev_root_id != NodeId::ZERO && prev_root_id != import.root_id && !errors.is_empty() + { + // In the case of a new import line, throw a diagnostic message + // for the previous line. + self.throw_unresolved_import_error(errors, glob_error); + errors = vec![]; + } + if seen_spans.insert(err.span) { + errors.push((*import, err)); + prev_root_id = import.root_id; } } @@ -607,60 +605,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - if let Some(binding) = resolution.binding { - if let NameBindingKind::Import { import, .. } = binding.kind - && let Some((amb_binding, _)) = binding.ambiguity - && binding.res() != Res::Err - && exported_ambiguities.contains(&binding) + let Some(binding) = resolution.binding else { continue }; + + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&binding) + { + self.lint_buffer.buffer_lint( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + BuiltinLintDiag::AmbiguousGlobReexports { + name: key.ident.to_string(), + namespace: key.ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + + if let Some(glob_binding) = resolution.shadowed_glob { + let binding_id = match binding.kind { + NameBindingKind::Res(res) => { + Some(self.def_id_to_node_id[res.def_id().expect_local()]) + } + NameBindingKind::Module(module) => { + Some(self.def_id_to_node_id[module.def_id().expect_local()]) + } + NameBindingKind::Import { import, .. } => import.id(), + }; + + if binding.res() != Res::Err + && glob_binding.res() != Res::Err + && let NameBindingKind::Import { import: glob_import, .. } = + glob_binding.kind + && let Some(binding_id) = binding_id + && let Some(glob_import_id) = glob_import.id() + && let glob_import_def_id = self.local_def_id(glob_import_id) + && self.effective_visibilities.is_exported(glob_import_def_id) + && glob_binding.vis.is_public() + && !binding.vis.is_public() { self.lint_buffer.buffer_lint( - AMBIGUOUS_GLOB_REEXPORTS, - import.root_id, - import.root_span, - BuiltinLintDiag::AmbiguousGlobReexports { - name: key.ident.to_string(), - namespace: key.ns.descr().to_string(), - first_reexport_span: import.root_span, - duplicate_reexport_span: amb_binding.span, + HIDDEN_GLOB_REEXPORTS, + binding_id, + binding.span, + BuiltinLintDiag::HiddenGlobReexports { + name: key.ident.name.to_string(), + namespace: key.ns.descr().to_owned(), + glob_reexport_span: glob_binding.span, + private_item_span: binding.span, }, ); } - - if let Some(glob_binding) = resolution.shadowed_glob { - let binding_id = match binding.kind { - NameBindingKind::Res(res) => { - Some(self.def_id_to_node_id[res.def_id().expect_local()]) - } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id[module.def_id().expect_local()]) - } - NameBindingKind::Import { import, .. } => import.id(), - }; - - if binding.res() != Res::Err - && glob_binding.res() != Res::Err - && let NameBindingKind::Import { import: glob_import, .. } = - glob_binding.kind - && let Some(binding_id) = binding_id - && let Some(glob_import_id) = glob_import.id() - && let glob_import_def_id = self.local_def_id(glob_import_id) - && self.effective_visibilities.is_exported(glob_import_def_id) - && glob_binding.vis.is_public() - && !binding.vis.is_public() - { - self.lint_buffer.buffer_lint( - HIDDEN_GLOB_REEXPORTS, - binding_id, - binding.span, - BuiltinLintDiag::HiddenGlobReexports { - name: key.ident.name.to_string(), - namespace: key.ns.descr().to_owned(), - glob_reexport_span: glob_binding.span, - private_item_span: binding.span, - }, - ); - } - } } } } @@ -1242,17 +1240,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut any_successful_reexport = false; let mut crate_private_reexport = false; self.per_ns(|this, ns| { - if let Ok(binding) = source_bindings[ns].get() { - if !binding.vis.is_at_least(import.vis, this.tcx) { - reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis - && binding_def_id.is_top_level_module() - { - crate_private_reexport = true; - } - } else { - any_successful_reexport = true; + let Ok(binding) = source_bindings[ns].get() else { + return; + }; + + if !binding.vis.is_at_least(import.vis, this.tcx) { + reexport_error = Some((ns, binding)); + if let ty::Visibility::Restricted(binding_def_id) = binding.vis + && binding_def_id.is_top_level_module() + { + crate_private_reexport = true; } + } else { + any_successful_reexport = true; } }); @@ -1469,28 +1469,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut() = Vec::new(); - if let Some(def_id) = module.opt_def_id() { - let mut children = Vec::new(); - - module.for_each_child(self, |this, ident, _, binding| { - let res = binding.res().expect_non_local(); - let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; - if res != def::Res::Err && !error_ambiguity { - let mut reexport_chain = SmallVec::new(); - let mut next_binding = binding; - while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { - reexport_chain.push(import.simplify(this)); - next_binding = binding; - } + let Some(def_id) = module.opt_def_id() else { return }; + + let mut children = Vec::new(); - children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); + module.for_each_child(self, |this, ident, _, binding| { + let res = binding.res().expect_non_local(); + let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; + if res != def::Res::Err && !error_ambiguity { + let mut reexport_chain = SmallVec::new(); + let mut next_binding = binding; + while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { + reexport_chain.push(import.simplify(this)); + next_binding = binding; } - }); - if !children.is_empty() { - // Should be fine because this code is only called for local modules. - self.module_children.insert(def_id.expect_local(), children); + children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); } + }); + + if !children.is_empty() { + // Should be fine because this code is only called for local modules. + self.module_children.insert(def_id.expect_local(), children); } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c1e7f3277f34a..5072145d61eae 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1234,54 +1234,56 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { - if let Some(ref args) = path_segment.args { - match &**args { - GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args), - GenericArgs::Parenthesized(p_args) => { - // Probe the lifetime ribs to know how to behave. - for rib in self.lifetime_ribs.iter().rev() { - match rib.kind { - // We are inside a `PolyTraitRef`. The lifetimes are - // to be introduced in that (maybe implicit) `for<>` binder. - LifetimeRibKind::Generics { - binder, - kind: LifetimeBinderKind::PolyTrait, - .. - } => { - self.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { + let Some(ref args) = path_segment.args else { + return; + }; + + match &**args { + GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args), + GenericArgs::Parenthesized(p_args) => { + // Probe the lifetime ribs to know how to behave. + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + // We are inside a `PolyTraitRef`. The lifetimes are + // to be introduced in that (maybe implicit) `for<>` binder. + LifetimeRibKind::Generics { + binder, + kind: LifetimeBinderKind::PolyTrait, + .. + } => { + self.with_lifetime_rib( + LifetimeRibKind::AnonymousCreateParameter { + binder, + report_in_path: false, + }, + |this| { + this.resolve_fn_signature( binder, - report_in_path: false, - }, - |this| { - this.resolve_fn_signature( - binder, - false, - p_args.inputs.iter().map(|ty| (None, &**ty)), - &p_args.output, - ) - }, - ); - break; - } - // We have nowhere to introduce generics. Code is malformed, - // so use regular lifetime resolution to avoid spurious errors. - LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { - visit::walk_generic_args(self, args); - break; - } - LifetimeRibKind::AnonymousCreateParameter { .. } - | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } - | LifetimeRibKind::Elided(_) - | LifetimeRibKind::ElisionFailure - | LifetimeRibKind::ConcreteAnonConst(_) - | LifetimeRibKind::ConstParamTy => {} + false, + p_args.inputs.iter().map(|ty| (None, &**ty)), + &p_args.output, + ) + }, + ); + break; } + // We have nowhere to introduce generics. Code is malformed, + // so use regular lifetime resolution to avoid spurious errors. + LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { + visit::walk_generic_args(self, args); + break; + } + LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } + | LifetimeRibKind::Elided(_) + | LifetimeRibKind::ElisionFailure + | LifetimeRibKind::ConcreteAnonConst(_) + | LifetimeRibKind::ConstParamTy => {} } } - GenericArgs::ParenthesizedElided(_) => {} } + GenericArgs::ParenthesizedElided(_) => {} } } @@ -3496,21 +3498,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.visit_ty(&qself.ty); } self.visit_path(&delegation.path, delegation.id); - if let Some(body) = &delegation.body { - self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { - // `PatBoundCtx` is not necessary in this context - let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; - - let span = delegation.path.segments.last().unwrap().ident.span; - this.fresh_binding( - Ident::new(kw::SelfLower, span), - delegation.id, - PatternSource::FnParam, - &mut bindings, - ); - this.visit_block(body); - }); - } + let Some(body) = &delegation.body else { return }; + self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { + // `PatBoundCtx` is not necessary in this context + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + + let span = delegation.path.segments.last().unwrap().ident.span; + this.fresh_binding( + Ident::new(kw::SelfLower, span), + delegation.id, + PatternSource::FnParam, + &mut bindings, + ); + this.visit_block(body); + }); } fn resolve_params(&mut self, params: &'ast [Param]) { From 6f22dfe4df43e3f9be87e9debcc6a430715d7b02 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Mon, 20 Jan 2025 21:07:11 +0000 Subject: [PATCH 13/23] rustc_resolve: use `Iterator` combinators instead of `for` loops where applicable --- compiler/rustc_resolve/src/late.rs | 38 ++++++++++-------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5072145d61eae..8bd40ed3a73b2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1728,13 +1728,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } let normalized_ident = ident.normalize_to_macros_2_0(); - let mut outer_res = None; - for rib in lifetime_rib_iter { - if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) { - outer_res = Some(outer); - break; - } - } + let outer_res = lifetime_rib_iter + .find_map(|rib| rib.bindings.get_key_value(&normalized_ident).map(|(&outer, _)| outer)); self.emit_undeclared_lifetime_error(lifetime, outer_res); self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named); @@ -1801,23 +1796,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } LifetimeRibKind::AnonymousReportError => { if elided { - let mut suggestion = None; - for rib in self.lifetime_ribs[i..].iter().rev() { + let suggestion = self.lifetime_ribs[i..].iter().rev().find_map(|rib| { if let LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound, .. - } = &rib.kind + } = rib.kind { - suggestion = - Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { - lo: span.shrink_to_lo(), - hi: lifetime.ident.span.shrink_to_hi(), - }); - break; + Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + lo: span.shrink_to_lo(), + hi: lifetime.ident.span.shrink_to_hi(), + }) + } else { + None } - } - + }); // are we trying to use an anonymous lifetime // on a non GAT associated trait type? if !self.in_func_body @@ -2486,14 +2479,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Determine whether or not a label from the `rib_index`th label rib is reachable. fn is_label_valid_from_rib(&self, rib_index: usize) -> bool { let ribs = &self.label_ribs[rib_index + 1..]; - - for rib in ribs { - if rib.kind.is_label_barrier() { - return false; - } - } - - true + ribs.iter().all(|rib| !rib.kind.is_label_barrier()) } fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { From efabee2dee498093a701ac0f721b76f8a834b50f Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 21 Jan 2025 13:43:55 +0000 Subject: [PATCH 14/23] rustc_resolve: don't open-code `Option::filter` --- compiler/rustc_resolve/src/diagnostics.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 01496a6aec511..43e4e4d591f8a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1976,10 +1976,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect::>(); candidates.sort(); candidates.dedup(); - match find_best_match_for_name(&candidates, ident, None) { - Some(sugg) if sugg == ident => None, - sugg => sugg, - } + find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident) } pub(crate) fn report_path_resolution_error( From fed5f98c47e64bc5e96679165d16e5eec8b4917e Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 21 Jan 2025 17:27:24 +0000 Subject: [PATCH 15/23] Remove test panic from File::open --- library/std/src/sys/pal/windows/fs.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index b3659351b8c11..f8493c21ad444 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -328,9 +328,6 @@ impl File { mem::size_of::() as u32, ); if result == 0 { - if api::get_last_error().code != 0 { - panic!("FILE_ALLOCATION_INFO failed!!!"); - } let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; let result = c::SetFileInformationByHandle( handle.as_raw_handle(), From 922e6bb2d4a5828cc12499c4f3dca685c3fd9002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 20 Jan 2025 19:42:41 +0000 Subject: [PATCH 16/23] Detect missing fields with default values and suggest `..` When a struct definition has default field values, and the use struct ctor has missing field, if all those missing fields have defaults suggest `..`: ``` error[E0063]: missing fields `field1` and `field2` in initializer of `S` --> $DIR/non-exhaustive-ctor.rs:16:13 | LL | let _ = S { field: () }; | ^ missing `field1` and `field2` | help: all remaining fields have defaults, use `..` | LL | let _ = S { field: (), .. }; | ++++ ``` --- compiler/rustc_hir_typeck/src/expr.rs | 30 +++++++ .../non-exhaustive-ctor.disabled.stderr | 86 +++++++++++++++++++ .../non-exhaustive-ctor.enabled.fixed | 28 ++++++ .../non-exhaustive-ctor.enabled.stderr | 25 ++++++ .../non-exhaustive-ctor.rs | 28 ++++++ 5 files changed, 197 insertions(+) create mode 100644 tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr create mode 100644 tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed create mode 100644 tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr create mode 100644 tests/ui/structs/default-field-values/non-exhaustive-ctor.rs diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 01fed72d5a270..bdd436302f489 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2349,6 +2349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.report_missing_fields( adt_ty, path_span, + expr.span, remaining_fields, variant, hir_fields, @@ -2386,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, adt_ty: Ty<'tcx>, span: Span, + full_span: Span, remaining_fields: UnordMap, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], @@ -2425,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); + if remaining_fields.items().all(|(_, (_, field))| field.value.is_some()) + && self.tcx.sess.is_nightly_build() + { + let msg = format!( + "all remaining fields have default values, {you_can} use those values with `..`", + you_can = if self.tcx.features().default_field_values() { + "you can" + } else { + "if you added `#![feature(default_field_values)]` to your crate you could" + }, + ); + if let Some(hir_field) = hir_fields.last() { + err.span_suggestion_verbose( + hir_field.span.shrink_to_hi(), + msg, + ", ..".to_string(), + Applicability::MachineApplicable, + ); + } else if hir_fields.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_hi().with_hi(full_span.hi()), + msg, + " { .. }".to_string(), + Applicability::MachineApplicable, + ); + } + } + if let Some(hir_field) = hir_fields.last() { self.suggest_fru_from_range_and_emit(hir_field, variant, args, err); } else { diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr new file mode 100644 index 0000000000000..6379342565705 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr @@ -0,0 +1,86 @@ +error[E0658]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:9:22 + | +LL | pub field: () = (), + | ^^^^^ + | + = note: see issue #132162 for more information + = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:11:25 + | +LL | pub field1: Priv = Priv, + | ^^^^^^^ + | + = note: see issue #132162 for more information + = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:13:25 + | +LL | pub field2: Priv = Priv, + | ^^^^^^^ + | + = note: see issue #132162 for more information + = help: add `#![feature(default_field_values)]` 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[E0797]: base expression required after `..` + --> $DIR/non-exhaustive-ctor.rs:20:19 + | +LL | let _ = S { .. }; // ok + | ^ + | +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | +help: add a base expression here + | +LL | let _ = S { ../* expr */ }; // ok + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/non-exhaustive-ctor.rs:22:30 + | +LL | let _ = S { field: (), .. }; // ok + | ^ + | +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | +help: add a base expression here + | +LL | let _ = S { field: (), ../* expr */ }; // ok + | ++++++++++ + +error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:24:13 + | +LL | let _ = S { }; + | ^ missing `field`, `field1` and `field2` + | +help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..` + | +LL | let _ = S { .. }; + | ~~~~~~ + +error[E0063]: missing fields `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:26:13 + | +LL | let _ = S { field: () }; + | ^ missing `field1` and `field2` + | +help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..` + | +LL | let _ = S { field: (), .. }; + | ++++ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0063, E0658, E0797. +For more information about an error, try `rustc --explain E0063`. diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed new file mode 100644 index 0000000000000..7a371f993e809 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed @@ -0,0 +1,28 @@ +//@ revisions: enabled disabled +//@[enabled] run-rustfix +#![allow(private_interfaces, dead_code)] +#![cfg_attr(enabled, feature(default_field_values))] +use m::S; + +mod m { + pub struct S { + pub field: () = (), + //[disabled]~^ ERROR default values on fields are experimental + pub field1: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + pub field2: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + } + struct Priv; +} + +fn main() { + let _ = S { .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { field: (), .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { .. }; + //~^ ERROR missing fields `field`, `field1` and `field2` + let _ = S { field: (), .. }; + //~^ ERROR missing fields `field1` and `field2` +} diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr new file mode 100644 index 0000000000000..6d035ebdc4750 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr @@ -0,0 +1,25 @@ +error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:24:13 + | +LL | let _ = S { }; + | ^ missing `field`, `field1` and `field2` + | +help: all remaining fields have default values, you can use those values with `..` + | +LL | let _ = S { .. }; + | ~~~~~~ + +error[E0063]: missing fields `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:26:13 + | +LL | let _ = S { field: () }; + | ^ missing `field1` and `field2` + | +help: all remaining fields have default values, you can use those values with `..` + | +LL | let _ = S { field: (), .. }; + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs new file mode 100644 index 0000000000000..b60b219f8bcf0 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs @@ -0,0 +1,28 @@ +//@ revisions: enabled disabled +//@[enabled] run-rustfix +#![allow(private_interfaces, dead_code)] +#![cfg_attr(enabled, feature(default_field_values))] +use m::S; + +mod m { + pub struct S { + pub field: () = (), + //[disabled]~^ ERROR default values on fields are experimental + pub field1: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + pub field2: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + } + struct Priv; +} + +fn main() { + let _ = S { .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { field: (), .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { }; + //~^ ERROR missing fields `field`, `field1` and `field2` + let _ = S { field: () }; + //~^ ERROR missing fields `field1` and `field2` +} From 57dd42d6134539f5a98f59039bcba6d93daf9d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 Jan 2025 21:24:31 +0000 Subject: [PATCH 17/23] Point at invalid utf-8 span on user's source code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` error: couldn't read `$DIR/not-utf8-bin-file.rs`: stream did not contain valid UTF-8 --> $DIR/not-utf8-2.rs:6:5 | LL | include!("not-utf8-bin-file.rs"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `[193]` is not valid utf-8 --> $DIR/not-utf8-bin-file.rs:2:14 | LL | let _ = "�|�␂!5�cc␕␂��"; | ^ = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) ``` When we attempt to load a Rust source code file, if there is a OS file failure we try reading the file as bytes. If that succeeds we try to turn it into UTF-8. If *that* fails, we provide additional context about *where* the file has the first invalid UTF-8 character. Fix #76869. --- compiler/rustc_builtin_macros/src/lib.rs | 1 + .../rustc_builtin_macros/src/source_util.rs | 11 +-- compiler/rustc_parse/src/lib.rs | 67 +++++++++++++++++-- src/tools/compiletest/src/errors.rs | 2 + .../tests_revision_unpaired_stdout_stderr.rs | 2 +- tests/ui/macros/not-utf8.rs | 2 +- tests/ui/macros/not-utf8.stderr | 9 ++- tests/ui/modules/path-no-file-name.rs | 2 +- tests/ui/modules/path-no-file-name.stderr | 2 +- tests/ui/parser/issues/issue-5806.rs | 2 +- tests/ui/parser/issues/issue-5806.stderr | 2 +- tests/ui/parser/mod_file_with_path_attr.rs | 2 +- .../ui/parser/mod_file_with_path_attr.stderr | 2 +- .../staged-api-invalid-path-108697.stderr | 2 +- 14 files changed, 88 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 6071d36f8ebbc..0918403b8555a 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -16,6 +16,7 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] +#![feature(string_from_utf8_lossy_owned)] #![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 123b96f6bcaaa..d163da3ddea3b 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{ use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::source_map::SourceMap; use rustc_span::{Pos, Span, Symbol}; @@ -209,9 +209,10 @@ pub(crate) fn expand_include_str( let interned_src = Symbol::intern(src); MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src)) } - Err(_) => { - let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); - DummyResult::any(sp, guar) + Err(utf8err) => { + let mut err = cx.dcx().struct_span_err(sp, format!("`{path}` wasn't a utf-8 file")); + utf8_error(cx.source_map(), path.as_str(), None, &mut err, utf8err, &bytes[..]); + DummyResult::any(sp, err.emit()) } }, Err(dummy) => dummy, @@ -273,7 +274,7 @@ fn load_binary_file( .and_then(|path| path.into_os_string().into_string().ok()); if let Some(new_path) = new_path { - err.span_suggestion( + err.span_suggestion_verbose( path_span, "there is a file with the same name in a different directory", format!("\"{}\"", new_path.replace('\\', "/").escape_debug()), diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f963a424a7fd6..e681987ff07f7 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -11,18 +11,21 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] +#![feature(string_from_utf8_lossy_owned)] #![warn(unreachable_pub)] // tidy-alphabetical-end -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::str::Utf8Error; use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrItem, Attribute, MetaItemInner, token}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Diag, FatalError, PResult}; +use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize}; use rustc_session::parse::ParseSess; +use rustc_span::source_map::SourceMap; use rustc_span::{FileName, SourceFile, Span}; pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION; @@ -73,9 +76,22 @@ pub fn new_parser_from_file<'a>( path: &Path, sp: Option, ) -> Result, Vec>> { - let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| { - let msg = format!("couldn't read {}: {}", path.display(), e); + let sm = psess.source_map(); + let source_file = sm.load_file(path).unwrap_or_else(|e| { + let msg = format!("couldn't read `{}`: {}", path.display(), e); let mut err = psess.dcx().struct_fatal(msg); + if let Ok(contents) = std::fs::read(path) + && let Err(utf8err) = String::from_utf8(contents.clone()) + { + utf8_error( + sm, + &path.display().to_string(), + sp, + &mut err, + utf8err.utf8_error(), + &contents, + ); + } if let Some(sp) = sp { err.span(sp); } @@ -84,6 +100,49 @@ pub fn new_parser_from_file<'a>( new_parser_from_source_file(psess, source_file) } +pub fn utf8_error( + sm: &SourceMap, + path: &str, + sp: Option, + err: &mut Diag<'_, E>, + utf8err: Utf8Error, + contents: &[u8], +) { + // The file exists, but it wasn't valid UTF-8. + let start = utf8err.valid_up_to(); + let note = format!("invalid utf-8 at byte `{start}`"); + let msg = if let Some(len) = utf8err.error_len() { + format!( + "byte{s} `{bytes}` {are} not valid utf-8", + bytes = if len == 1 { + format!("{:?}", contents[start]) + } else { + format!("{:?}", &contents[start..start + len]) + }, + s = pluralize!(len), + are = if len == 1 { "is" } else { "are" }, + ) + } else { + note.clone() + }; + let contents = String::from_utf8_lossy(contents).to_string(); + let source = sm.new_source_file(PathBuf::from(path).into(), contents); + let span = Span::with_root_ctxt( + source.normalized_byte_pos(start as u32), + source.normalized_byte_pos(start as u32), + ); + if span.is_dummy() { + err.note(note); + } else { + if sp.is_some() { + err.span_note(span, msg); + } else { + err.span(span); + err.span_label(span, msg); + } + } +} + /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing /// the initial token stream. fn new_parser_from_source_file( diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index efe758e65cf66..37ef63ae42ea9 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -101,6 +101,8 @@ pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec { rdr.lines() .enumerate() + // We want to ignore utf-8 failures in tests during collection of annotations. + .filter(|(_, line)| line.is_ok()) .filter_map(|(line_num, line)| { parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), revision).map( |(which, error)| { diff --git a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs index 00edf99a30dbd..ee92d302db3c9 100644 --- a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs +++ b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs @@ -58,7 +58,7 @@ pub fn check(tests_path: impl AsRef, bad: &mut bool) { let mut expected_revisions = BTreeSet::new(); - let contents = std::fs::read_to_string(test).unwrap(); + let Ok(contents) = std::fs::read_to_string(test) else { continue }; // Collect directives. iter_header(&contents, &mut |HeaderLine { revision, directive, .. }| { diff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs index 8100d65a9f811..ad8ac39d230e4 100644 --- a/tests/ui/macros/not-utf8.rs +++ b/tests/ui/macros/not-utf8.rs @@ -3,5 +3,5 @@ //@ reference: input.encoding.invalid fn foo() { - include!("not-utf8.bin") + include!("not-utf8.bin"); } diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr index 0d587cab5f3ed..17ee8197ac8be 100644 --- a/tests/ui/macros/not-utf8.stderr +++ b/tests/ui/macros/not-utf8.stderr @@ -1,9 +1,14 @@ -error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8 +error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8 --> $DIR/not-utf8.rs:6:5 | -LL | include!("not-utf8.bin") +LL | include!("not-utf8.bin"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | +note: byte `193` is not valid utf-8 + --> $DIR/not-utf8.bin:1:1 + | +LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�... + | ^ = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/modules/path-no-file-name.rs b/tests/ui/modules/path-no-file-name.rs index 23127346e02aa..753a09501235a 100644 --- a/tests/ui/modules/path-no-file-name.rs +++ b/tests/ui/modules/path-no-file-name.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "\.:.*\(" -> ".: $$ACCESS_DENIED_MSG (" +//@ normalize-stderr: "\.`:.*\(" -> ".`: $$ACCESS_DENIED_MSG (" //@ normalize-stderr: "os error \d+" -> "os error $$ACCESS_DENIED_CODE" #[path = "."] diff --git a/tests/ui/modules/path-no-file-name.stderr b/tests/ui/modules/path-no-file-name.stderr index 834e8ea6b03de..6274ecfed1365 100644 --- a/tests/ui/modules/path-no-file-name.stderr +++ b/tests/ui/modules/path-no-file-name.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/.: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) +error: couldn't read `$DIR/.`: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) --> $DIR/path-no-file-name.rs:5:1 | LL | mod m; diff --git a/tests/ui/parser/issues/issue-5806.rs b/tests/ui/parser/issues/issue-5806.rs index dbd53a7adc433..1a819e22197fe 100644 --- a/tests/ui/parser/issues/issue-5806.rs +++ b/tests/ui/parser/issues/issue-5806.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "parser:.*\(" -> "parser: $$ACCESS_DENIED_MSG (" +//@ normalize-stderr: "parser`:.*\(" -> "parser`: $$ACCESS_DENIED_MSG (" //@ normalize-stderr: "os error \d+" -> "os error $$ACCESS_DENIED_CODE" #[path = "../parser"] diff --git a/tests/ui/parser/issues/issue-5806.stderr b/tests/ui/parser/issues/issue-5806.stderr index 4b025bd19a048..88cc982baf259 100644 --- a/tests/ui/parser/issues/issue-5806.stderr +++ b/tests/ui/parser/issues/issue-5806.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/../parser: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) +error: couldn't read `$DIR/../parser`: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) --> $DIR/issue-5806.rs:5:1 | LL | mod foo; diff --git a/tests/ui/parser/mod_file_with_path_attr.rs b/tests/ui/parser/mod_file_with_path_attr.rs index ff964f750e296..b7f4a9c6ae02f 100644 --- a/tests/ui/parser/mod_file_with_path_attr.rs +++ b/tests/ui/parser/mod_file_with_path_attr.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "not_a_real_file.rs:.*\(" -> "not_a_real_file.rs: $$FILE_NOT_FOUND_MSG (" +//@ normalize-stderr: "not_a_real_file.rs`:.*\(" -> "not_a_real_file.rs`: $$FILE_NOT_FOUND_MSG (" #[path = "not_a_real_file.rs"] mod m; //~ ERROR not_a_real_file.rs diff --git a/tests/ui/parser/mod_file_with_path_attr.stderr b/tests/ui/parser/mod_file_with_path_attr.stderr index 9ccb775daab13..ef8a715712bbd 100644 --- a/tests/ui/parser/mod_file_with_path_attr.stderr +++ b/tests/ui/parser/mod_file_with_path_attr.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/not_a_real_file.rs: $FILE_NOT_FOUND_MSG (os error 2) +error: couldn't read `$DIR/not_a_real_file.rs`: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/mod_file_with_path_attr.rs:4:1 | LL | mod m; diff --git a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr index 9c6d1a042d755..e68e19c4dc99e 100644 --- a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr +++ b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/lol: No such file or directory (os error 2) +error: couldn't read `$DIR/lol`: No such file or directory (os error 2) --> $DIR/staged-api-invalid-path-108697.rs:8:1 | LL | mod foo; From e7db0925d1441990ceb8236b5d4015f9a2ba333c Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Wed, 22 Jan 2025 01:14:43 +0000 Subject: [PATCH 18/23] address review: modify ICE-133117-duplicated-never-arm.rs Use enum Void to avoid mistmatched types error Signed-off-by: Shunpoco --- .../ICE-133117-duplicate-never-arm.rs | 14 +++++---- .../ICE-133117-duplicate-never-arm.stderr | 30 +++++-------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs index 884dbacbaa98f..bca2ab5657021 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs @@ -1,12 +1,14 @@ +#![feature(never_type)] #![feature(never_patterns)] #![allow(incomplete_features)] -fn main() { - match () { - (!| - //~^ ERROR: mismatched types - !) if true => {} //~ ERROR a never pattern is always unreachable - //~^ ERROR: mismatched types +enum Void {} + +fn foo(x: Void) { + match x { + (!|!) if true => {} //~ ERROR a never pattern is always unreachable (!|!) if true => {} //~ ERROR a never pattern is always unreachable } } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr index 4b8de102a7b55..5da9642dc1998 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr @@ -1,11 +1,11 @@ error: a never pattern is always unreachable - --> $DIR/ICE-133117-duplicate-never-arm.rs:8:23 + --> $DIR/ICE-133117-duplicate-never-arm.rs:9:26 | -LL | !) if true => {} - | ^^ - | | - | this will never be executed - | help: remove this expression +LL | (!|!) if true => {} + | ^^ + | | + | this will never be executed + | help: remove this expression error: a never pattern is always unreachable --> $DIR/ICE-133117-duplicate-never-arm.rs:10:26 @@ -16,21 +16,5 @@ LL | (!|!) if true => {} | this will never be executed | help: remove this expression -error: mismatched types - --> $DIR/ICE-133117-duplicate-never-arm.rs:6:10 - | -LL | (!| - | ^ a never pattern must be used on an uninhabited type - | - = note: the matched value is of type `()` - -error: mismatched types - --> $DIR/ICE-133117-duplicate-never-arm.rs:8:9 - | -LL | !) if true => {} - | ^ a never pattern must be used on an uninhabited type - | - = note: the matched value is of type `()` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors From d8a216b866ff238589005fb1ea4c54644d8d24bf Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Wed, 22 Jan 2025 01:27:15 +0000 Subject: [PATCH 19/23] address review: modify ICE-133063-never-arm-no-otherwise-block.rs - Use enum Void to avoid mismatched types error - We don't need to use if let to check the ICE Signed-off-by: Shunpoco --- ...ICE-133063-never-arm-no-otherwise-block.rs | 15 +++---- ...133063-never-arm-no-otherwise-block.stderr | 40 ++++--------------- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs index a9527d7d0c445..4f52f6ee4bd91 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs @@ -1,18 +1,13 @@ +#![feature(never_type)] #![feature(never_patterns)] -#![feature(if_let_guard)] #![allow(incomplete_features)] -fn split_last(_: &()) -> Option<(&i32, &i32)> { - None -} +enum Void {} -fn assign_twice() { +fn foo(x: Void) { loop { - match () { - (!| //~ ERROR: mismatched types - !) if let _ = split_last(&()) => {} //~ ERROR a never pattern is always unreachable - //~^ ERROR: mismatched types - //~^^ WARNING: irrefutable `if let` guard pattern [irrefutable_let_patterns] + match x { + (!|!) if false => {} //~ ERROR a never pattern is always unreachable _ => {} } } diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr index 896c95f1866fe..cc451fed31805 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr @@ -1,37 +1,11 @@ error: a never pattern is always unreachable - --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:13:46 + --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:10:31 | -LL | !) if let _ = split_last(&()) => {} - | ^^ - | | - | this will never be executed - | help: remove this expression +LL | (!|!) if false => {} + | ^^ + | | + | this will never be executed + | help: remove this expression -error: mismatched types - --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:12:14 - | -LL | (!| - | ^ a never pattern must be used on an uninhabited type - | - = note: the matched value is of type `()` - -error: mismatched types - --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:13:13 - | -LL | !) if let _ = split_last(&()) => {} - | ^ a never pattern must be used on an uninhabited type - | - = note: the matched value is of type `()` - -warning: irrefutable `if let` guard pattern - --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:13:19 - | -LL | !) if let _ = split_last(&()) => {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this pattern will always match, so the guard is useless - = help: consider removing the guard and adding a `let` inside the match arm - = note: `#[warn(irrefutable_let_patterns)]` on by default - -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 1 previous error From 481ed2d9319a28b770da60f4567e55f5cc053835 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Wed, 22 Jan 2025 01:51:11 +0000 Subject: [PATCH 20/23] address review: modify matches/mod.rs The candidate shouldn't have false_edge_start_block if it has sub candidates. In remove_never_subcandidates(), the false_edge_start_block from the first sub candidte is assigned to a value and the value is later used if all sub candidates are removed and candidate doesn't have false_edge_start_block. In merge_trivial_subcandidates, I leave the if block which assign a false_edge_start_block into the candidate as before I put this commit since compile panics. Signed-off-by: Shunpoco --- compiler/rustc_mir_build/src/builder/matches/mod.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 7e7c5ceee937e..430854974b38e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1940,10 +1940,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// in match tree lowering. fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { assert!(!candidate.subcandidates.is_empty()); - if candidate.false_edge_start_block.is_none() { - candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; - } - if candidate.has_guard { // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. return; @@ -1963,6 +1959,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let or_span = candidate.or_span.take().unwrap(); let source_info = self.source_info(or_span); + if candidate.false_edge_start_block.is_none() { + candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; + } + // Remove the (known-trivial) subcandidates from the candidate tree, // so that they aren't visible after match tree lowering, and wire them // all to join up at a single shared pre-binding block. @@ -1986,6 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return; } + let false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; candidate.subcandidates.retain_mut(|candidate| { if candidate.extra_data.is_never { candidate.visit_leaves(|subcandidate| { @@ -2004,6 +2005,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let next_block = self.cfg.start_new_block(); candidate.pre_binding_block = Some(next_block); candidate.otherwise_block = Some(next_block); + // In addition, if `candidate` should have `false_edge_start_block`. + if candidate.false_edge_start_block.is_none() { + candidate.false_edge_start_block = false_edge_start_block; + } } } From 7275bdf6ec396d052b6dae8af8597b5eebf1f66f Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Wed, 22 Jan 2025 02:42:11 +0000 Subject: [PATCH 21/23] modify comment Signed-off-by: Shunpoco --- compiler/rustc_mir_build/src/builder/matches/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 430854974b38e..b21ec8f3083b3 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -2005,7 +2005,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let next_block = self.cfg.start_new_block(); candidate.pre_binding_block = Some(next_block); candidate.otherwise_block = Some(next_block); - // In addition, if `candidate` should have `false_edge_start_block`. + // In addition, if `candidate` doesn't have `false_edge_start_block`, it should be assigned here. if candidate.false_edge_start_block.is_none() { candidate.false_edge_start_block = false_edge_start_block; } From 9e98d2572901d2767df9a26c938aba1f112b332c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 22 Jan 2025 04:46:55 +0100 Subject: [PATCH 22/23] Library: Finalize dyn compatibility renaming --- library/std/src/keyword_docs.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 0c526eafdf36f..1d26bf37f4d28 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2387,13 +2387,12 @@ mod async_keyword {} /// [`async`]: ../std/keyword.async.html mod await_keyword {} -// FIXME(dyn_compat_renaming): Update URL and link text. #[doc(keyword = "dyn")] // /// `dyn` is a prefix of a [trait object]'s type. /// /// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait` -/// are [dynamically dispatched]. To use the trait this way, it must be 'dyn-compatible'[^1]. +/// are [dynamically dispatched]. To use the trait this way, it must be *dyn compatible*[^1]. /// /// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that /// is being passed. That is, the type has been [erased]. @@ -2406,7 +2405,7 @@ mod await_keyword {} /// the function pointer and then that function pointer is called. /// /// See the Reference for more information on [trait objects][ref-trait-obj] -/// and [object safety][ref-obj-safety]. +/// and [dyn compatibility][ref-dyn-compat]. /// /// ## Trade-offs /// @@ -2419,9 +2418,9 @@ mod await_keyword {} /// [trait object]: ../book/ch17-02-trait-objects.html /// [dynamically dispatched]: https://en.wikipedia.org/wiki/Dynamic_dispatch /// [ref-trait-obj]: ../reference/types/trait-object.html -/// [ref-obj-safety]: ../reference/items/traits.html#object-safety +/// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility /// [erased]: https://en.wikipedia.org/wiki/Type_erasure -/// [^1]: Formerly known as 'object safe'. +/// [^1]: Formerly known as *object safe*. mod dyn_keyword {} #[doc(keyword = "union")] From 12214db74bfa1513cd8a8ffdc21ad83e1b2d7844 Mon Sep 17 00:00:00 2001 From: Anthony Eid Date: Wed, 22 Jan 2025 00:00:31 -0500 Subject: [PATCH 23/23] Update lint tests with new dangling pointers message --- compiler/rustc_lint/messages.ftl | 4 +-- .../allow.stderr | 4 +++ .../calls.stderr | 10 ++++++ .../cstring-as-ptr.stderr | 4 +++ .../example-from-issue123613.stderr | 4 +++ .../ext.stderr | 4 +++ .../methods.stderr | 4 +++ .../temporaries.stderr | 16 +++++++++ .../types.stderr | 34 +++++++++++++++++++ 9 files changed, 82 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 3570126de7427..3170a4d49c87e 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -209,8 +209,8 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help_bind = you must make sure that the variable you bind the `{$typ}` to lives at least as long as the pointer returned by the call to `{$callee}` - .help_returned = in particular, if this pointer is returned from the current function, binding the `{$typ}` inside the function will not suffice + .help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}` + .help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice .help_visit = for more information, see lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr index fd434eacf3de3..e1c12cfd1a501 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr @@ -7,6 +7,8 @@ LL | dbg!(String::new().as_ptr()); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/allow.rs:7:12 @@ -23,6 +25,8 @@ LL | dbg!(String::new().as_ptr()); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/allow.rs:18:12 diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr index d1615b76d82e0..41c6cdd0e3ef4 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr @@ -7,6 +7,8 @@ LL | let ptr = cstring().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/calls.rs:1:9 @@ -23,6 +25,8 @@ LL | let ptr = cstring().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `CString` will be dropped @@ -34,6 +38,8 @@ LL | let _ptr: *const u8 = cstring().as_ptr().cast(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `CString` will be dropped @@ -45,6 +51,8 @@ LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `CString` will be dropped @@ -56,6 +64,8 @@ LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see error: aborting due to 5 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr index 5289fbb872342..d4126ba231f76 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr @@ -15,6 +15,8 @@ LL | let s = CString::new("some text").unwrap().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/cstring-as-ptr.rs:2:9 @@ -34,6 +36,8 @@ LL | mymacro!(); | ---------- in this macro invocation | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr index 0de794f6ae285..aace55e92cf16 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr @@ -7,6 +7,8 @@ LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_mut_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/example-from-issue123613.rs:1:9 @@ -23,6 +25,8 @@ LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr index 5d401c89c0ca2..976334ddef9c8 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr @@ -7,6 +7,8 @@ LL | let _ptr1 = Vec::::new().as_ptr().dbg(); | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/ext.rs:1:9 @@ -23,6 +25,8 @@ LL | let _ptr2 = vec![0].as_ptr().foo(); | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice = help: for more information, see error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr index 11c052c158e55..a86a69bc39a28 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr @@ -7,6 +7,8 @@ LL | vec![0u8].as_ptr(); | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/methods.rs:1:9 @@ -23,6 +25,8 @@ LL | vec![0u8].as_mut_ptr(); | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_mut_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice = help: for more information, see error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr index d2e9ac8c4e957..e8994703cabfa 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr @@ -7,6 +7,8 @@ LL | string().as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/temporaries.rs:2:9 @@ -23,6 +25,8 @@ LL | "hello".to_string().as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -34,6 +38,8 @@ LL | (string() + "hello").as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -45,6 +51,8 @@ LL | (if true { String::new() } else { "hello".into() }).as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -58,6 +66,8 @@ LL | .as_ptr(); | ^^^^^^ this pointer will immediately be invalid | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -71,6 +81,8 @@ LL | .as_ptr(); | ^^^^^^ this pointer will immediately be invalid | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -82,6 +94,8 @@ LL | { string() }.as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Vec` will be dropped @@ -93,6 +107,8 @@ LL | vec![0u8].as_ptr(); | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice = help: for more information, see error: aborting due to 8 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr index 250ed6dc9e379..fab2459b53f6f 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -7,6 +7,8 @@ LL | declval::().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see note: the lint level is defined here --> $DIR/types.rs:1:9 @@ -23,6 +25,8 @@ LL | declval::().as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Vec` will be dropped @@ -34,6 +38,8 @@ LL | declval::>().as_ptr(); | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped @@ -45,6 +51,8 @@ LL | declval::>().as_ptr(); | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped @@ -56,6 +64,8 @@ LL | declval::>().as_ptr(); | this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<[u8]>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8]>` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped @@ -67,6 +77,8 @@ LL | declval::>().as_ptr(); | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped @@ -78,6 +90,8 @@ LL | declval::>().as_ptr(); | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped @@ -89,6 +103,8 @@ LL | declval::<[u8; 10]>().as_ptr(); | this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `[u8; 10]` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `[u8; 10]` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped @@ -100,6 +116,8 @@ LL | declval::>().as_ptr(); | this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<[u8; 10]>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8; 10]>` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box>` will be dropped @@ -111,6 +129,8 @@ LL | declval::>>().as_ptr(); | this `Box>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box>` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped @@ -122,6 +142,8 @@ LL | declval::>().as_ptr(); | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Box>>>` will be dropped @@ -133,6 +155,8 @@ LL | declval::>>>>().as_ptr(); | this `Box>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box>>>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box>>>` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Cell` will be dropped @@ -144,6 +168,8 @@ LL | declval::>().as_ptr(); | this `Cell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Cell` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Cell` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped @@ -155,6 +181,8 @@ LL | declval::>().as_ptr(); | this `MaybeUninit` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `MaybeUninit` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `MaybeUninit` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `Vec` will be dropped @@ -166,6 +194,8 @@ LL | declval::>().as_ptr(); | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `UnsafeCell` will be dropped @@ -177,6 +207,8 @@ LL | declval::>().get(); | this `UnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `UnsafeCell` to lives at least as long as the pointer returned by the call to `get` + = help: in particular, if this pointer is returned from the current function, binding the `UnsafeCell` inside the function will not suffice = help: for more information, see error: a dangling pointer will be produced because the temporary `SyncUnsafeCell` will be dropped @@ -188,6 +220,8 @@ LL | declval::>().get(); | this `SyncUnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `SyncUnsafeCell` to lives at least as long as the pointer returned by the call to `get` + = help: in particular, if this pointer is returned from the current function, binding the `SyncUnsafeCell` inside the function will not suffice = help: for more information, see error: aborting due to 17 previous errors