diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 804cd03353820..ce203eae95fd0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1287,12 +1287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]), )) { - let mut span = expr.span; - while expr.span.eq_ctxt(span) - && let Some(parent_callsite) = span.parent_callsite() - { - span = parent_callsite; - } + let span = expr.span.find_oldest_ancestor_in_same_ctxt(); let mut sugg = if expr.precedence().order() >= PREC_POSTFIX { vec![(span.shrink_to_hi(), ".into()".to_owned())] @@ -1897,12 +1892,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => sugg.to_string(), }; - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - msg, - sugg, - Applicability::HasPlaceholders, - ); + let span = expr.span.find_oldest_ancestor_in_same_ctxt(); + err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders); return true; } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index ef569b4bef3b3..86f36eedd9007 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -43,7 +43,8 @@ use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, Pro use rustc_middle::mir::FakeReadCause; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{ - self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarArgs, UpvarCapture, + self, ClosureSizeProfileData, Ty, TyCtxt, TypeVisitableExt as _, TypeckResults, UpvarArgs, + UpvarCapture, }; use rustc_session::lint; use rustc_span::sym; @@ -191,6 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } }; + let args = self.resolve_vars_if_possible(args); let closure_def_id = closure_def_id.expect_local(); assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id); @@ -361,7 +363,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For coroutine-closures, we additionally must compute the // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref // version of the coroutine-closure's output coroutine. - if let UpvarArgs::CoroutineClosure(args) = args { + if let UpvarArgs::CoroutineClosure(args) = args + && !args.references_error() + { let closure_env_region: ty::Region<'_> = ty::Region::new_bound( self.tcx, ty::INNERMOST, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index dd73f0f4a350d..ad64745d579a0 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -771,7 +771,7 @@ impl<'tcx> CoroutineArgs<'tcx> { } } -#[derive(Debug, Copy, Clone, HashStable)] +#[derive(Debug, Copy, Clone, HashStable, TypeFoldable, TypeVisitable)] pub enum UpvarArgs<'tcx> { Closure(GenericArgsRef<'tcx>), Coroutine(GenericArgsRef<'tcx>), diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index a3e6c2abc51fa..03195a122b485 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -674,6 +674,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) && interpreted_as_const.is_none() + && scrut.is_some() { let mut bindings = vec![]; pat.each_binding(|name, _, _, _| bindings.push(name)); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7ce879807cae1..c1e1175b4bd6b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -743,6 +743,45 @@ impl Span { Some(self) } + /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same + /// [`SyntaxContext`] the initial span. + /// + /// This method is suitable for peeling through *local* macro expansions to find the "innermost" + /// span that is still local and shares the same [`SyntaxContext`]. For example, given + /// + /// ```ignore (illustrative example, contains type error) + /// macro_rules! outer { + /// ($x: expr) => { + /// inner!($x) + /// } + /// } + /// + /// macro_rules! inner { + /// ($x: expr) => { + /// format!("error: {}", $x) + /// //~^ ERROR mismatched types + /// } + /// } + /// + /// fn bar(x: &str) -> Result<(), Box> { + /// Err(outer!(x)) + /// } + /// ``` + /// + /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse + /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the + /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the + /// initial span. + pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span { + let mut cur = self; + while cur.eq_ctxt(self) + && let Some(parent_callsite) = cur.parent_callsite() + { + cur = parent_callsite; + } + cur + } + /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().edition() diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 34d90a3b4a0dc..70099e0a3b560 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -45,13 +45,11 @@ impl Thread { Err(io::Error::last_os_error()) }; - extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { - unsafe { - // Next, reserve some stack space for if we otherwise run out of stack. - stack_overflow::reserve_stack(); - // Finally, let's run some code. - Box::from_raw(main as *mut Box)(); - } + unsafe extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { + // Next, reserve some stack space for if we otherwise run out of stack. + stack_overflow::reserve_stack(); + // Finally, let's run some code. + Box::from_raw(main as *mut Box)(); 0 } } @@ -59,15 +57,19 @@ impl Thread { pub fn set_name(name: &CStr) { if let Ok(utf8) = name.to_str() { if let Ok(utf16) = to_u16s(utf8) { - Self::set_name_wide(&utf16) + unsafe { + // SAFETY: the vec returned by `to_u16s` ends with a zero value + Self::set_name_wide(&utf16) + } }; }; } - pub fn set_name_wide(name: &[u16]) { - unsafe { - c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()); - }; + /// # Safety + /// + /// `name` must end with a zero value + pub unsafe fn set_name_wide(name: &[u16]) { + c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()); } pub fn join(self) { diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 62f0a2c7b1c18..4f79f8c496169 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -12,8 +12,6 @@ const WORD_SIZE: usize = core::mem::size_of::(); pub mod alloc; #[path = "../zkvm/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 5abf201aa201b..cc21560fff505 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -25,7 +25,6 @@ pub mod fs; pub mod io; pub mod lazy_box; pub mod process; -pub mod thread; pub mod thread_local_dtor; pub mod thread_parking; pub mod wstr; diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 8c9885974b481..6a268633f72c1 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -417,6 +417,10 @@ impl TcpListener { // it allows up to about 37, but other times it doesn't even // accept 32. There may be a global limitation causing this. let backlog = 20; + } else if #[cfg(target_os = "haiku")] { + // Haiku does not support a queue length > 32 + // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81 + let backlog = 32; } else { // The default for all other platforms let backlog = 128; diff --git a/library/std/src/sys_common/thread.rs b/library/std/src/sys_common/thread.rs deleted file mode 100644 index 8f5624bbce9da..0000000000000 --- a/library/std/src/sys_common/thread.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::env; -use crate::sync::atomic::{self, Ordering}; -use crate::sys::thread as imp; - -pub fn min_stack() -> usize { - static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - match MIN.load(Ordering::Relaxed) { - 0 => {} - n => return n - 1, - } - let amt = env::var_os("RUST_MIN_STACK").and_then(|s| s.to_str().and_then(|s| s.parse().ok())); - let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE); - - // 0 is our sentinel value, so ensure that we'll never see 0 after - // initialization has run - MIN.store(amt + 1, Ordering::Relaxed); - amt -} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f792a27dd694d..fd89edd4acebe 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -160,6 +160,7 @@ mod tests; use crate::any::Any; use crate::cell::{OnceCell, UnsafeCell}; +use crate::env; use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; @@ -171,9 +172,9 @@ use crate::panicking; use crate::pin::Pin; use crate::ptr::addr_of_mut; use crate::str; +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::Arc; use crate::sys::thread as imp; -use crate::sys_common::thread; use crate::sys_common::thread_parking::Parker; use crate::sys_common::{AsInner, IntoInner}; use crate::time::{Duration, Instant}; @@ -468,7 +469,23 @@ impl Builder { { let Builder { name, stack_size } = self; - let stack_size = stack_size.unwrap_or_else(thread::min_stack); + let stack_size = stack_size.unwrap_or_else(|| { + static MIN: AtomicUsize = AtomicUsize::new(0); + + match MIN.load(Ordering::Relaxed) { + 0 => {} + n => return n - 1, + } + + let amt = env::var_os("RUST_MIN_STACK") + .and_then(|s| s.to_str().and_then(|s| s.parse().ok())) + .unwrap_or(imp::DEFAULT_MIN_STACK_SIZE); + + // 0 is our sentinel value, so ensure that we'll never see 0 after + // initialization has run + MIN.store(amt + 1, Ordering::Relaxed); + amt + }); let my_thread = Thread::new(name.map(|name| { CString::new(name).expect("thread name may not contain interior null bytes") @@ -1191,17 +1208,17 @@ impl ThreadId { cfg_if::cfg_if! { if #[cfg(target_has_atomic = "64")] { - use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; + use crate::sync::atomic::AtomicU64; static COUNTER: AtomicU64 = AtomicU64::new(0); - let mut last = COUNTER.load(Relaxed); + let mut last = COUNTER.load(Ordering::Relaxed); loop { let Some(id) = last.checked_add(1) else { exhausted(); }; - match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) { + match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { Ok(_) => return ThreadId(NonZero::new(id).unwrap()), Err(id) => last = id, } diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs new file mode 100644 index 0000000000000..8fc9924a12fb0 --- /dev/null +++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs @@ -0,0 +1,23 @@ +//@ edition: 2021 + +#![feature(async_closure)] + +struct DropMe; + +trait Impossible {} +fn trait_error() {} + +pub fn main() { + let b = DropMe; + let async_closure = async move || { + // Type error here taints the environment. This causes us to fallback all + // variables to `Error`. This means that when we compute the upvars for the + // *outer* coroutine-closure, we don't actually see any upvars since `MemCategorization` + // and `ExprUseVisitor`` will bail early when it sees error. This means + // that our underlying assumption that the parent and child captures are + // compatible ends up being broken, previously leading to an ICE. + trait_error::<()>(); + //~^ ERROR the trait bound `(): Impossible` is not satisfied + let _b = b; + }; +} diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr new file mode 100644 index 0000000000000..b4dc3e268bdaf --- /dev/null +++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `(): Impossible` is not satisfied + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:19:23 + | +LL | trait_error::<()>(); + | ^^ the trait `Impossible` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:7:1 + | +LL | trait Impossible {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `trait_error` + --> $DIR/dont-ice-when-body-tainted-by-errors.rs:8:19 + | +LL | fn trait_error() {} + | ^^^^^^^^^^ required by this bound in `trait_error` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr index 6832f21f25e99..0d2aae689f037 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr @@ -46,10 +46,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ...$e; { todo!() } - | ++ +++++++++++ error: aborting due to 6 previous errors diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr index cb9e48e70e391..9ba0e09e1540c 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr @@ -67,10 +67,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e...; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:17 @@ -85,10 +81,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e..=; { todo!() } - | ++ +++++++++++ error: aborting due to 8 previous errors diff --git a/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs new file mode 100644 index 0000000000000..8426b0021f497 --- /dev/null +++ b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.rs @@ -0,0 +1,8 @@ +// https://github.com/rust-lang/rust/issues/123844 +// An uninitialized refutable let should not suggest `let else`, as it can't be used with deferred +// initialization. + +fn main() { + let Some(x); //~ ERROR refutable pattern in local binding + x = 1; +} diff --git a/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr new file mode 100644 index 0000000000000..13312306c07b7 --- /dev/null +++ b/tests/ui/let-else/uninitialized-refutable-let-issue-123844.stderr @@ -0,0 +1,13 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/uninitialized-refutable-let-issue-123844.rs:6:9 + | +LL | let Some(x); + | ^^^^^^^ pattern `None` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + = note: the matched value is of type `Option` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr index 7c5cc4777b6b4..2c0baf7e5f80b 100644 --- a/tests/ui/parser/recover/recover-range-pats.stderr +++ b/tests/ui/parser/recover/recover-range-pats.stderr @@ -491,10 +491,6 @@ LL | mac2!(0, 1); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let $e1..$e2; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:138:17 @@ -509,10 +505,6 @@ LL | mac2!(0, 1); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let $e1...$e2; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:142:17 @@ -527,10 +519,6 @@ LL | mac2!(0, 1); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let $e1..=$e2; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:151:17 @@ -545,10 +533,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ..$e; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:153:17 @@ -563,10 +547,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ...$e; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:156:17 @@ -581,10 +561,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let ..=$e; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:158:17 @@ -599,10 +575,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e..; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:160:17 @@ -617,10 +589,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e...; { todo!() } - | ++ +++++++++++ error[E0005]: refutable pattern in local binding --> $DIR/recover-range-pats.rs:162:17 @@ -635,10 +603,6 @@ LL | mac!(0); = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let $e..=; { todo!() } - | ++ +++++++++++ error: aborting due to 69 previous errors diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed deleted file mode 100644 index dcb256de18f17..0000000000000 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.fixed +++ /dev/null @@ -1,37 +0,0 @@ -//@ run-rustfix -#![allow(dead_code)] - -// https://github.com/rust-lang/rust/issues/112007 -fn bug_report(w: &mut W) -> std::fmt::Result { - if true { - writeln!(w, "`;?` here ->")?; - } else { - return writeln!(w, "but not here"); - //~^ ERROR mismatched types - }; - Ok(()) -} - -macro_rules! baz { - ($w: expr) => { - bar!($w) - } -} - -macro_rules! bar { - ($w: expr) => { - writeln!($w, "but not here") - //~^ ERROR mismatched types - } -} - -fn foo(w: &mut W) -> std::fmt::Result { - if true { - writeln!(w, "`;?` here ->")?; - } else { - return baz!(w); - }; - Ok(()) -} - -fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs index 58cd6cbf20c57..7ec9f0d4cdb9c 100644 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs @@ -1,8 +1,16 @@ -//@ run-rustfix -#![allow(dead_code)] +// Check that we don't leak stdlib implementation details through suggestions. +// Also check that the suggestion provided tries as hard as it can to see through local macros. +// +// FIXME(jieyouxu): this test is NOT run-rustfix because this test contains conflicting +// MaybeIncorrect suggestions: +// +// 1. `return ... ;` +// 2. `?` +// +// when the suggestions are applied to the same file, it becomes uncompilable. // https://github.com/rust-lang/rust/issues/112007 -fn bug_report(w: &mut W) -> std::fmt::Result { +pub fn bug_report(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { @@ -25,7 +33,7 @@ macro_rules! bar { } } -fn foo(w: &mut W) -> std::fmt::Result { +pub fn foo(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { @@ -34,4 +42,4 @@ fn foo(w: &mut W) -> std::fmt::Result { Ok(()) } -fn main() {} +pub fn main() {} diff --git a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr index df2e06e8f3b76..889d2c94d0cfb 100644 --- a/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr +++ b/tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:9:9 + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:17:9 | LL | / if true { LL | | writeln!(w, "`;?` here ->")?; @@ -21,9 +21,13 @@ help: you might have meant to return this value | LL | return writeln!(w, "but not here"); | ++++++ + +help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller + | +LL | writeln!(w, "but not here")? + | + error[E0308]: mismatched types - --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:32:9 + --> $DIR/issue-112007-leaked-writeln-macro-internals.rs:40:9 | LL | / if true { LL | | writeln!(w, "`;?` here ->")?; @@ -44,6 +48,10 @@ help: you might have meant to return this value | LL | return baz!(w); | ++++++ + +help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller + | +LL | writeln!($w, "but not here")? + | + error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/question-mark-operator-suggestion-span.rs b/tests/ui/typeck/question-mark-operator-suggestion-span.rs new file mode 100644 index 0000000000000..7aea6e63dd1f2 --- /dev/null +++ b/tests/ui/typeck/question-mark-operator-suggestion-span.rs @@ -0,0 +1,22 @@ +// Check that we don't construct a span for `?` suggestions that point into non-local macros +// like into the stdlib where the user has no control over. +// +// FIXME(jieyouxu): this test is currently NOT run-rustfix because there are conflicting +// MaybeIncorrect suggestions: +// +// 1. adding `return ... ;`, and +// 2. adding `?`. +// +// When rustfix puts those together, the fixed file now contains uncompilable code. + +#![crate_type = "lib"] + +pub fn bug_report(w: &mut W) -> std::fmt::Result { + if true { + writeln!(w, "`;?` here ->")?; + } else { + writeln!(w, "but not here") + //~^ ERROR mismatched types + } + Ok(()) +} diff --git a/tests/ui/typeck/question-mark-operator-suggestion-span.stderr b/tests/ui/typeck/question-mark-operator-suggestion-span.stderr new file mode 100644 index 0000000000000..089b3bcd1988a --- /dev/null +++ b/tests/ui/typeck/question-mark-operator-suggestion-span.stderr @@ -0,0 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/question-mark-operator-suggestion-span.rs:18:9 + | +LL | / if true { +LL | | writeln!(w, "`;?` here ->")?; +LL | | } else { +LL | | writeln!(w, "but not here") + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>` +LL | | +LL | | } + | |_____- expected this to be `()` + | + = note: expected unit type `()` + found enum `Result<(), std::fmt::Error>` + = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using a semicolon here + | +LL | }; + | + +help: you might have meant to return this value + | +LL | return writeln!(w, "but not here"); + | ++++++ + +help: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller + | +LL | writeln!(w, "but not here")? + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.