diff options
| -rw-r--r-- | Cargo.lock | 8 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/expr.rs | 65 | ||||
| -rw-r--r-- | compiler/rustc_error_messages/locales/en-US/passes.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 142 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs | 22 | ||||
| -rw-r--r-- | library/std/src/sys/unix/thread_parker/darwin.rs | 131 | ||||
| -rw-r--r-- | library/std/src/sys/unix/thread_parker/mod.rs | 13 | ||||
| -rw-r--r-- | library/std/src/thread/tests.rs | 22 | ||||
| -rw-r--r-- | src/test/rustdoc-ui/doc_cfg_hide.rs | 11 | ||||
| -rw-r--r-- | src/test/rustdoc-ui/doc_cfg_hide.stderr | 40 | ||||
| -rw-r--r-- | src/test/ui/drop/drop_order.rs | 64 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/unusual-rib-combinations.rs | 28 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/unusual-rib-combinations.stderr | 61 | ||||
| -rw-r--r-- | src/test/ui/traits/issue-102989.rs | 16 | ||||
| -rw-r--r-- | src/test/ui/traits/issue-102989.stderr | 59 | ||||
| m--------- | src/tools/cargo | 0 |
18 files changed, 609 insertions, 103 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0cc7f8a1c7c..f393a918094 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/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c55b4906302..ec9c3935020 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -387,32 +387,58 @@ impl<'hir> LoweringContext<'_, 'hir> { then: &Block, else_opt: Option<&Expr>, ) -> hir::ExprKind<'hir> { - let lowered_cond = self.lower_expr(cond); - let new_cond = self.manage_let_cond(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) } } - // 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> { - 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, + // 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 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, } } - 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 { + 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, + hir::ExprKind::Binary(op, lhs, rhs), + AttrVec::new(), + )) + } + 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()) + } } } @@ -439,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.manage_let_cond(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())); diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 1f1c9c29d66..4bc6bd9fb22 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 dab8ae47779..3c684fffac8 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 1cc81a9ab98..ed548341344 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -272,6 +272,10 @@ pub struct DocTestUnknown { pub struct DocTestTakesList; #[derive(LintDiagnostic)] +#[diag(passes::doc_cfg_hide_takes_list)] +pub struct DocCfgHideTakesList; + +#[derive(LintDiagnostic)] #[diag(passes::doc_primitive)] pub struct DocPrimitive; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index cc877e2fd30..77ba7a82672 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)] @@ -748,35 +755,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 +1394,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); @@ -1423,9 +1425,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,13 +1463,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); return; } - _ => {} + LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::Elided(_) + | LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ElisionFailure + | LifetimeRibKind::AnonymousReportError => {} } } 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); @@ -1493,8 +1499,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, .. } => { @@ -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) + } } } @@ -2204,7 +2213,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); }); @@ -2399,11 +2408,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 @@ -3938,7 +3945,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 +3959,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/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fda6a2236b1..4431cf9f443 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/library/std/src/sys/unix/thread_parker/darwin.rs b/library/std/src/sys/unix/thread_parker/darwin.rs new file mode 100644 index 00000000000..2f5356fe227 --- /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; + +// 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; + 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 e2453580dc7..35f1e68a87e 100644 --- a/library/std/src/sys/unix/thread_parker/mod.rs +++ b/library/std/src/sys/unix/thread_parker/mod.rs @@ -11,7 +11,18 @@ )))] cfg_if::cfg_if! { - if #[cfg(target_os = "netbsd")] { + if #[cfg(all( + any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ), + not(miri), + ))] { + mod darwin; + pub use darwin::Parker; + } else if #[cfg(target_os = "netbsd")] { mod netbsd; pub use netbsd::Parker; } else { diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 130e47c8d44..dfb8765ab4e 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -245,6 +245,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 { thread::current().unpark(); 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 00000000000..5d8791748a0 --- /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 00000000000..03623368cd0 --- /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 + diff --git a/src/test/ui/drop/drop_order.rs b/src/test/ui/drop/drop_order.rs index e42150dcc09..ba1ac53aa7c 100644 --- a/src/test/ui/drop/drop_order.rs +++ b/src/test/ui/drop/drop_order.rs @@ -1,4 +1,6 @@ // run-pass +// compile-flags: -Z validate-mir +#![feature(let_chains)] use std::cell::RefCell; use std::convert::TryInto; @@ -116,6 +118,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 +196,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(); } 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 00000000000..b4c86aab863 --- /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 00000000000..6d7b4250698 --- /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`. diff --git a/src/test/ui/traits/issue-102989.rs b/src/test/ui/traits/issue-102989.rs new file mode 100644 index 00000000000..62f95272fbf --- /dev/null +++ b/src/test/ui/traits/issue-102989.rs @@ -0,0 +1,16 @@ +// normalize-stderr-test "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" + +#![feature(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 00000000000..efe1a246774 --- /dev/null +++ b/src/test/ui/traits/issue-102989.stderr @@ -0,0 +1,59 @@ +error: `self` parameter is only allowed in associated functions + --> $DIR/issue-102989.rs:7: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: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:11:13 + | +LL | let x = x << 1; + | ^ help: a local variable with a similar name exists: `f` + +error[E0152]: found duplicate lang item `sized` + --> $DIR/issue-102989.rs:5:1 + | +LL | trait Sized { } + | ^^^^^^^^^^^ + | + = 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[E0277]: the size for values of type `{integer}` cannot be known at compilation time + --> $DIR/issue-102989.rs:11:15 + | +LL | let x = x << 1; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `{integer}` + +error[E0308]: mismatched types + --> $DIR/issue-102989.rs:7: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:7:30 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ^ +... +LL | let x = x << 1; + | ^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0152, E0277, E0308, E0412, E0425. +For more information about an error, try `rustc --explain E0152`. diff --git a/src/tools/cargo b/src/tools/cargo -Subproject b8f30cb23c4e5f20854a4f683325782b7cff983 +Subproject b332991a57c9d055f1864de1eed93e2178d4944 |
