From 99182dd8058f0a1153b8b7fcf873028caa6fbfa7 Mon Sep 17 00:00:00 2001 From: joboet <jonasboettiger@icloud.com> Date: Thu, 6 Oct 2022 22:46:15 +0200 Subject: [PATCH 01/16] std: use semaphore for thread parking on Apple platforms --- .../std/src/sys/unix/thread_parker/darwin.rs | 131 ++++++++++++++++++ library/std/src/sys/unix/thread_parker/mod.rs | 10 +- 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 library/std/src/sys/unix/thread_parker/darwin.rs diff --git a/library/std/src/sys/unix/thread_parker/darwin.rs b/library/std/src/sys/unix/thread_parker/darwin.rs new file mode 100644 index 0000000000000..510839d5dafbf --- /dev/null +++ b/library/std/src/sys/unix/thread_parker/darwin.rs @@ -0,0 +1,131 @@ +//! Thread parking for Darwin-based systems. +//! +//! Darwin actually has futex syscalls (`__ulock_wait`/`__ulock_wake`), but they +//! cannot be used in `std` because they are non-public (their use will lead to +//! rejection from the App Store) and because they are only available starting +//! with macOS version 10.12, even though the minimum target version is 10.7. +//! +//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin +//! supports semaphores, which allow us to implement the behaviour we need with +//! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore +//! provided by libdispatch, as the underlying Mach semaphore is only dubiously +//! public. + +use crate::pin::Pin; +use crate::sync::atomic::{ + AtomicI8, + Ordering::{Acquire, Release}, +}; +use crate::time::Duration; + +type dispatch_semaphore_t = *mut crate::ffi::c_void; +type dispatch_time_t = u64; + +const DISPATCH_TIME_NOW: dispatch_time_t = 0; +const DISPATCH_TIME_FOREVER: dispatch_time_t = !0; + +#[link(name = "System", kind = "dylib")] +extern "C" { + fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t; + fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t; + fn dispatch_semaphore_wait(dsema: dispatch_semaphore_t, timeout: dispatch_time_t) -> isize; + fn dispatch_semaphore_signal(dsema: dispatch_semaphore_t) -> isize; + fn dispatch_release(object: *mut crate::ffi::c_void); +} + +const EMPTY: i8 = 0; +const NOTIFIED: i8 = 1; +const PARKED: i8 = -1; + +pub struct Parker { + semaphore: dispatch_semaphore_t, + state: AtomicI8, +} + +unsafe impl Sync for Parker {} +unsafe impl Send for Parker {} + +impl Parker { + pub unsafe fn new(parker: *mut Parker) { + let semaphore = dispatch_semaphore_create(0); + assert!( + !semaphore.is_null(), + "failed to create dispatch semaphore for thread synchronization" + ); + parker.write(Parker { semaphore, state: AtomicI8::new(EMPTY) }) + } + + // Does not need `Pin`, but other implementation do. + pub unsafe fn park(self: Pin<&Self>) { + // The semaphore counter must be zero at this point, because unparking + // threads will not actually increase it until we signalled that we + // are waiting. + + // Change NOTIFIED to EMPTY and EMPTY to PARKED. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + // Another thread may increase the semaphore counter from this point on. + // If it is faster than us, we will decrement it again immediately below. + // If we are faster, we wait. + + // Ensure that the semaphore counter has actually been decremented, even + // if the call timed out for some reason. + while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {} + + // At this point, the semaphore counter is zero again. + + // We were definitely woken up, so we don't need to check the state. + // Still, we need to reset the state using a swap to observe the state + // change with acquire ordering. + self.state.swap(EMPTY, Acquire); + } + + // Does not need `Pin`, but other implementation do. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + let nanos = dur.as_nanos().try_into().unwrap_or(i64::MAX); + let timeout = dispatch_time(DISPATCH_TIME_NOW, nanos); + + let timeout = dispatch_semaphore_wait(self.semaphore, timeout) != 0; + + let state = self.state.swap(EMPTY, Acquire); + if state == NOTIFIED && timeout { + // If the state was NOTIFIED but semaphore_wait returned without + // decrementing the count because of a timeout, it means another + // thread is about to call semaphore_signal. We must wait for that + // to happen to ensure the semaphore count is reset. + while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {} + } else { + // Either a timeout occurred and we reset the state before any thread + // tried to wake us up, or we were woken up and reset the state, + // making sure to observe the state change with acquire ordering. + // Either way, the semaphore counter is now zero again. + } + } + + // Does not need `Pin`, but other implementation do. + pub fn unpark(self: Pin<&Self>) { + let state = self.state.swap(NOTIFIED, Release); + if state == PARKED { + unsafe { + dispatch_semaphore_signal(self.semaphore); + } + } + } +} + +impl Drop for Parker { + fn drop(&mut self) { + // SAFETY: + // We always ensure that the semaphore count is reset, so this will + // never cause an exception. + unsafe { + dispatch_release(self.semaphore); + } + } +} diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs index e2453580dc72a..724ec2d482edb 100644 --- a/library/std/src/sys/unix/thread_parker/mod.rs +++ b/library/std/src/sys/unix/thread_parker/mod.rs @@ -11,7 +11,15 @@ )))] cfg_if::cfg_if! { - if #[cfg(target_os = "netbsd")] { + if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { + mod darwin; + pub use darwin::Parker; + } else if #[cfg(target_os = "netbsd")] { mod netbsd; pub use netbsd::Parker; } else { From 0ad4dd494a67a0fffc5a3e4df08f0c26cf074c59 Mon Sep 17 00:00:00 2001 From: joboet <jonasboettiger@icloud.com> Date: Thu, 6 Oct 2022 22:46:47 +0200 Subject: [PATCH 02/16] std: add thread parking tests --- library/std/src/thread/tests.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 130e47c8d44f0..dfb8765ab4eed 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -244,6 +244,28 @@ fn test_try_panic_any_message_unit_struct() { } } +#[test] +fn test_park_unpark_before() { + for _ in 0..10 { + thread::current().unpark(); + thread::park(); + } +} + +#[test] +fn test_park_unpark_called_other_thread() { + for _ in 0..10 { + let th = thread::current(); + + let _guard = thread::spawn(move || { + super::sleep(Duration::from_millis(50)); + th.unpark(); + }); + + thread::park(); + } +} + #[test] fn test_park_timeout_unpark_before() { for _ in 0..10 { From b4c8a7b952de72bc70e798408efbd4124fa15c59 Mon Sep 17 00:00:00 2001 From: joboet <jonasboettiger@icloud.com> Date: Sat, 8 Oct 2022 09:07:28 +0200 Subject: [PATCH 03/16] std: remove unused linker attribute --- library/std/src/sys/unix/thread_parker/darwin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/thread_parker/darwin.rs b/library/std/src/sys/unix/thread_parker/darwin.rs index 510839d5dafbf..2f5356fe2276b 100644 --- a/library/std/src/sys/unix/thread_parker/darwin.rs +++ b/library/std/src/sys/unix/thread_parker/darwin.rs @@ -24,7 +24,7 @@ type dispatch_time_t = u64; const DISPATCH_TIME_NOW: dispatch_time_t = 0; const DISPATCH_TIME_FOREVER: dispatch_time_t = !0; -#[link(name = "System", kind = "dylib")] +// Contained in libSystem.dylib, which is linked by default. extern "C" { fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t; fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t; From c320ab98ff1d4adb32cece206aa895e4effae175 Mon Sep 17 00:00:00 2001 From: joboet <jonasboettiger@icloud.com> Date: Sat, 8 Oct 2022 09:12:06 +0200 Subject: [PATCH 04/16] std: do not use dispatch semaphore under miri (yet) --- library/std/src/sys/unix/thread_parker/mod.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs index 724ec2d482edb..35f1e68a87e5b 100644 --- a/library/std/src/sys/unix/thread_parker/mod.rs +++ b/library/std/src/sys/unix/thread_parker/mod.rs @@ -11,11 +11,14 @@ )))] cfg_if::cfg_if! { - if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "tvos", + if #[cfg(all( + any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ), + not(miri), ))] { mod darwin; pub use darwin::Parker; From ad8b24272428b28770471f222c19fa3154a65819 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <nathan.whitaker01@gmail.com> Date: Wed, 12 Oct 2022 15:29:08 -0700 Subject: [PATCH 05/16] Let chains should still drop temporaries by the end of the condition's execution --- compiler/rustc_ast_lowering/src/expr.rs | 45 +++++++++++++----- src/test/ui/drop/drop_order.rs | 63 +++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c55b490630200..104010f8d435e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> { else_opt: Option<&Expr>, ) -> hir::ExprKind<'hir> { let lowered_cond = self.lower_expr(cond); - let new_cond = self.manage_let_cond(lowered_cond); + let new_cond = self.wrap_cond_in_drop_scope(lowered_cond); let then_expr = self.lower_block_expr(then); if let Some(rslt) = else_opt { hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt))) @@ -397,9 +397,9 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond` - // in a temporary block. - fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> { + // Wraps a condition (i.e. `cond` in `if cond` or `while cond`) in a terminating scope + // so that temporaries created in the condition don't live beyond it. + fn wrap_cond_in_drop_scope(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> { fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool { match expr.kind { hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), @@ -407,12 +407,35 @@ impl<'hir> LoweringContext<'_, 'hir> { _ => false, } } - if has_let_expr(cond) { - cond - } else { - let reason = DesugaringKind::CondTemporary; - let span_block = self.mark_span_with_reason(reason, cond.span, None); - self.expr_drop_temps(span_block, cond, AttrVec::new()) + + // We have to take special care for `let` exprs in the condition, e.g. in + // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the + // condition in this case. + // + // In order to mantain the drop behavior for the non `let` parts of the condition, + // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially + // gets transformed into `if { let _t = foo; _t } && let pat = val` + match cond.kind { + hir::ExprKind::Binary( + op @ Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, + lhs, + rhs, + ) if has_let_expr(cond) => { + let lhs = self.wrap_cond_in_drop_scope(lhs); + let rhs = self.wrap_cond_in_drop_scope(rhs); + + self.arena.alloc(self.expr( + cond.span, + hir::ExprKind::Binary(op, lhs, rhs), + AttrVec::new(), + )) + } + hir::ExprKind::Let(_) => cond, + _ => { + let reason = DesugaringKind::CondTemporary; + let span_block = self.mark_span_with_reason(reason, cond.span, None); + self.expr_drop_temps(span_block, cond, AttrVec::new()) + } } } @@ -440,7 +463,7 @@ impl<'hir> LoweringContext<'_, 'hir> { opt_label: Option<Label>, ) -> hir::ExprKind<'hir> { let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond)); - let new_cond = self.manage_let_cond(lowered_cond); + let new_cond = self.wrap_cond_in_drop_scope(lowered_cond); let then = self.lower_block_expr(body); let expr_break = self.expr_break(span, AttrVec::new()); let stmt_break = self.stmt_expr(span, expr_break); diff --git a/src/test/ui/drop/drop_order.rs b/src/test/ui/drop/drop_order.rs index e42150dcc09d2..bf740b6a9ab67 100644 --- a/src/test/ui/drop/drop_order.rs +++ b/src/test/ui/drop/drop_order.rs @@ -1,4 +1,5 @@ // run-pass +#![feature(let_chains)] use std::cell::RefCell; use std::convert::TryInto; @@ -116,6 +117,58 @@ impl DropOrderCollector { } } + fn let_chain(&self) { + // take the "then" branch + if self.option_loud_drop(2).is_some() // 2 + && self.option_loud_drop(1).is_some() // 1 + && let Some(_d) = self.option_loud_drop(4) { // 4 + self.print(3); // 3 + } + + // take the "else" branch + if self.option_loud_drop(6).is_some() // 2 + && self.option_loud_drop(5).is_some() // 1 + && let None = self.option_loud_drop(7) { // 3 + unreachable!(); + } else { + self.print(8); // 4 + } + + // let exprs interspersed + if self.option_loud_drop(9).is_some() // 1 + && let Some(_d) = self.option_loud_drop(13) // 5 + && self.option_loud_drop(10).is_some() // 2 + && let Some(_e) = self.option_loud_drop(12) { // 4 + self.print(11); // 3 + } + + // let exprs first + if let Some(_d) = self.option_loud_drop(18) // 5 + && let Some(_e) = self.option_loud_drop(17) // 4 + && self.option_loud_drop(14).is_some() // 1 + && self.option_loud_drop(15).is_some() { // 2 + self.print(16); // 3 + } + + // let exprs last + if self.option_loud_drop(20).is_some() // 2 + && self.option_loud_drop(19).is_some() // 1 + && let Some(_d) = self.option_loud_drop(23) // 5 + && let Some(_e) = self.option_loud_drop(22) { // 4 + self.print(21); // 3 + } + } + + fn while_(&self) { + let mut v = self.option_loud_drop(4); + while let Some(_d) = v + && self.option_loud_drop(1).is_some() + && self.option_loud_drop(2).is_some() { + self.print(3); + v = None; + } + } + fn assert_sorted(self) { assert!( self.0 @@ -142,4 +195,14 @@ fn main() { let collector = DropOrderCollector::default(); collector.match_(); collector.assert_sorted(); + + println!("-- let chain --"); + let collector = DropOrderCollector::default(); + collector.let_chain(); + collector.assert_sorted(); + + println!("-- while --"); + let collector = DropOrderCollector::default(); + collector.while_(); + collector.assert_sorted(); } From e8a6e60c5d47d7d2e62e196f80e926bf2dbdd95b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sun, 9 Oct 2022 17:56:40 +0400 Subject: [PATCH 06/16] resolve: Add some asserts for unexpected lifetime rib combinations --- compiler/rustc_resolve/src/late.rs | 38 ++++++++---- .../ui/lifetimes/unusual-rib-combinations.rs | 28 +++++++++ .../lifetimes/unusual-rib-combinations.stderr | 61 +++++++++++++++++++ 3 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/lifetimes/unusual-rib-combinations.rs create mode 100644 src/test/ui/lifetimes/unusual-rib-combinations.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 776c8ad528c0f..52419b582ec58 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1423,9 +1423,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } else { LifetimeUseSet::Many }), - LifetimeRibKind::Generics { .. } - | LifetimeRibKind::ConstGeneric - | LifetimeRibKind::AnonConst => None, + LifetimeRibKind::Generics { .. } => None, + LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => { + span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind) + } }) .unwrap_or(LifetimeUseSet::Many); debug!(?use_ctxt, ?use_set); @@ -1460,7 +1461,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); return; } - _ => {} + LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::Elided(_) + | LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ElisionFailure + | LifetimeRibKind::AnonymousReportError => {} } } @@ -1534,9 +1539,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { return; } LifetimeRibKind::Item => break, - LifetimeRibKind::Generics { .. } - | LifetimeRibKind::ConstGeneric - | LifetimeRibKind::AnonConst => {} + LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {} + LifetimeRibKind::AnonConst => { + // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`. + span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind) + } } } self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); @@ -1751,9 +1758,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); break; } - LifetimeRibKind::Generics { .. } - | LifetimeRibKind::ConstGeneric - | LifetimeRibKind::AnonConst => {} + LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {} + LifetimeRibKind::AnonConst => { + // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`. + span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind) + } } } @@ -3938,7 +3947,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn_id: NodeId, async_node_id: Option<(NodeId, Span)>, ) { - if let Some((async_node_id, _)) = async_node_id { + if let Some((async_node_id, span)) = async_node_id { let mut extra_lifetime_params = self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); for rib in self.lifetime_ribs.iter().rev() { @@ -3952,7 +3961,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { extra_lifetime_params.extend(earlier_fresh); } } - _ => {} + LifetimeRibKind::Generics { .. } => {} + _ => { + // We are in a function definition. We should only find `Generics` + // and `AnonymousCreateParameter` inside the innermost `Item`. + span_bug!(span, "unexpected rib kind: {:?}", rib.kind) + } } } self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); diff --git a/src/test/ui/lifetimes/unusual-rib-combinations.rs b/src/test/ui/lifetimes/unusual-rib-combinations.rs new file mode 100644 index 0000000000000..b4c86aab863c8 --- /dev/null +++ b/src/test/ui/lifetimes/unusual-rib-combinations.rs @@ -0,0 +1,28 @@ +#![feature(inline_const)] + +struct S<'a>(&'a u8); +fn foo() {} + +// Paren generic args in AnonConst +fn a() -> [u8; foo::()] { +//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait +//~| ERROR mismatched types + panic!() +} + +// Paren generic args in ConstGeneric +fn b<const C: u8()>() {} +//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait + +// Paren generic args in AnonymousReportError +fn c<T = u8()>() {} +//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait +//~| ERROR defaults for type parameters are only allowed in +//~| WARN this was previously accepted + +// Elided lifetime in path in ConstGeneric +fn d<const C: S>() {} +//~^ ERROR missing lifetime specifier +//~| ERROR `S<'static>` is forbidden as the type of a const generic parameter + +fn main() {} diff --git a/src/test/ui/lifetimes/unusual-rib-combinations.stderr b/src/test/ui/lifetimes/unusual-rib-combinations.stderr new file mode 100644 index 0000000000000..6d7b42506982c --- /dev/null +++ b/src/test/ui/lifetimes/unusual-rib-combinations.stderr @@ -0,0 +1,61 @@ +error[E0106]: missing lifetime specifier + --> $DIR/unusual-rib-combinations.rs:24:15 + | +LL | fn d<const C: S>() {} + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | fn d<'a, const C: S<'a>>() {} + | +++ ++++ + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/unusual-rib-combinations.rs:7:16 + | +LL | fn a() -> [u8; foo::()] { + | ^^^^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/unusual-rib-combinations.rs:14:15 + | +LL | fn b<const C: u8()>() {} + | ^^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/unusual-rib-combinations.rs:18:10 + | +LL | fn c<T = u8()>() {} + | ^^^^ only `Fn` traits may use parentheses + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/unusual-rib-combinations.rs:18:6 + | +LL | fn c<T = u8()>() {} + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> + = note: `#[deny(invalid_type_param_default)]` on by default + +error[E0308]: mismatched types + --> $DIR/unusual-rib-combinations.rs:7:16 + | +LL | fn a() -> [u8; foo::()] { + | ^^^^^^^ expected `usize`, found fn item + | + = note: expected type `usize` + found fn item `fn() {foo}` + +error: `S<'static>` is forbidden as the type of a const generic parameter + --> $DIR/unusual-rib-combinations.rs:24:15 + | +LL | fn d<const C: S>() {} + | ^ + | + = note: the only supported types are integers, `bool` and `char` + = help: more complex types are supported with `#![feature(adt_const_params)]` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0106, E0214, E0308. +For more information about an error, try `rustc --explain E0106`. From e94ec30dc4205911c53901f1255a47089f95ddd2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Mon, 10 Oct 2022 17:41:44 +0400 Subject: [PATCH 07/16] resolve: Remove redundant item lifetime ribs and cleanup lifetime rib walking loops --- compiler/rustc_resolve/src/late.rs | 65 +++++++++++++----------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 52419b582ec58..194d057c870eb 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -748,35 +748,31 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { match foreign_item.kind { ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { - self.with_lifetime_rib(LifetimeRibKind::Item, |this| { - this.with_generic_param_rib( - &generics.params, - ItemRibKind(HasGenericParams::Yes(generics.span)), - LifetimeRibKind::Generics { - binder: foreign_item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, - |this| visit::walk_foreign_item(this, foreign_item), - ) - }); + self.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes(generics.span)), + LifetimeRibKind::Generics { + binder: foreign_item.id, + kind: LifetimeBinderKind::Item, + span: generics.span, + }, + |this| visit::walk_foreign_item(this, foreign_item), + ); } ForeignItemKind::Fn(box Fn { ref generics, .. }) => { - self.with_lifetime_rib(LifetimeRibKind::Item, |this| { - this.with_generic_param_rib( - &generics.params, - ItemRibKind(HasGenericParams::Yes(generics.span)), - LifetimeRibKind::Generics { - binder: foreign_item.id, - kind: LifetimeBinderKind::Function, - span: generics.span, - }, - |this| visit::walk_foreign_item(this, foreign_item), - ) - }); + self.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes(generics.span)), + LifetimeRibKind::Generics { + binder: foreign_item.id, + kind: LifetimeBinderKind::Function, + span: generics.span, + }, + |this| visit::walk_foreign_item(this, foreign_item), + ); } ForeignItemKind::Static(..) => { - self.with_item_rib(|this| { + self.with_static_rib(|this| { visit::walk_foreign_item(this, foreign_item); }); } @@ -1391,9 +1387,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { return self.resolve_anonymous_lifetime(lifetime, false); } - let mut indices = (0..self.lifetime_ribs.len()).rev(); - for i in &mut indices { - let rib = &self.lifetime_ribs[i]; + let mut lifetime_rib_iter = self.lifetime_ribs.iter().rev(); + while let Some(rib) = lifetime_rib_iter.next() { let normalized_ident = ident.normalize_to_macros_2_0(); if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) { self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named); @@ -1470,8 +1465,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } let mut outer_res = None; - for i in indices { - let rib = &self.lifetime_ribs[i]; + for rib in lifetime_rib_iter { let normalized_ident = ident.normalize_to_macros_2_0(); if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) { outer_res = Some(outer); @@ -1498,8 +1492,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { count: 1, }; let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime); - for i in (0..self.lifetime_ribs.len()).rev() { - let rib = &mut self.lifetime_ribs[i]; + for rib in self.lifetime_ribs.iter().rev() { debug!(?rib.kind); match rib.kind { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { @@ -2213,7 +2206,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => { - self.with_item_rib(|this| { + self.with_static_rib(|this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); }); @@ -2408,11 +2401,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.label_ribs.pop(); } - fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) { + fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) { let kind = ItemRibKind(HasGenericParams::No); - self.with_lifetime_rib(LifetimeRibKind::Item, |this| { - this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) - }) + self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) } // HACK(min_const_generics,const_evaluatable_unchecked): We From f6341065912ff1b284e54acfec96b000dee81a34 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Mon, 10 Oct 2022 18:31:08 +0400 Subject: [PATCH 08/16] resolve: Regroup lifetime rib kinds to account for their purpose --- compiler/rustc_resolve/src/late.rs | 39 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 194d057c870eb..060f7987a5d6d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -224,22 +224,14 @@ enum LifetimeUseSet { #[derive(Copy, Clone, Debug)] enum LifetimeRibKind { - /// This rib acts as a barrier to forbid reference to lifetimes of a parent item. - Item, - + // -- Ribs introducing named lifetimes + // /// This rib declares generic parameters. + /// Only for this kind the `LifetimeRib::bindings` field can be non-empty. Generics { binder: NodeId, span: Span, kind: LifetimeBinderKind }, - /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const - /// generics. We are disallowing this until we can decide on how we want to handle non-'static - /// lifetimes in const generics. See issue #74052 for discussion. - ConstGeneric, - - /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`. - /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by - /// `body_id` is an anonymous constant and `lifetime_ref` is non-static. - AnonConst, - + // -- Ribs introducing unnamed lifetimes + // /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: @@ -256,16 +248,31 @@ enum LifetimeRibKind { /// ``` AnonymousCreateParameter { binder: NodeId, report_in_path: bool }, + /// Replace all anonymous lifetimes by provided lifetime. + Elided(LifetimeRes), + + // -- Barrier ribs that stop lifetime lookup, or continue it but produce an error later. + // /// Give a hard error when either `&` or `'_` is written. Used to /// rule out things like `where T: Foo<'_>`. Does not imply an /// error on default object bounds (e.g., `Box<dyn Foo>`). AnonymousReportError, - /// Replace all anonymous lifetimes by provided lifetime. - Elided(LifetimeRes), - /// Signal we cannot find which should be the anonymous lifetime. ElisionFailure, + + /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const + /// generics. We are disallowing this until we can decide on how we want to handle non-'static + /// lifetimes in const generics. See issue #74052 for discussion. + ConstGeneric, + + /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`. + /// This function will emit an error if `generic_const_exprs` is not enabled, the body + /// identified by `body_id` is an anonymous constant and `lifetime_ref` is non-static. + AnonConst, + + /// This rib acts as a barrier to forbid reference to lifetimes of a parent item. + Item, } #[derive(Copy, Clone, Debug)] From 709a08ade6a8873dad8dc3987e842ed26523ef1f Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <nathan.whitaker01@gmail.com> Date: Thu, 13 Oct 2022 18:20:39 -0700 Subject: [PATCH 09/16] Lower condition directly from AST to HIR --- compiler/rustc_ast_lowering/src/expr.rs | 46 +++++++++++++------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 104010f8d435e..ec9c393502056 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -387,23 +387,26 @@ impl<'hir> LoweringContext<'_, 'hir> { then: &Block, else_opt: Option<&Expr>, ) -> hir::ExprKind<'hir> { - let lowered_cond = self.lower_expr(cond); - let new_cond = self.wrap_cond_in_drop_scope(lowered_cond); + let lowered_cond = self.lower_cond(cond); let then_expr = self.lower_block_expr(then); if let Some(rslt) = else_opt { - hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt))) + hir::ExprKind::If( + lowered_cond, + self.arena.alloc(then_expr), + Some(self.lower_expr(rslt)), + ) } else { - hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), None) + hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None) } } - // Wraps a condition (i.e. `cond` in `if cond` or `while cond`) in a terminating scope + // Lowers a condition (i.e. `cond` in `if cond` or `while cond`), wrapping it in a terminating scope // so that temporaries created in the condition don't live beyond it. - fn wrap_cond_in_drop_scope(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> { - fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool { - match expr.kind { - hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), - hir::ExprKind::Let(..) => true, + fn lower_cond(&mut self, cond: &Expr) -> &'hir hir::Expr<'hir> { + fn has_let_expr(expr: &Expr) -> bool { + match &expr.kind { + ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), + ExprKind::Let(..) => true, _ => false, } } @@ -415,14 +418,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // In order to mantain the drop behavior for the non `let` parts of the condition, // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially // gets transformed into `if { let _t = foo; _t } && let pat = val` - match cond.kind { - hir::ExprKind::Binary( - op @ Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. }, - lhs, - rhs, - ) if has_let_expr(cond) => { - let lhs = self.wrap_cond_in_drop_scope(lhs); - let rhs = self.wrap_cond_in_drop_scope(rhs); + match &cond.kind { + ExprKind::Binary(op @ Spanned { node: ast::BinOpKind::And, .. }, lhs, rhs) + if has_let_expr(cond) => + { + let op = self.lower_binop(*op); + let lhs = self.lower_cond(lhs); + let rhs = self.lower_cond(rhs); self.arena.alloc(self.expr( cond.span, @@ -430,8 +432,9 @@ impl<'hir> LoweringContext<'_, 'hir> { AttrVec::new(), )) } - hir::ExprKind::Let(_) => cond, + ExprKind::Let(..) => self.lower_expr(cond), _ => { + let cond = self.lower_expr(cond); let reason = DesugaringKind::CondTemporary; let span_block = self.mark_span_with_reason(reason, cond.span, None); self.expr_drop_temps(span_block, cond, AttrVec::new()) @@ -462,14 +465,13 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Block, opt_label: Option<Label>, ) -> hir::ExprKind<'hir> { - let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond)); - let new_cond = self.wrap_cond_in_drop_scope(lowered_cond); + let lowered_cond = self.with_loop_condition_scope(|t| t.lower_cond(cond)); let then = self.lower_block_expr(body); let expr_break = self.expr_break(span, AttrVec::new()); let stmt_break = self.stmt_expr(span, expr_break); let else_blk = self.block_all(span, arena_vec![self; stmt_break], None); let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new())); - let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr)); + let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr)); let if_expr = self.expr(span, if_kind, AttrVec::new()); let block = self.block_expr(self.arena.alloc(if_expr)); let span = self.lower_span(span.with_hi(cond.span.hi())); From 4e1c09dcd64507c03ded02844c1e5022031b9e38 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <nathan.whitaker01@gmail.com> Date: Thu, 13 Oct 2022 18:29:25 -0700 Subject: [PATCH 10/16] Validate MIR in the `drop_order` test --- src/test/ui/drop/drop_order.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/drop/drop_order.rs b/src/test/ui/drop/drop_order.rs index bf740b6a9ab67..ba1ac53aa7ce8 100644 --- a/src/test/ui/drop/drop_order.rs +++ b/src/test/ui/drop/drop_order.rs @@ -1,4 +1,5 @@ // run-pass +// compile-flags: -Z validate-mir #![feature(let_chains)] use std::cell::RefCell; From b8418485bc400d5a00f197ff328655bfa367835e Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <takoyaki0316@gmail.com> Date: Thu, 13 Oct 2022 13:07:56 +0900 Subject: [PATCH 11/16] check if the self type is `ty::Float` before getting second substs --- .../src/traits/error_reporting/suggestions.rs | 22 +++--- src/test/ui/traits/issue-102989.rs | 18 +++++ src/test/ui/traits/issue-102989.stderr | 72 +++++++++++++++++++ 3 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/traits/issue-102989.rs create mode 100644 src/test/ui/traits/issue-102989.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fda6a2236b195..4431cf9f4436b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2937,19 +2937,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span, _ => return, }; - match ( - trait_ref.skip_binder().self_ty().kind(), - trait_ref.skip_binder().substs.type_at(1).kind(), - ) { - (ty::Float(_), ty::Infer(InferTy::IntVar(_))) => { - err.span_suggestion_verbose( - rhs_span.shrink_to_hi(), - "consider using a floating-point literal by writing it with `.0`", - ".0", - Applicability::MaybeIncorrect, - ); - } - _ => {} + if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind() + && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().substs.type_at(1).kind() + { + err.span_suggestion_verbose( + rhs_span.shrink_to_hi(), + "consider using a floating-point literal by writing it with `.0`", + ".0", + Applicability::MaybeIncorrect, + ); } } diff --git a/src/test/ui/traits/issue-102989.rs b/src/test/ui/traits/issue-102989.rs new file mode 100644 index 0000000000000..cd517a1c4ac87 --- /dev/null +++ b/src/test/ui/traits/issue-102989.rs @@ -0,0 +1,18 @@ +// compile-flags: -Cinstrument-coverage +//~^ ERROR can't find crate for `profiler_builtins` + +#![no_core] +#![feature(no_core, lang_items)] +#[lang="sized"] +trait Sized { } //~ ERROR found duplicate lang item `sized` + +fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR cannot find type `Struct` in this scope + //~| ERROR mismatched types + let x = x << 1; + //~^ ERROR the size for values of type `{integer}` cannot be known at compilation time + //~| ERROR cannot find value `x` in this scope +} + +fn main() {} diff --git a/src/test/ui/traits/issue-102989.stderr b/src/test/ui/traits/issue-102989.stderr new file mode 100644 index 0000000000000..255fa6966efc9 --- /dev/null +++ b/src/test/ui/traits/issue-102989.stderr @@ -0,0 +1,72 @@ +error: `self` parameter is only allowed in associated functions + --> $DIR/issue-102989.rs:9:15 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error[E0412]: cannot find type `Struct` in this scope + --> $DIR/issue-102989.rs:9:22 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `x` in this scope + --> $DIR/issue-102989.rs:13:13 + | +LL | let x = x << 1; + | ^ help: a local variable with a similar name exists: `f` + +error: `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` + +error[E0463]: can't find crate for `profiler_builtins` + | + = note: the compiler may have been built without the profiler runtime + +error[E0152]: found duplicate lang item `sized` + --> $DIR/issue-102989.rs:7:1 + | +LL | trait Sized { } + | ^^^^^^^^^^^ + | + = note: the lang item is first defined in crate `core`. + = note: first definition in `core` loaded from $BUILD_DIR/aarch64-apple-darwin/stage1/lib/rustlib/aarch64-apple-darwin/lib/libcore-500f4c12402b1108.rlib + = note: second definition in the local crate (`issue_102989`) + +error: `#[panic_handler]` function required, but not found + +error: language item required, but not found: `eh_personality` + | + = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library + = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` + +error[E0277]: the size for values of type `{integer}` cannot be known at compilation time + --> $DIR/issue-102989.rs:13:15 + | +LL | let x = x << 1; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `core::marker::Sized` is not implemented for `{integer}` + +error[E0308]: mismatched types + --> $DIR/issue-102989.rs:9:42 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ---------- ^^^^ expected `&u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | +note: consider returning one of these bindings + --> $DIR/issue-102989.rs:9:30 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ^ +... +LL | let x = x << 1; + | ^ + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0152, E0277, E0308, E0412, E0425, E0463. +For more information about an error, try `rustc --explain E0152`. From 5378677c31e89ae2fe4de954631bde8efeac91d1 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <takoyaki0316@gmail.com> Date: Thu, 13 Oct 2022 15:07:39 +0900 Subject: [PATCH 12/16] normalize stderr --- src/test/ui/traits/issue-102989.rs | 3 ++- src/test/ui/traits/issue-102989.stderr | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/test/ui/traits/issue-102989.rs b/src/test/ui/traits/issue-102989.rs index cd517a1c4ac87..cb1e3271d26e8 100644 --- a/src/test/ui/traits/issue-102989.rs +++ b/src/test/ui/traits/issue-102989.rs @@ -1,5 +1,6 @@ +//~ ERROR can't find crate for `profiler_builtins` // compile-flags: -Cinstrument-coverage -//~^ ERROR can't find crate for `profiler_builtins` +// normalize-stderr-test "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" #![no_core] #![feature(no_core, lang_items)] diff --git a/src/test/ui/traits/issue-102989.stderr b/src/test/ui/traits/issue-102989.stderr index 255fa6966efc9..efea2251a13f8 100644 --- a/src/test/ui/traits/issue-102989.stderr +++ b/src/test/ui/traits/issue-102989.stderr @@ -1,5 +1,5 @@ error: `self` parameter is only allowed in associated functions - --> $DIR/issue-102989.rs:9:15 + --> $DIR/issue-102989.rs:10:15 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^ not semantically valid as function parameter @@ -7,13 +7,13 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { = note: associated functions are those in `impl` or `trait` definitions error[E0412]: cannot find type `Struct` in this scope - --> $DIR/issue-102989.rs:9:22 + --> $DIR/issue-102989.rs:10:22 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^^^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> $DIR/issue-102989.rs:13:13 + --> $DIR/issue-102989.rs:14:13 | LL | let x = x << 1; | ^ help: a local variable with a similar name exists: `f` @@ -25,13 +25,13 @@ error[E0463]: can't find crate for `profiler_builtins` = note: the compiler may have been built without the profiler runtime error[E0152]: found duplicate lang item `sized` - --> $DIR/issue-102989.rs:7:1 + --> $DIR/issue-102989.rs:8:1 | LL | trait Sized { } | ^^^^^^^^^^^ | = note: the lang item is first defined in crate `core`. - = note: first definition in `core` loaded from $BUILD_DIR/aarch64-apple-darwin/stage1/lib/rustlib/aarch64-apple-darwin/lib/libcore-500f4c12402b1108.rlib + = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib = note: second definition in the local crate (`issue_102989`) error: `#[panic_handler]` function required, but not found @@ -42,7 +42,7 @@ error: language item required, but not found: `eh_personality` = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` error[E0277]: the size for values of type `{integer}` cannot be known at compilation time - --> $DIR/issue-102989.rs:13:15 + --> $DIR/issue-102989.rs:14:15 | LL | let x = x << 1; | ^^ doesn't have a size known at compile-time @@ -50,7 +50,7 @@ LL | let x = x << 1; = help: the trait `core::marker::Sized` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/issue-102989.rs:9:42 + --> $DIR/issue-102989.rs:10:42 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ---------- ^^^^ expected `&u32`, found `()` @@ -58,7 +58,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | implicitly returns `()` as its body has no tail or `return` expression | note: consider returning one of these bindings - --> $DIR/issue-102989.rs:9:30 + --> $DIR/issue-102989.rs:10:30 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^ From 40bb4b740b094e79ce93f0649fa4522ddaa2eafd Mon Sep 17 00:00:00 2001 From: Weihang Lo <me@weihanglo.tw> Date: Fri, 14 Oct 2022 09:58:48 +0100 Subject: [PATCH 13/16] Update cargo 12 commits in b8f30cb23c4e5f20854a4f683325782b7cff9837..b332991a57c9d055f1864de1eed93e2178d49440 2022-10-10 19:16:06 +0000 to 2022-10-13 22:05:28 +0000 - Differentiate the warning when an alias (built-in or user-defined) shadows an external subcommand (rust-lang/cargo#11170) - chore: Update tests for latest clap (rust-lang/cargo#11235) - feat(publish): Support 'publish.timeout' config behind '-Zpublish-timeout' (rust-lang/cargo#11230) - Add missing edition (rust-lang/cargo#11231) - doc(profiles): add module level doc (rust-lang/cargo#11219) - refactor(publish): Clarify which SourceId is being used (rust-lang/cargo#11216) - Add new SourceKind::SparseRegistry to differentiate sparse registries (rust-lang/cargo#11209) - Fix deadlock when build scripts are waiting for input on stdin (rust-lang/cargo#11205) - refactor: New variant `FeaturesFor::ArtifactDep` (rust-lang/cargo#11184) - Fix rustdoc warning about unclosed HTML tag (rust-lang/cargo#11221) - refactor(tests): Prepare for wait-for-publish test changes (rust-lang/cargo#11210) - Add configuration option for controlling crates.io protocol (rust-lang/cargo#11215) --- Cargo.lock | 8 ++++---- src/tools/cargo | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0cc7f8a1c7ce3..f393a91809417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -297,7 +297,7 @@ dependencies = [ "cargo-test-macro", "cargo-test-support", "cargo-util", - "clap 4.0.9", + "clap 4.0.15", "crates-io", "curl", "curl-sys", @@ -439,7 +439,7 @@ dependencies = [ [[package]] name = "cargo-util" -version = "0.2.1" +version = "0.2.2" dependencies = [ "anyhow", "core-foundation", @@ -602,9 +602,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.9" +version = "4.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30607dd93c420c6f1f80b544be522a0238a7db35e6a12968d28910983fee0df0" +checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f" dependencies = [ "atty", "bitflags", diff --git a/src/tools/cargo b/src/tools/cargo index b8f30cb23c4e5..b332991a57c9d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit b8f30cb23c4e5f20854a4f683325782b7cff9837 +Subproject commit b332991a57c9d055f1864de1eed93e2178d49440 From f528414e4092815e96690275c527717871ff411d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume.gomez@huawei.com> Date: Wed, 12 Oct 2022 11:32:00 +0200 Subject: [PATCH 14/16] Add missing checks for `doc(cfg_hide(...))` attribute --- .../locales/en-US/passes.ftl | 3 +++ compiler/rustc_passes/src/check_attr.rs | 23 +++++++++++++++++++ compiler/rustc_passes/src/errors.rs | 4 ++++ 3 files changed, 30 insertions(+) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 1f1c9c29d665a..4bc6bd9fb2207 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -145,6 +145,9 @@ passes_doc_test_takes_list = passes_doc_primitive = `doc(primitive)` should never have been stable +passes_doc_cfg_hide_takes_list = + `#[doc(cfg_hide(...)]` takes a list of attributes + passes_doc_test_unknown_any = unknown `doc` attribute `{$path}` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 73fb89bbc385e..c5ba4eb68fac0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -934,6 +934,22 @@ impl CheckAttrVisitor<'_> { is_valid } + /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes. + /// Returns `true` if valid. + fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { + if meta.meta_item_list().is_some() { + true + } else { + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::DocCfgHideTakesList, + ); + false + } + } + /// Runs various checks on `#[doc]` attributes. Returns `true` if valid. /// /// `specified_inline` should be initialized to `None` and kept for the scope @@ -987,6 +1003,13 @@ impl CheckAttrVisitor<'_> { is_valid = false; } + sym::cfg_hide + if !self.check_attr_crate_level(attr, meta, hir_id) + || !self.check_doc_cfg_hide(meta, hir_id) => + { + is_valid = false; + } + sym::inline | sym::no_inline if !self.check_doc_inline( attr, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 1cc81a9ab9884..ed54834134453 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -271,6 +271,10 @@ pub struct DocTestUnknown { #[diag(passes::doc_test_takes_list)] pub struct DocTestTakesList; +#[derive(LintDiagnostic)] +#[diag(passes::doc_cfg_hide_takes_list)] +pub struct DocCfgHideTakesList; + #[derive(LintDiagnostic)] #[diag(passes::doc_primitive)] pub struct DocPrimitive; From 6f0c2470dbc3eeff7aa243965ec8c3dc7b64e254 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume.gomez@huawei.com> Date: Wed, 12 Oct 2022 11:32:26 +0200 Subject: [PATCH 15/16] Add UI test for invalid `doc(cfg_hide(...))` attributes --- src/test/rustdoc-ui/doc_cfg_hide.rs | 11 +++++++ src/test/rustdoc-ui/doc_cfg_hide.stderr | 40 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/test/rustdoc-ui/doc_cfg_hide.rs create mode 100644 src/test/rustdoc-ui/doc_cfg_hide.stderr diff --git a/src/test/rustdoc-ui/doc_cfg_hide.rs b/src/test/rustdoc-ui/doc_cfg_hide.rs new file mode 100644 index 0000000000000..5d8791748a012 --- /dev/null +++ b/src/test/rustdoc-ui/doc_cfg_hide.rs @@ -0,0 +1,11 @@ +#![feature(doc_cfg_hide)] +#![deny(warnings)] + +#![doc(cfg_hide = "test")] //~ ERROR +//~^ WARN +#![doc(cfg_hide)] //~ ERROR +//~^ WARN + +#[doc(cfg_hide(doc))] //~ ERROR +//~^ WARN +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc_cfg_hide.stderr b/src/test/rustdoc-ui/doc_cfg_hide.stderr new file mode 100644 index 0000000000000..03623368cd047 --- /dev/null +++ b/src/test/rustdoc-ui/doc_cfg_hide.stderr @@ -0,0 +1,40 @@ +error: this attribute can only be applied at the crate level + --> $DIR/doc_cfg_hide.rs:9:7 + | +LL | #[doc(cfg_hide(doc))] + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information +note: the lint level is defined here + --> $DIR/doc_cfg_hide.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` +help: to apply to the crate, use an inner attribute + | +LL | #![doc(cfg_hide(doc))] + | ~~~~~~~~~~~~~~~~~~~~~~ + +error: `#[doc(cfg_hide(...)]` takes a list of attributes + --> $DIR/doc_cfg_hide.rs:4:8 + | +LL | #![doc(cfg_hide = "test")] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: `#[doc(cfg_hide(...)]` takes a list of attributes + --> $DIR/doc_cfg_hide.rs:6:8 + | +LL | #![doc(cfg_hide)] + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: aborting due to 3 previous errors + From 062ea9ce4ded4e5a864dfb4109d6533e03d67679 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <takoyaki0316@gmail.com> Date: Sat, 15 Oct 2022 02:45:11 +0900 Subject: [PATCH 16/16] remove no_core feature --- src/test/ui/traits/issue-102989.rs | 5 +--- src/test/ui/traits/issue-102989.stderr | 35 ++++++++------------------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/test/ui/traits/issue-102989.rs b/src/test/ui/traits/issue-102989.rs index cb1e3271d26e8..62f95272fbfd2 100644 --- a/src/test/ui/traits/issue-102989.rs +++ b/src/test/ui/traits/issue-102989.rs @@ -1,9 +1,6 @@ -//~ ERROR can't find crate for `profiler_builtins` -// compile-flags: -Cinstrument-coverage // normalize-stderr-test "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" -#![no_core] -#![feature(no_core, lang_items)] +#![feature(lang_items)] #[lang="sized"] trait Sized { } //~ ERROR found duplicate lang item `sized` diff --git a/src/test/ui/traits/issue-102989.stderr b/src/test/ui/traits/issue-102989.stderr index efea2251a13f8..efe1a24677457 100644 --- a/src/test/ui/traits/issue-102989.stderr +++ b/src/test/ui/traits/issue-102989.stderr @@ -1,5 +1,5 @@ error: `self` parameter is only allowed in associated functions - --> $DIR/issue-102989.rs:10:15 + --> $DIR/issue-102989.rs:7:15 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^ not semantically valid as function parameter @@ -7,50 +7,37 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { = note: associated functions are those in `impl` or `trait` definitions error[E0412]: cannot find type `Struct` in this scope - --> $DIR/issue-102989.rs:10:22 + --> $DIR/issue-102989.rs:7:22 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^^^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> $DIR/issue-102989.rs:14:13 + --> $DIR/issue-102989.rs:11:13 | LL | let x = x << 1; | ^ help: a local variable with a similar name exists: `f` -error: `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` - -error[E0463]: can't find crate for `profiler_builtins` - | - = note: the compiler may have been built without the profiler runtime - error[E0152]: found duplicate lang item `sized` - --> $DIR/issue-102989.rs:8:1 + --> $DIR/issue-102989.rs:5:1 | LL | trait Sized { } | ^^^^^^^^^^^ | - = note: the lang item is first defined in crate `core`. + = note: the lang item is first defined in crate `core` (which `std` depends on) = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib = note: second definition in the local crate (`issue_102989`) -error: `#[panic_handler]` function required, but not found - -error: language item required, but not found: `eh_personality` - | - = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library - = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` - error[E0277]: the size for values of type `{integer}` cannot be known at compilation time - --> $DIR/issue-102989.rs:14:15 + --> $DIR/issue-102989.rs:11:15 | LL | let x = x << 1; | ^^ doesn't have a size known at compile-time | - = help: the trait `core::marker::Sized` is not implemented for `{integer}` + = help: the trait `std::marker::Sized` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/issue-102989.rs:10:42 + --> $DIR/issue-102989.rs:7:42 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ---------- ^^^^ expected `&u32`, found `()` @@ -58,7 +45,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | implicitly returns `()` as its body has no tail or `return` expression | note: consider returning one of these bindings - --> $DIR/issue-102989.rs:10:30 + --> $DIR/issue-102989.rs:7:30 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^ @@ -66,7 +53,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { LL | let x = x << 1; | ^ -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0152, E0277, E0308, E0412, E0425, E0463. +Some errors have detailed explanations: E0152, E0277, E0308, E0412, E0425. For more information about an error, try `rustc --explain E0152`.