diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index f5b8b9d6a1e6f..40bf435e6d110 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2184,28 +2184,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - // See . - // - // In the new solver, check the well-formedness of the return type. - // This emulates, in a way, the predicates that fall out of - // normalizing the return type in the old solver. - // - // FIXME(-Znext-solver): We alternatively could check the predicates of - // the method itself hold, but we intentionally do not do this in the old - // solver b/c of cycles, and doing it in the new solver would be stronger. - // This should be fixed in the future, since it likely leads to much better - // method winnowing. - if let Some(xform_ret_ty) = xform_ret_ty - && self.infcx.next_trait_solver() - { - ocx.register_obligation(traits::Obligation::new( - self.tcx, - cause.clone(), - self.param_env, - ty::ClauseKind::WellFormed(xform_ret_ty.into()), - )); - } - // Evaluate those obligations to see if they might possibly hold. for error in ocx.try_evaluate_obligations() { result = ProbeResult::NoMatch; diff --git a/compiler/rustc_interface/src/diagnostics.rs b/compiler/rustc_interface/src/diagnostics.rs index 2a2757f814715..191f36ee2f9f1 100644 --- a/compiler/rustc_interface/src/diagnostics.rs +++ b/compiler/rustc_interface/src/diagnostics.rs @@ -122,13 +122,16 @@ pub(crate) struct MultipleOutputTypesToStdout; #[diag( "target feature `{$feature}` must be {$enabled} to ensure that the ABI of the current target can be implemented correctly" )] -#[note( - "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 #116344 ")] pub(crate) struct AbiRequiredTargetFeature<'a> { pub feature: &'a str, pub enabled: &'a str, + #[note( + "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 #116344 " + )] + pub fcw: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 307d858bf2428..5173f12d6fb66 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -29,7 +29,7 @@ use rustc_span::edition::Edition; use rustc_span::source_map::SourceMapInputs; use rustc_span::{SessionGlobals, Symbol, sym}; use rustc_structures::CrateType; -use rustc_target::spec::Target; +use rustc_target::spec::{Arch, Target}; use tracing::info; use crate::diagnostics; @@ -102,16 +102,36 @@ pub(crate) fn check_abi_required_features(sess: &Session) { ); } + // Make this a hard error on ARM since starting with LLVM24, the backend will otherwise + // emit a (less friendly) hard error. + let hard_error = matches!(sess.target.arch, Arch::Arm); + for feature in abi_feature_constraints.required { if !sess.internal_target_features.contains(&Symbol::intern(feature)) { - sess.dcx() - .emit_warn(diagnostics::AbiRequiredTargetFeature { feature, enabled: "enabled" }); + let diag = diagnostics::AbiRequiredTargetFeature { + feature, + enabled: "enabled", + fcw: !hard_error, + }; + if hard_error { + sess.dcx().emit_err(diag); + } else { + sess.dcx().emit_warn(diag); + } } } for feature in abi_feature_constraints.incompatible { if sess.internal_target_features.contains(&Symbol::intern(feature)) { - sess.dcx() - .emit_warn(diagnostics::AbiRequiredTargetFeature { feature, enabled: "disabled" }); + let diag = diagnostics::AbiRequiredTargetFeature { + feature, + enabled: "disabled", + fcw: !hard_error, + }; + if hard_error { + sess.dcx().emit_err(diag); + } else { + sess.dcx().emit_warn(diag); + } } } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 86c5aaf4a46ed..7bb9b4ff8c375 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1256,13 +1256,11 @@ impl<'tcx> Debug for Rvalue<'tcx> { }; let mut struct_fmt = fmt.debug_struct(&name); - // FIXME(project-rfc-2229#48): This should be a list of capture names/places - if let Some(def_id) = def_id.as_local() - && let Some(upvars) = tcx.upvars_mentioned(def_id) - { - for (&var_id, place) in iter::zip(upvars.keys(), places) { - let var_name = tcx.hir_name(var_id); - struct_fmt.field(var_name.as_str(), place); + if let Some(def_id) = def_id.as_local() { + let captures = tcx.closure_captures(def_id); + assert_eq!(captures.len(), places.len()); + for (&capture, place) in iter::zip(captures, places) { + struct_fmt.field(capture.to_symbol().as_str(), place); } } else { for (index, place) in places.iter().enumerate() { @@ -1277,13 +1275,11 @@ impl<'tcx> Debug for Rvalue<'tcx> { let name = format!("{{coroutine@{:?}}}", tcx.def_span(def_id)); let mut struct_fmt = fmt.debug_struct(&name); - // FIXME(project-rfc-2229#48): This should be a list of capture names/places - if let Some(def_id) = def_id.as_local() - && let Some(upvars) = tcx.upvars_mentioned(def_id) - { - for (&var_id, place) in iter::zip(upvars.keys(), places) { - let var_name = tcx.hir_name(var_id); - struct_fmt.field(var_name.as_str(), place); + if let Some(def_id) = def_id.as_local() { + let captures = tcx.closure_captures(def_id); + assert_eq!(captures.len(), places.len()); + for (&capture, place) in iter::zip(captures, places) { + struct_fmt.field(capture.to_symbol().as_str(), place); } } else { for (index, place) in places.iter().enumerate() { diff --git a/compiler/rustc_mir_transform/src/coverage/hir_info.rs b/compiler/rustc_mir_transform/src/coverage/hir_info.rs index ab66bf1a733ef..246104ee97843 100644 --- a/compiler/rustc_mir_transform/src/coverage/hir_info.rs +++ b/compiler/rustc_mir_transform/src/coverage/hir_info.rs @@ -1,6 +1,7 @@ use rustc_hir as hir; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_middle::hir::nested_filter; +use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; use rustc_span::def_id::LocalDefId; @@ -20,21 +21,24 @@ pub(crate) struct ExtractedHirInfo { pub(crate) hole_spans: Vec, } -pub(crate) fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo { - // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back - // to HIR for it. - - // Synthetic by-move coroutine bodies don't have useful HIR of their own. - // Use the original coroutine body instead. These synthetic bodies are - // created with a coroutine type, so we can inspect that type as-is. - if tcx.is_synthetic_mir(def_id) { - let effective_def_id = +pub(crate) fn extract_hir_info<'tcx>( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, +) -> ExtractedHirInfo { + let def_id: LocalDefId = { + let mut def_id = mir_body.source.def_id().expect_local(); + + // Synthetic by-move coroutine bodies don't have useful HIR of their own. + // Use the original coroutine body instead. These synthetic bodies are + // created with a coroutine type, so we can inspect that type as-is. + if tcx.is_synthetic_mir(def_id) { match *tcx.type_of(def_id).instantiate_identity().skip_normalization().kind() { - ty::Coroutine(coroutine_def_id, _) => coroutine_def_id.expect_local(), - _ => tcx.local_parent(def_id), - }; - return extract_hir_info(tcx, effective_def_id); - } + ty::Coroutine(coroutine_def_id, _) => def_id = coroutine_def_id.expect_local(), + _ => def_id = tcx.local_parent(def_id), + } + } + def_id + }; let hir_node = tcx.hir_node_by_def_id(def_id); let fn_body_id = hir_node.body_id().expect("HIR node is a function with body"); @@ -45,14 +49,15 @@ pub(crate) fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> E let mut body_span = hir_body.value.span; - use hir::{Closure, Expr, ExprKind, Node}; // Unexpand a closure's body span back to the context of its declaration. // This helps with closure bodies that consist of just a single bang-macro, // and also with closure bodies produced by async desugaring. - if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) = - hir_node + if let hir::Node::Expr(expr) = hir_node + && let hir::ExprKind::Closure(closure) = expr.kind + && let Some(effective_body_span) = + body_span.find_ancestor_in_same_ctxt(closure.fn_decl_span) { - body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span); + body_span = effective_body_span; } // The actual signature span is only used if it has the same context and diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index fdca5e9bfdc9b..d8c4ba4b40b04 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -58,10 +58,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage { } fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { - let def_id = mir_body.source.def_id(); - let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered(); + let _span = debug_span!("instrument_function_for_coverage", def_id = ?mir_body.source.def_id()) + .entered(); - let hir_info = hir_info::extract_hir_info(tcx, def_id.expect_local()); + let hir_info = hir_info::extract_hir_info(tcx, mir_body); // Build the coverage graph, which is a simplified view of the MIR control-flow // graph that ignores some details not relevant to coverage instrumentation. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index c4ad541e5b30c..3e7b3d2ae2daa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -79,7 +79,6 @@ use crate::error_reporting::traits::ambiguity::{ use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs}; -use crate::solve::deeply_normalize_for_diagnostics; use crate::traits::{ MatchExpressionArmCause, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, specialization_graph, @@ -1577,10 +1576,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let (expected_found, exp_found, is_simple_error, values, param_env) = match values { None => (None, Mismatch::Fixed("type"), false, None, None), Some(ty::ParamEnvAnd { param_env, value: values }) => { - let mut values = self.resolve_vars_if_possible(values); - if self.next_trait_solver() { - values = deeply_normalize_for_diagnostics(self, param_env, values); - } + let values = self.resolve_vars_if_possible(values); let (is_simple_error, exp_found) = match values { ValuePairs::Terms(ExpectedFound { expected, found }) => { match (expected.kind(), found.kind()) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 11b051b530198..29ae564d9eb9a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1669,8 +1669,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { bound_predicate.rebind(data), ); let unnormalized_term = data.projection_term.to_term(self.tcx, ty::IsRigid::No); - // FIXME(-Znext-solver): For diagnostic purposes, it would be nice - // to deeply normalize this type. let normalized_term = ocx.normalize( &obligation.cause, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index dc29b6311cc7e..fc16b6d44c310 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -504,7 +504,16 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // (*) The predicates of an inherent associated type include the // predicates of the impl that it's contained in. - if !data.self_ty().has_escaping_bound_vars() { + // In an ideal world, there are no escaping bound vars here. However, WF is jank, and + // sometimes there are. We can only `compute_inherent_assoc_term_args` if the Self ty in the + // args has no escaping bound vars. If we already have impl format args, though, + // `compute_inherent_assoc_term_args` is a no-op (and we have no Self type), so no need to + // check for escaping bound vars. + let can_compute_impl_args = + matches!(data.kind, ty::AliasTermKind::InherentConstImpl { .. }) + || !data.self_ty().has_escaping_bound_vars(); + + if can_compute_impl_args { // FIXME(inherent_associated_types): Should this happen inside of a snapshot? // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm! let args = traits::project::compute_inherent_assoc_term_args( @@ -1099,10 +1108,12 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.add_wf_preds_for_inherent_projection(alias_const.into()); return; // Subtree is handled by above function } - // please ping khyperia and/or BoxyUwU if this `bug!` fires - ty::AliasConstKind::InherentImpl { .. } => bug!( - "This ought to be unreachable, the entrypoints of WF should still have InherentSelf-form alias consts." - ), + // FIXME: This should be unreachable but isn't because we normalize in item + // wfck before computing wf requirements + ty::AliasConstKind::InherentImpl { .. } => { + self.add_wf_preds_for_inherent_projection(alias_const.into()); + return; + } ty::AliasConstKind::Projection { def_id } | ty::AliasConstKind::Free { def_id } | ty::AliasConstKind::Anon { def_id } => { diff --git a/compiler/rustc_type_ir/src/term_kind.rs b/compiler/rustc_type_ir/src/term_kind.rs index bb4ebf054d263..ed23b196fe269 100644 --- a/compiler/rustc_type_ir/src/term_kind.rs +++ b/compiler/rustc_type_ir/src/term_kind.rs @@ -1,3 +1,5 @@ +use std::debug_assert_matches; + use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash_NoContext}; @@ -265,11 +267,25 @@ impl AliasTerm { /// The following methods work only with (trait) associated term projections. // FIXME: Replace by an impl on Alias impl AliasTerm { + fn debug_assert_has_self(self) { + // InherentConstImpl is deliberately omitted here, it is not self-format args + debug_assert_matches!( + self.kind, + AliasTermKind::ProjectionTy { .. } + | AliasTermKind::ProjectionConst { .. } + | AliasTermKind::InherentTy { .. } + | AliasTermKind::InherentConstSelf { .. }, + "AliasTerm::self_ty is only valid on projection and inherent aliases" + ); + } + pub fn self_ty(self) -> I::Ty { + self.debug_assert_has_self(); self.args.type_at(0) } pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + self.debug_assert_has_self(); AliasTerm::new( interner, self.kind, diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4af5b6ed3888b..b2afe0b464eb6 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -4326,6 +4326,47 @@ impl UniqueRc { pub fn new(value: T) -> Self { Self::new_in(value, Global) } +} + +impl UniqueRc { + /// Creates a new `UniqueRc` in the provided allocator. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + #[must_use] + // #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(value: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + RcInner { + strong: Cell::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueRc still stays valid. + weak: Cell::new(1), + value, + }, + alloc, + )); + Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } + } + + #[cfg(not(no_global_oom_handling))] + fn unwrap_with_allocator(this: Self) -> (T, A) { + let inner_ptr = this.ptr; + let (data_ptr, alloc) = Self::into_raw_with_allocator(this); + + // SAFETY: Conceptually moves out of the `UniqueRc`. + // We do not use the data inside ever again. + let val = unsafe { data_ptr.read() }; + + // Drop the strong-weak ref + drop(Weak { ptr: inner_ptr, alloc: &alloc }); + + (val, alloc) + } /// Maps the value in a `UniqueRc`, reusing the allocation if possible. /// @@ -4349,22 +4390,24 @@ impl UniqueRc { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn map(this: Self, f: impl FnOnce(T) -> U) -> UniqueRc { + pub fn map(this: Self, f: impl FnOnce(T) -> U) -> UniqueRc { if size_of::() == size_of::() && align_of::() == align_of::() && UniqueRc::weak_count(&this) == 0 { // ignore-tidy-undocumented-unsafe unsafe { - let ptr = UniqueRc::into_raw(this); + let (ptr, alloc) = UniqueRc::into_raw_with_allocator(this); let value = ptr.read(); - let mut allocation = UniqueRc::from_raw(ptr.cast::>()); + let mut allocation = + UniqueRc::from_raw_with_allocator(ptr.cast::>(), alloc); allocation.write(f(value)); allocation.assume_init() } } else { - UniqueRc::new(f(UniqueRc::unwrap(this))) + let (val, alloc) = UniqueRc::unwrap_with_allocator(this); + UniqueRc::new_in(f(val), alloc) } } @@ -4394,10 +4437,10 @@ impl UniqueRc { pub fn try_map( this: Self, f: impl FnOnce(T) -> R, - ) -> >>::TryType + ) -> >>::TryType where R: Try, - R::Residual: Residual>, + R::Residual: Residual>, { if size_of::() == size_of::() && align_of::() == align_of::() @@ -4405,34 +4448,27 @@ impl UniqueRc { { // ignore-tidy-undocumented-unsafe unsafe { - let ptr = UniqueRc::into_raw(this); + let (ptr, alloc) = UniqueRc::into_raw_with_allocator(this); let value = ptr.read(); - let mut allocation = UniqueRc::from_raw(ptr.cast::>()); + let mut allocation = UniqueRc::from_raw_with_allocator( + ptr.cast::>(), + alloc, + ); allocation.write(f(value)?); try { allocation.assume_init() } } } else { - try { UniqueRc::new(f(UniqueRc::unwrap(this))?) } + let (val, alloc) = UniqueRc::unwrap_with_allocator(this); + try { UniqueRc::new_in(f(val)?, alloc) } } } - - #[cfg(not(no_global_oom_handling))] - fn unwrap(this: Self) -> T { - let this = ManuallyDrop::new(this); - // SAFETY: Pointer is valid for reads. - let val: T = unsafe { ptr::read(&**this) }; - - let _weak = Weak { ptr: this.ptr, alloc: Global }; - - val - } } -impl UniqueRc { +impl UniqueRc { #[cfg(not(no_global_oom_handling))] - unsafe fn from_raw(ptr: *const T) -> Self { - // SAFETY: Caller upholds that data behind pointer is initialised & correct. + unsafe fn from_raw_with_allocator(ptr: *const T, alloc: A) -> Self { + // SAFETY: Upheld by caller let offset = unsafe { data_offset(ptr) }; // Reverse the offset to find the original RcInner. @@ -4444,42 +4480,17 @@ impl UniqueRc { ptr: unsafe { NonNull::new_unchecked(rc_ptr) }, _marker: PhantomData, _marker2: PhantomData, - alloc: Global, + alloc, } } #[cfg(not(no_global_oom_handling))] - fn into_raw(this: Self) -> *const T { + fn into_raw_with_allocator(this: Self) -> (*const T, A) { let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) - } -} - -impl UniqueRc { - /// Creates a new `UniqueRc` in the provided allocator. - /// - /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading - /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. - /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will - /// point to the new [`Rc`]. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn new_in(value: T, alloc: A) -> Self { - let (ptr, alloc) = Box::into_unique(Box::new_in( - RcInner { - strong: Cell::new(0), - // keep one weak reference so if all the weak pointers that are created are dropped - // the UniqueRc still stays valid. - weak: Cell::new(1), - value, - }, - alloc, - )); - Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } + // SAFETY: The copy of the allocator stored in `this` is forgotten + (Self::as_ptr(&this), unsafe { ptr::read(&this.alloc) }) } -} -impl UniqueRc { /// Converts the `UniqueRc` into a regular [`Rc`]. /// /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 403a6563492a8..09a371f94bbb9 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4803,6 +4803,46 @@ impl UniqueArc { pub fn new(value: T) -> Self { Self::new_in(value, Global) } +} + +impl UniqueArc { + /// Creates a new `UniqueArc` in the provided allocator. + /// + /// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`]. + /// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will + /// point to the new [`Arc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + #[must_use] + // #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(data: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + ArcInner { + strong: atomic::AtomicUsize::new(0), + // keep one weak reference so if all the weak pointers that are created are dropped + // the UniqueArc still stays valid. + weak: atomic::AtomicUsize::new(1), + data, + }, + alloc, + )); + Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } + } + + #[cfg(not(no_global_oom_handling))] + fn unwrap_with_allocator(this: Self) -> (T, A) { + let inner_ptr = this.ptr; + let (data_ptr, alloc) = Self::into_raw_with_allocator(this); + + // SAFETY: Conceptually moves out of the `UniqueRc`. + // We do not use the data inside ever again. + let val = unsafe { data_ptr.read() }; + + drop(Weak { ptr: inner_ptr, alloc: &alloc }); + + (val, alloc) + } /// Maps the value in a `UniqueArc`, reusing the allocation if possible. /// @@ -4826,22 +4866,24 @@ impl UniqueArc { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn map(this: Self, f: impl FnOnce(T) -> U) -> UniqueArc { + pub fn map(this: Self, f: impl FnOnce(T) -> U) -> UniqueArc { if size_of::() == size_of::() && align_of::() == align_of::() && UniqueArc::weak_count(&this) == 0 { // ignore-tidy-undocumented-unsafe unsafe { - let ptr = UniqueArc::into_raw(this); + let (ptr, alloc) = UniqueArc::into_raw_with_allocator(this); let value = ptr.read(); - let mut allocation = UniqueArc::from_raw(ptr.cast::>()); + let mut allocation = + UniqueArc::from_raw_with_allocator(ptr.cast::>(), alloc); allocation.write(f(value)); allocation.assume_init() } } else { - UniqueArc::new(f(UniqueArc::unwrap(this))) + let (val, alloc) = UniqueArc::unwrap_with_allocator(this); + UniqueArc::new_in(f(val), alloc) } } @@ -4871,10 +4913,10 @@ impl UniqueArc { pub fn try_map( this: Self, f: impl FnOnce(T) -> R, - ) -> >>::TryType + ) -> >>::TryType where R: Try, - R::Residual: Residual>, + R::Residual: Residual>, { if size_of::() == size_of::() && align_of::() == align_of::() @@ -4882,33 +4924,26 @@ impl UniqueArc { { // ignore-tidy-undocumented-unsafe unsafe { - let ptr = UniqueArc::into_raw(this); + let (ptr, alloc) = UniqueArc::into_raw_with_allocator(this); let value = ptr.read(); - let mut allocation = UniqueArc::from_raw(ptr.cast::>()); + let mut allocation = UniqueArc::from_raw_with_allocator( + ptr.cast::>(), + alloc, + ); allocation.write(f(value)?); try { allocation.assume_init() } } } else { - try { UniqueArc::new(f(UniqueArc::unwrap(this))?) } + let (val, alloc) = UniqueArc::unwrap_with_allocator(this); + try { UniqueArc::new_in(f(val)?, alloc) } } } - - #[cfg(not(no_global_oom_handling))] - fn unwrap(this: Self) -> T { - let this = ManuallyDrop::new(this); - // SAFETY: Pointer is valid for reads and `this` is ManuallyDrop. - let val: T = unsafe { ptr::read(&**this) }; - - let _weak = Weak { ptr: this.ptr, alloc: Global }; - - val - } } -impl UniqueArc { +impl UniqueArc { #[cfg(not(no_global_oom_handling))] - unsafe fn from_raw(ptr: *const T) -> Self { + unsafe fn from_raw_with_allocator(ptr: *const T, alloc: A) -> Self { // SAFETY: Upheld by caller. let offset = unsafe { data_offset(ptr) }; @@ -4921,44 +4956,17 @@ impl UniqueArc { ptr: unsafe { NonNull::new_unchecked(rc_ptr) }, _marker: PhantomData, _marker2: PhantomData, - alloc: Global, + alloc, } } #[cfg(not(no_global_oom_handling))] - fn into_raw(this: Self) -> *const T { + fn into_raw_with_allocator(this: Self) -> (*const T, A) { let this = ManuallyDrop::new(this); - Self::as_ptr(&*this) + // SAFETY: The copy of the allocator stored in `this` is forgotten + (Self::as_ptr(&*this), unsafe { ptr::read(&this.alloc) }) } -} -impl UniqueArc { - /// Creates a new `UniqueArc` in the provided allocator. - /// - /// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading - /// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`]. - /// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will - /// point to the new [`Arc`]. - #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "unique_rc_arc", issue = "112566")] - #[must_use] - // #[unstable(feature = "allocator_api", issue = "32838")] - pub fn new_in(data: T, alloc: A) -> Self { - let (ptr, alloc) = Box::into_unique(Box::new_in( - ArcInner { - strong: atomic::AtomicUsize::new(0), - // keep one weak reference so if all the weak pointers that are created are dropped - // the UniqueArc still stays valid. - weak: atomic::AtomicUsize::new(1), - data, - }, - alloc, - )); - Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc } - } -} - -impl UniqueArc { /// Converts the `UniqueArc` into a regular [`Arc`]. /// /// This consumes the `UniqueArc` and returns a regular [`Arc`] that contains the `value` that diff --git a/library/core/src/cmp/clamp.rs b/library/core/src/cmp/clamp.rs index a737b59bbbe51..e42cd7fb39f29 100644 --- a/library/core/src/cmp/clamp.rs +++ b/library/core/src/cmp/clamp.rs @@ -66,6 +66,7 @@ macro impl_for_float($t:ty) { #[unstable(feature = "clamp_bounds", issue = "147781")] #[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] const impl ClampBounds<$t> for RangeFrom<$t> { + #[inline] fn clamp(self, value: $t) -> $t { assert!(!self.start.is_nan(), "start was NaN"); value.max(self.start) @@ -75,6 +76,7 @@ macro impl_for_float($t:ty) { #[unstable(feature = "clamp_bounds", issue = "147781")] #[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")] const impl ClampBounds<$t> for RangeToInclusive<$t> { + #[inline] fn clamp(self, value: $t) -> $t { assert!(!self.end.is_nan(), "end was NaN"); value.min(self.end) @@ -88,6 +90,7 @@ macro impl_for_float($t:ty) { clippy::neg_cmp_op_on_partial_ord, reason = "NaN check is intentionally included in comparison" )] + #[inline] fn clamp(self, value: $t) -> $t { let (start, end) = self.into_inner(); assert!(start <= end, "start > end, or either was NaN"); diff --git a/library/core/src/num/complex.rs b/library/core/src/num/complex.rs index 9321718899cdd..73b904d81fc53 100644 --- a/library/core/src/num/complex.rs +++ b/library/core/src/num/complex.rs @@ -1,5 +1,7 @@ +use crate::ops::{Add, Sub}; + /// A complex number. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[unstable(feature = "complex_numbers", issue = "154023")] #[repr(C)] #[lang = "complex"] @@ -18,3 +20,39 @@ impl Complex { Complex { re, im } } } + +#[unstable(feature = "complex_numbers", issue = "154023")] +impl Add for Complex { + type Output = Complex; + + fn add(self, rhs: Self) -> Self::Output { + Complex::new(self.re + rhs.re, self.im + rhs.im) + } +} + +#[unstable(feature = "complex_numbers", issue = "154023")] +impl> Add for Complex { + type Output = Complex; + + fn add(self, rhs: T) -> Self::Output { + Complex::new(self.re + rhs, self.im) + } +} + +#[unstable(feature = "complex_numbers", issue = "154023")] +impl Sub for Complex { + type Output = Complex; + + fn sub(self, rhs: Self) -> Self::Output { + Complex::new(self.re - rhs.re, self.im - rhs.im) + } +} + +#[unstable(feature = "complex_numbers", issue = "154023")] +impl> Sub for Complex { + type Output = Complex; + + fn sub(self, rhs: T) -> Self::Output { + Complex::new(self.re - rhs, self.im) + } +} diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 816da7a2fb7f2..f9e2dc6b7f849 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -345,6 +345,8 @@ impl Duration { /// Creates a new `Duration` from the specified number of weeks. /// + /// For this method, one week is defined as 7 days, or 604,800 seconds. + /// /// # Panics /// /// Panics if the given number of weeks overflows the `Duration` size. @@ -373,6 +375,8 @@ impl Duration { /// Creates a new `Duration` from the specified number of days. /// + /// For this method, one day is defined as 24 hours, or 86,400 seconds. + /// /// # Panics /// /// Panics if the given number of days overflows the `Duration` size. @@ -401,6 +405,8 @@ impl Duration { /// Creates a new `Duration` from the specified number of hours. /// + /// For this method, one hour is defined as 60 minutes, or 3,600 seconds. + /// /// # Panics /// /// Panics if the given number of hours overflows the `Duration` size. @@ -429,6 +435,8 @@ impl Duration { /// Creates a new `Duration` from the specified number of minutes. /// + /// For this method, one minute is defined as 60 seconds. + /// /// # Panics /// /// Panics if the given number of minutes overflows the `Duration` size. diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 142df37c2b7fe..4cee09495de8c 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -19,6 +19,7 @@ #![feature(clone_to_uninit)] #![feature(cmp_minmax)] #![feature(cmp_splat)] +#![feature(complex_numbers)] #![feature(const_array)] #![feature(const_bool)] #![feature(const_cell_traits)] diff --git a/library/coretests/tests/num/complex.rs b/library/coretests/tests/num/complex.rs new file mode 100644 index 0000000000000..4260c0a9a27a9 --- /dev/null +++ b/library/coretests/tests/num/complex.rs @@ -0,0 +1,44 @@ +use core::num::{Complex, Wrapping}; + +#[test] +fn complex_addition() { + let a = Complex::new(1, 2); + let b = Complex::new(3, 4); + assert_eq!(a + b, Complex::new(a.re + b.re, a.im + b.im)); + assert_eq!(a + b, b + a); + assert_eq!(a + 8, Complex::new(a.re + 8, a.im)); + + let a = Complex::new(Wrapping(1u8), Wrapping(2)); + let b = Complex::new(Wrapping(3u8), Wrapping(4)); + assert_eq!(a + b, Complex::new(a.re + b.re, a.im + b.im)); + assert_eq!(a + b, b + a); + let c = a + Wrapping(u8::MAX); + assert_eq!(c, Complex::new(a.re + Wrapping(u8::MAX), a.im)); + assert_eq!(c.re.0, 1u8.wrapping_add(u8::MAX)); + + let a = Complex::new(1.0, 2.0); + let b = Complex::new(3.0, 4.0); + assert_eq!(a + b, Complex::new(a.re + b.re, a.im + b.im)); + assert_eq!(a + b, b + a); + assert_eq!(a + 8.0, Complex::new(a.re + 8.0, a.im)); +} + +#[test] +fn complex_subtraction() { + let a = Complex::new(1, 2); + let b = Complex::new(3, 4); + assert_eq!(a - b, Complex::new(a.re - b.re, a.im - b.im)); + assert_eq!(a - 8, Complex::new(a.re - 8, a.im)); + + let a = Complex::new(Wrapping(1u8), Wrapping(2)); + let b = Complex::new(Wrapping(3u8), Wrapping(4)); + assert_eq!(a - b, Complex::new(a.re - b.re, a.im - b.im)); + let c = a - Wrapping(u8::MAX); + assert_eq!(c, Complex::new(a.re - Wrapping(u8::MAX), a.im)); + assert_eq!(c.re.0, 1u8.wrapping_sub(u8::MAX)); + + let a = Complex::new(1.0, 2.0); + let b = Complex::new(3.0, 4.0); + assert_eq!(a - b, Complex::new(a.re - b.re, a.im - b.im)); + assert_eq!(a - 8.0, Complex::new(a.re - 8.0, a.im)); +} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index 0e003e5a9ec27..b1c3001790f07 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -24,6 +24,7 @@ mod u8; mod bignum; mod carryless_mul; mod cast; +mod complex; mod const_from; mod dec2flt; mod float_conversions; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c2007433ff5ea..817d208a8a620 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -390,6 +390,7 @@ #![feature(str_internals)] #![feature(sync_unsafe_cell)] #![feature(temporary_niche_types)] +#![feature(trim_prefix_suffix)] #![feature(ub_checks)] #![feature(uint_carryless_mul)] #![feature(unsafe_pinned)] diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index c99524375113a..288331d4db69a 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -6,6 +6,7 @@ use crate::ffi::{OsStr, OsString, c_void}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, MaybeUninit, offset_of}; +use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; @@ -18,6 +19,9 @@ use crate::sys::time::SystemTime; use crate::sys::{Align8, AsInner, FromInner, IntoInner, c, cvt}; use crate::{fmt, ptr, slice}; +#[cfg(test)] +mod tests; + mod dir; pub use dir::Dir; mod remove_dir_all; @@ -1591,14 +1595,77 @@ pub fn set_times_nofollow(p: &WCStr, times: FileTimes) -> io::Result<()> { } fn get_path(f: impl AsRawHandle) -> io::Result { + let h = f.as_raw_handle(); + // If getting the canonical path fails with ERROR_INVALID_FUNCTION + // then it's likely it failed to resolve the path's drive. + // In that case, use the fallback method to resolve it. + let invalid_function = Some(c::ERROR_INVALID_FUNCTION as i32); + match get_path_canonical(h) { + Err(e) if e.raw_os_error() == invalid_function => get_path_fallback(h).ok_or(e), + result => result, + } +} + +fn get_path_canonical(handle: c::HANDLE) -> io::Result { fill_utf16_buf( - |buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) - }, + |buf, sz| unsafe { c::GetFinalPathNameByHandleW(handle, buf, sz, c::VOLUME_NAME_DOS) }, |buf| PathBuf::from(OsString::from_wide(buf)), ) } +/// Fallback in case `get_path_canonical` fails. +/// +/// `get_path_canonical` can fail if the Win32 drive name cannot be resolved. +/// This can happen with certain third party drivers that don't integrate +/// with the mount manager. +/// +/// Instead we manually do the same job by getting the NT path +/// and then finding the first drive letter that points to a prefix of +/// that path. From there we can construct a Win32 path. +/// +/// It's implemented by first getting the NT path, which should always succeed. +/// Then we use [`GetLogicalDrives`] to get a bit array of win32 drive letters +/// from 'A' to 'Z'. If the corresponding bit is set then it means that drive exists. +/// E.g. bit 2 being set means there's a `C:` drive. +/// +/// Then for each drive we use [`QueryDosDeviceW`] to see the NT path that drive resolves to. +/// If that path is a prefix to the path we got initially then we treat that as the canonical drive letter. +/// So in the unlikely even two drives point to the same device, the lowest one is considered canonical. +/// +/// [`GetLogicalDrives`]: https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives +/// [`QueryDosDeviceW`]: https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-querydosdevicew +fn get_path_fallback(handle: c::HANDLE) -> Option { + fill_utf16_buf( + |buf, sz| unsafe { c::GetFinalPathNameByHandleW(handle, buf, sz, c::VOLUME_NAME_NT) }, + |nt_path| { + let mut buf = [0_u16; c::MAX_PATH as usize]; + for letter in api::get_logical_drives() { + let device_name = [letter as u16, b':' as u16, 0]; + // SAFETY: `device_name` is a null terminated u16 string + if let Some(drive_path) = unsafe { api::query_dos_device(&device_name, &mut buf) } { + if let Some(nt_path) = nt_path.strip_prefix(drive_path) { + // Reserve approximately enough space for the drive + path. + let mut path = Vec::with_capacity(r"\\?\C:".len() + nt_path.len()); + // Create a verbatim drive root (e.g. \\?\D:) + let mut verbatim_root = *br#"\\?\C:"#; + verbatim_root[4] = letter; + path.extend_from_slice(&verbatim_root); + path.extend(OsString::from_wide(nt_path).into_encoded_bytes()); + // SAFETY: All characters are either in the ASCII range (the prefix) + // or else came from an OsString. + unsafe { + return Some(OsString::from_encoded_bytes_unchecked(path).into()); + } + } + } + } + None + }, + ) + .ok() + .flatten() +} + pub fn canonicalize(p: &WCStr) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary diff --git a/library/std/src/sys/fs/windows/tests.rs b/library/std/src/sys/fs/windows/tests.rs new file mode 100644 index 0000000000000..b53dfddecf627 --- /dev/null +++ b/library/std/src/sys/fs/windows/tests.rs @@ -0,0 +1,21 @@ +use super::{get_path_canonical, get_path_fallback}; +use crate::env; +use crate::fs::{File, canonicalize}; +use crate::os::windows::io::AsRawHandle; +use crate::test_helpers::tmpdir; + +#[test] +/// Test that `get_path_canonical` and `get_path_fallback` return the exact same path. +fn canonicalize_fallback() { + let t = tmpdir(); + let fname = t.join("hello.txt"); + // This test may break if run in an environment that requires the fallback. + // So skip it if not in CI. + if env::var_os("CI").is_none() && canonicalize(&fname).is_err() { + return; + } + let f = File::create(fname).unwrap(); + let canonical = get_path_canonical(f.as_raw_handle()).unwrap(); + let fallback = get_path_fallback(f.as_raw_handle()).unwrap(); + assert_eq!(canonical, fallback); +} diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 25a6c2d7d8eda..c3494bf9aa4e6 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -364,3 +364,42 @@ pub macro unicode_str { ) } } + +/// Returns a list of enabled drive letters. +/// +/// This is a wrapper around [`GetLogicalDrives`]. +/// Each letter is returned as an ascii byte. +/// +/// [`GetLogicalDrives`]: (https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives) +pub fn get_logical_drives() -> impl Iterator { + // SAFETY: `GetLogicalDrives` only returns information. + let drives = unsafe { c::GetLogicalDrives() }; + (b'A'..=b'Z').filter(move |letter| drives >> (letter - b'A') & 1 == 1) +} + +/// Get the NT path a device name points to. +/// +/// # Safety +/// +/// `device_name` must be null-terminated. +// FIXME: Use a null-terminated wide string type to assert validity, similar to CStr. +// Then this function can be safe. +pub unsafe fn query_dos_device<'a>( + device_name: &[u16], + buffer: &'a mut [u16], +) -> Option<&'a [u16]> { + let device_ptr = device_name.as_ptr(); + let buffer_ptr = buffer.as_mut_ptr(); + let buffer_len = buffer.len().try_into().ok()?; + // SAFETY: `device_ptr` points to a null-terminated u16 string. + // `buffer_ptr` is writeable up to buffer_len u16s. + let result = unsafe { c::QueryDosDeviceW(device_ptr, buffer_ptr, buffer_len) } as usize; + if result > 0 { + // QueryDosDeviceW returns a list of null-terminated strings where the list itself is also null-terminated + // In the case where you pass a device name (which we always) it only returns one string. + // Therefore to get the string we trim off both the list null termination and the string null termination. + Some(buffer[..result].trim_suffix(&[0, 0])) + } else { + None + } +} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index a0b2126af9a58..c4c4ac8c7d06e 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2181,6 +2181,7 @@ GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW GetFullPathNameW GetLastError +GetLogicalDrives GetModuleFileNameW GetModuleHandleA GetModuleHandleExW @@ -2354,6 +2355,7 @@ PROFILE_KERNEL PROFILE_SERVER PROFILE_USER PROGRESS_CONTINUE +QueryDosDeviceW QueryPerformanceCounter QueryPerformanceFrequency READ_CONTROL @@ -2508,6 +2510,7 @@ UpdateProcThreadAttribute VOLUME_NAME_DOS VOLUME_NAME_GUID VOLUME_NAME_NONE +VOLUME_NAME_NT WAIT_ABANDONED WAIT_ABANDONED_0 WAIT_FAILED diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 9c6f593e1e108..c3c5e193e41f1 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -54,6 +54,7 @@ windows_link::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FI windows_link::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); windows_link::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); windows_link::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); +windows_link::link!("kernel32.dll" "system" fn GetLogicalDrives() -> u32); windows_link::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32); windows_link::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE); windows_link::link!("kernel32.dll" "system" fn GetModuleHandleExW(dwflags : u32, lpmodulename : PCWSTR, phmodule : *mut HMODULE) -> BOOL); @@ -83,6 +84,7 @@ windows_link::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, even windows_link::link!("ntdll.dll" "system" fn NtSetInformationFile(filehandle : HANDLE, iostatusblock : *mut IO_STATUS_BLOCK, fileinformation : *const core::ffi::c_void, length : u32, fileinformationclass : FILE_INFORMATION_CLASS) -> NTSTATUS); windows_link::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); windows_link::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle : HANDLE, desiredaccess : TOKEN_ACCESS_MASK, tokenhandle : *mut HANDLE) -> BOOL); +windows_link::link!("kernel32.dll" "system" fn QueryDosDeviceW(lpdevicename : PCWSTR, lptargetpath : PWSTR, ucchmax : u32) -> u32); windows_link::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL); windows_link::link!("kernel32.dll" "system" fn QueryPerformanceFrequency(lpfrequency : *mut i64) -> BOOL); windows_link::link!("kernel32.dll" "system" fn ReadConsoleW(hconsoleinput : HANDLE, lpbuffer : *mut core::ffi::c_void, nnumberofcharstoread : u32, lpnumberofcharsread : *mut u32, pinputcontrol : *const CONSOLE_READCONSOLE_CONTROL) -> BOOL); @@ -3411,6 +3413,7 @@ impl Default for UNICODE_STRING { pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32; pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32; +pub const VOLUME_NAME_NT: GETFINALPATHNAMEBYHANDLE_FLAGS = 2u32; pub const WAIT_ABANDONED: WAIT_EVENT = 128u32; pub const WAIT_ABANDONED_0: WAIT_EVENT = 128u32; pub type WAIT_EVENT = u32; diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs index 9b1d62f14bb7b..e51340af9a95c 100644 --- a/src/tools/generate-windows-sys/src/main.rs +++ b/src/tools/generate-windows-sys/src/main.rs @@ -33,7 +33,7 @@ fn main() -> Result<(), Box> { let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?; f.write_all(ARM32_SHIM.as_bytes())?; - writeln!(&mut f, "// ignore-tidy-filelength")?; + writeln!(&mut f, "// ignore-tidy-file-filelength")?; Ok(()) } diff --git a/tests/codegen-llvm/intrinsics/unchecked_math.rs b/tests/codegen-llvm/intrinsics/unchecked_math.rs index 419c120ede9ec..7f63ef99c4e12 100644 --- a/tests/codegen-llvm/intrinsics/unchecked_math.rs +++ b/tests/codegen-llvm/intrinsics/unchecked_math.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Z merge-functions=disabled #![crate_type = "lib"] #![feature(core_intrinsics)] diff --git a/tests/mir-opt/issues/issue_154166.rs b/tests/mir-opt/issues/issue_154166.rs new file mode 100644 index 0000000000000..e65c59ea8fca4 --- /dev/null +++ b/tests/mir-opt/issues/issue_154166.rs @@ -0,0 +1,20 @@ +// Check that closure debug implementation correctly displays all captures precisely. + +//@ revisions: e2018 e2021 +//@[e2018] edition: 2018 +//@[e2021] edition: 2021 + +#![crate_type = "lib"] + +pub fn foo(x: (String, String)) { + // CHECK-LABEL: foo( + // e2018: {closure{{.*}}issue_154166{{.*}}} { x: {{.*}} }; + // e2021: {closure{{.*}}issue_154166{{.*}}} { x__0: {{.*}}, x__1: {{.*}} }; + let _closure = || { + if std::hint::black_box(true) { + let _a = &x.1; + } else { + let _b = x.0; + } + }; +} diff --git a/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr b/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr new file mode 100644 index 0000000000000..0766847a93b18 --- /dev/null +++ b/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr @@ -0,0 +1,10 @@ +error: `generic_const_args` requires -Znext-solver=globally to be enabled + --> $DIR/wf-inherentimpl.rs:7:12 + | +LL | #![feature(generic_const_args, min_generic_const_args)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: enable all of these features + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/gca/wf-inherentimpl.rs b/tests/ui/const-generics/gca/wf-inherentimpl.rs new file mode 100644 index 0000000000000..cb3df20daa2dc --- /dev/null +++ b/tests/ui/const-generics/gca/wf-inherentimpl.rs @@ -0,0 +1,16 @@ +//@[next] check-pass +//@ revisions: next old +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +#![feature(inherent_associated_types)] +#![feature(macroless_generic_const_args)] +#![feature(generic_const_args, min_generic_const_args)] +//[old]~^ ERROR `generic_const_args` requires -Znext-solver=globally to be enabled +struct Foo; +impl Foo { + const SIZE: usize = { todo!() }; + fn to_bytes() -> [u8; Self::SIZE] { + todo!() + } +} +fn main() {} diff --git a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr index 52862ec5151b3..73b3e5bacd906 100644 --- a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr +++ b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr @@ -1,7 +1,4 @@ -warning: target feature `fpregs` must be enabled to ensure that the ABI of the current target can be implemented correctly - | - = note: 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 #116344 +error: target feature `fpregs` must be enabled to ensure that the ABI of the current target can be implemented correctly -warning: 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs index e652f321ad33b..59d0ba1a0ba4f 100644 --- a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs +++ b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs @@ -9,14 +9,14 @@ //@[arm] compile-flags: --target=armv8r-none-eabihf -Ctarget-cpu=cortex-r4 //@[arm] needs-llvm-components: arm -// LLVM 24 refuses to compile ARM minicore due to mismatched target features. -// FIXME(#161276): With LLVM rejecting this, we should make Rust's own warning an error. -//@[arm] max-llvm-major-version: 23 +// On x86 this is just a warning. +//@[x86] check-pass +//@[arm] check-fail -// For now this is just a warning. -//@ build-pass //@ ignore-backends: gcc //@ add-minicore +// Don't inherit the target-cpu above for minicore, to avoid errors when building that. +//@ minicore-compile-flags: -Ctarget-cpu=generic #![feature(no_core)] #![no_core] @@ -24,4 +24,5 @@ extern crate minicore; use minicore::*; -//~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly +//[x86]~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly +//[arm]~? ERROR must be enabled to ensure that the ABI of the current target can be implemented correctly