diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 0f97879275382..67d1d44b1e1f8 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -155,13 +155,6 @@ fn add_hidden_type<'tcx>( } } -fn get_hidden_type<'tcx>( - hidden_types: &DefinitionSiteHiddenTypes<'tcx>, - def_id: LocalDefId, -) -> Option>> { - hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) -} - #[derive(Debug)] struct DefiningUse<'tcx> { /// The opaque type using non NLL vars. This uses the actual @@ -508,7 +501,8 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>( let tcx = infcx.tcx; let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { - let Some(expected) = get_hidden_type(hidden_types, key.def_id) else { + let Some(expected) = hidden_types.0.get(&key.def_id).map(|ty| EarlyBinder::bind(*ty)) + else { if !tcx.use_typing_mode_borrowck() { if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() && alias_ty.def_id == key.def_id.to_def_id() diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1aaf02646c794..218f0ef5458c6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1817,12 +1817,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let element_ty = if !args.is_empty() { + // This shouldn't happen unless there's another error + // (e.g., never patterns in inappropriate contexts). + if self.diverges.get() != Diverges::Maybe { + self.dcx() + .struct_span_err(expr.span, "unexpected divergence state in checking array") + .delay_as_bug(); + } + let coerce_to = expected .to_option(self) .and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index()) .unwrap_or_else(|| self.next_ty_var(expr.span)); let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); - assert_eq!(self.diverges.get(), Diverges::Maybe); + for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e9f8bcd06be2d..d4236aad8e671 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -104,8 +104,8 @@ pub(crate) struct FnCtxt<'a, 'tcx> { /// the diverges flag is set to something other than `Maybe`. pub(super) diverges: Cell, - /// If one of the function arguments is a never pattern, this counts as diverging code. This - /// affect typechecking of the function body. + /// If one of the function arguments is a never pattern, this counts as diverging code. + /// This affect typechecking of the function body. pub(super) function_diverges_because_of_empty_arguments: Cell, /// Whether the currently checked node is the whole body of the function. diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9f5a85b692642..a615ac9d912dd 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -219,6 +219,12 @@ fn typeck_with_inspect<'tcx>( // the future. fcx.check_repeat_exprs(); + // We need to handle opaque types before emitting ambiguity errors as applying + // defining uses may guide type inference. + if fcx.next_trait_solver() { + fcx.try_handle_opaque_type_uses_next(); + } + fcx.type_inference_fallback(); // Even though coercion casts provide type hints, we check casts after fallback for diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 4c1fe69405e91..05b5b1a8af803 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -22,35 +22,50 @@ impl<'tcx> FnCtxt<'_, 'tcx> { /// inference variables. /// /// It then uses these defining uses to guide inference for all other uses. + /// + /// Unlike `handle_opaque_type_uses_next`, this does not report errors. + #[instrument(level = "debug", skip(self))] + pub(super) fn try_handle_opaque_type_uses_next(&mut self) { + // We clone the opaques instead of stealing them here as we still need + // to use them after fallback. + let opaque_types: Vec<_> = self.infcx.clone_opaque_types(); + + self.compute_definition_site_hidden_types(opaque_types, false); + } + + /// This takes all the opaque type uses during HIR typeck. It first computes + /// the concrete hidden type by iterating over all defining uses. + /// + /// A use during HIR typeck is defining if all non-lifetime arguments are + /// unique generic parameters and the hidden type does not reference any + /// inference variables. + /// + /// It then uses these defining uses to guide inference for all other uses. #[instrument(level = "debug", skip(self))] pub(super) fn handle_opaque_type_uses_next(&mut self) { // We clone the opaques instead of stealing them here as they are still used for // normalization in the next generation trait solver. - let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types(); + let opaque_types: Vec<_> = self.infcx.clone_opaque_types(); let num_entries = self.inner.borrow_mut().opaque_types().num_entries(); let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries)); debug_assert_eq!(prev, None); - for entry in &mut opaque_types { - *entry = self.resolve_vars_if_possible(*entry); - } - debug!(?opaque_types); - self.compute_definition_site_hidden_types(&opaque_types); - self.apply_definition_site_hidden_types(&opaque_types); + self.compute_definition_site_hidden_types(opaque_types, true); } } +#[derive(Copy, Clone, Debug)] enum UsageKind<'tcx> { None, NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>), UnconstrainedHiddenType(OpaqueHiddenType<'tcx>), - HasDefiningUse, + HasDefiningUse(OpaqueHiddenType<'tcx>), } impl<'tcx> UsageKind<'tcx> { fn merge(&mut self, other: UsageKind<'tcx>) { match (&*self, &other) { - (UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(), + (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(), (UsageKind::None, _) => *self = other, // When mergining non-defining uses, prefer earlier ones. This means // the error happens as early as possible. @@ -64,7 +79,7 @@ impl<'tcx> UsageKind<'tcx> { // intended to be defining. ( UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..), - UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse, + UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_), ) => *self = other, } } @@ -73,8 +88,14 @@ impl<'tcx> UsageKind<'tcx> { impl<'tcx> FnCtxt<'_, 'tcx> { fn compute_definition_site_hidden_types( &mut self, - opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], + mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>, + error_on_missing_defining_use: bool, ) { + for entry in opaque_types.iter_mut() { + *entry = self.resolve_vars_if_possible(*entry); + } + debug!(?opaque_types); + let tcx = self.tcx; let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() else { @@ -88,19 +109,47 @@ impl<'tcx> FnCtxt<'_, 'tcx> { _ => unreachable!("not opaque or generator: {def_id:?}"), } + // We do actually need to check this the second pass (we can't just + // store this), because we can go from `UnconstrainedHiddenType` to + // `HasDefiningUse` (because of fallback) let mut usage_kind = UsageKind::None; - for &(opaque_type_key, hidden_type) in opaque_types { + for &(opaque_type_key, hidden_type) in &opaque_types { if opaque_type_key.def_id != def_id { continue; } usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type)); - if let UsageKind::HasDefiningUse = usage_kind { + + if let UsageKind::HasDefiningUse(..) = usage_kind { break; } } + if let UsageKind::HasDefiningUse(ty) = usage_kind { + for &(opaque_type_key, hidden_type) in &opaque_types { + if opaque_type_key.def_id != def_id { + continue; + } + + let expected = EarlyBinder::bind(ty.ty).instantiate(tcx, opaque_type_key.args); + self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); + } + + // Being explicit here: it may be possible that we in a + // previous call to this function we did an insert, but this + // should be just fine, since they all get equated anyways and + // we shouldn't ever go from `HasDefiningUse` to anyway else. + let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty); + } + + // If we're in `fn try_handle_opaque_type_uses_next` then do not + // report any errors. + if !error_on_missing_defining_use { + continue; + } + let guar = match usage_kind { + UsageKind::HasDefiningUse(_) => continue, UsageKind::None => { if let Some(guar) = self.tainted_by_errors() { guar @@ -137,7 +186,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .emit() } } - UsageKind::HasDefiningUse => continue, }; self.typeck_results @@ -148,8 +196,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } + #[tracing::instrument(skip(self), ret)] fn consider_opaque_type_use( - &mut self, + &self, opaque_type_key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>, ) -> UsageKind<'tcx> { @@ -161,11 +210,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ) { match err { NonDefiningUseReason::Tainted(guar) => { - self.typeck_results.borrow_mut().hidden_types.insert( - opaque_type_key.def_id, - OpaqueHiddenType::new_error(self.tcx, guar), - ); - return UsageKind::HasDefiningUse; + return UsageKind::HasDefiningUse(OpaqueHiddenType::new_error(self.tcx, guar)); } _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type), }; @@ -193,27 +238,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.tcx, DefiningScopeKind::HirTypeck, ); - - let prev = self - .typeck_results - .borrow_mut() - .hidden_types - .insert(opaque_type_key.def_id, hidden_type); - assert!(prev.is_none()); - UsageKind::HasDefiningUse - } - - fn apply_definition_site_hidden_types( - &mut self, - opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], - ) { - let tcx = self.tcx; - for &(key, hidden_type) in opaque_types { - let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap(); - - let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); - self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); - } + UsageKind::HasDefiningUse(hidden_type) } /// We may in theory add further uses of an opaque after cloning the opaque diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 874c435402919..1594a0361a62c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -914,7 +914,16 @@ trait UnusedDelimLint { (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true) } - Break(_, Some(ref value)) => { + Break(label, Some(ref value)) => { + // Don't lint on `break 'label ({...})` - the parens are necessary + // to disambiguate from `break 'label {...}` which would be a syntax error. + // This avoids conflicts with the `break_with_label_and_loop` lint. + if label.is_some() + && matches!(value.kind, ast::ExprKind::Paren(ref inner) + if matches!(inner.kind, ast::ExprKind::Block(..))) + { + return; + } (value, UnusedDelimsCtx::BreakValue, false, None, None, true) } diff --git a/compiler/rustc_middle/src/mir/loops.rs b/compiler/rustc_middle/src/mir/loops.rs new file mode 100644 index 0000000000000..ae332913c6421 --- /dev/null +++ b/compiler/rustc_middle/src/mir/loops.rs @@ -0,0 +1,29 @@ +use rustc_index::bit_set::DenseBitSet; + +use super::*; + +/// Compute the set of loop headers in the given body. A loop header is usually defined as a block +/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. +/// However, computing dominators is expensive, so we approximate according to the post-order +/// traversal order. A loop header for us is a block which is visited after its predecessor in +/// post-order. This is ok as we mostly need a heuristic. +pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { + let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); + let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); + for (bb, bbdata) in traversal::postorder(body) { + // Post-order means we visit successors before the block for acyclic CFGs. + // If the successor is not visited yet, consider it a loop header. + for succ in bbdata.terminator().successors() { + if !visited.contains(succ) { + maybe_loop_headers.insert(succ); + } + } + + // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. + // bb1: goto -> bb1; + let _new = visited.insert(bb); + debug_assert!(_new); + } + + maybe_loop_headers +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cb436c8dd0aba..fab04df500a5c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -51,6 +51,7 @@ mod statement; mod syntax; mod terminator; +pub mod loops; pub mod traversal; pub mod visit; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2f857ea45ac72..0d97571fa818a 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -129,6 +129,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let ssa = SsaLocals::new(tcx, body, typing_env); // Clone dominators because we need them while mutating the body. let dominators = body.basic_blocks.dominators().clone(); + let maybe_loop_headers = loops::maybe_loop_headers(body); let arena = DroplessArena::default(); let mut state = @@ -141,6 +142,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); for bb in reverse_postorder { + // N.B. With loops, reverse postorder cannot produce a valid topological order. + // A statement or terminator from inside the loop, that is not processed yet, may have performed an indirect write. + if maybe_loop_headers.contains(bb) { + state.invalidate_derefs(); + } let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; state.visit_basic_block_data(bb, data); } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 59aa811aa73e8..492f5ca82a07e 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { body, arena, map: Map::new(tcx, body, Some(MAX_PLACES)), - maybe_loop_headers: maybe_loop_headers(body), + maybe_loop_headers: loops::maybe_loop_headers(body), opportunities: Vec::new(), }; @@ -830,29 +830,3 @@ enum Update { Incr, Decr, } - -/// Compute the set of loop headers in the given body. A loop header is usually defined as a block -/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. -/// However, computing dominators is expensive, so we approximate according to the post-order -/// traversal order. A loop header for us is a block which is visited after its predecessor in -/// post-order. This is ok as we mostly need a heuristic. -fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { - let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); - let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); - for (bb, bbdata) in traversal::postorder(body) { - // Post-order means we visit successors before the block for acyclic CFGs. - // If the successor is not visited yet, consider it a loop header. - for succ in bbdata.terminator().successors() { - if !visited.contains(succ) { - maybe_loop_headers.insert(succ); - } - } - - // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. - // bb1: goto -> bb1; - let _new = visited.insert(bb); - debug_assert!(_new); - } - - maybe_loop_headers -} diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 109c8476ccb16..ea45d50969909 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -99,19 +99,23 @@ where response_no_constraints(cx, input, Certainty::overflow(false)) } - fn is_ambiguous_result(result: QueryResult) -> bool { - result.is_ok_and(|response| { - has_no_inference_or_external_constraints(response) + fn is_ambiguous_result(result: QueryResult) -> Option { + result.ok().and_then(|response| { + if has_no_inference_or_external_constraints(response) && matches!(response.value.certainty, Certainty::Maybe { .. }) + { + Some(response.value.certainty) + } else { + None + } }) } fn propagate_ambiguity( cx: I, for_input: CanonicalInput, - from_result: QueryResult, + certainty: Certainty, ) -> QueryResult { - let certainty = from_result.unwrap().value.certainty; response_no_constraints(cx, for_input, certainty) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f933423197df3..4b6349e2f4269 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,7 +11,7 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use crate::relate::Relate; -use crate::solve::{CanonicalInput, ExternalConstraintsData, QueryResult, inspect}; +use crate::solve::{CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect}; use crate::visit::{Flags, TypeVisitable}; use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph}; @@ -550,6 +550,7 @@ impl CollectAndApply for Result { impl search_graph::Cx for I { type Input = CanonicalInput; type Result = QueryResult; + type AmbiguityInfo = Certainty; type DepNodeIndex = I::DepNodeIndex; type Tracked = I::Tracked; diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 8a41c99aeaae1..b2a871a21149e 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -40,6 +40,7 @@ pub use global_cache::GlobalCache; pub trait Cx: Copy { type Input: Debug + Eq + Hash + Copy; type Result: Debug + Eq + Hash + Copy; + type AmbiguityInfo: Debug + Eq + Hash + Copy; type DepNodeIndex; type Tracked: Debug; @@ -96,11 +97,13 @@ pub trait Delegate: Sized { input: ::Input, ) -> ::Result; - fn is_ambiguous_result(result: ::Result) -> bool; + fn is_ambiguous_result( + result: ::Result, + ) -> Option<::AmbiguityInfo>; fn propagate_ambiguity( cx: Self::Cx, for_input: ::Input, - from_result: ::Result, + ambiguity_info: ::AmbiguityInfo, ) -> ::Result; fn compute_goal( @@ -913,9 +916,9 @@ impl, X: Cx> SearchGraph { /// heads from the stack. This may not necessarily mean that we've actually /// reached a fixpoint for that cycle head, which impacts the way we rebase /// provisional cache entries. -enum RebaseReason { +enum RebaseReason { NoCycleUsages, - Ambiguity, + Ambiguity(X::AmbiguityInfo), Overflow, /// We've actually reached a fixpoint. /// @@ -951,7 +954,7 @@ impl, X: Cx> SearchGraph { &mut self, cx: X, stack_entry: &StackEntry, - rebase_reason: RebaseReason, + rebase_reason: RebaseReason, ) { let popped_head_index = self.stack.next_index(); #[allow(rustc::potential_query_instability)] @@ -969,10 +972,6 @@ impl, X: Cx> SearchGraph { return true; }; - let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else { - return false; - }; - // We're rebasing an entry `e` over a head `p`. This head // has a number of own heads `h` it depends on. // @@ -1033,8 +1032,8 @@ impl, X: Cx> SearchGraph { // is not actually equal to the final provisional result. We // need to discard the provisional cache entry in this case. RebaseReason::NoCycleUsages => return false, - RebaseReason::Ambiguity => { - *result = D::propagate_ambiguity(cx, input, *result); + RebaseReason::Ambiguity(info) => { + *result = D::propagate_ambiguity(cx, input, info); } RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input), RebaseReason::ReachedFixpoint(None) => {} @@ -1046,6 +1045,10 @@ impl, X: Cx> SearchGraph { }; } + let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else { + return false; + }; + // We now care about the path from the next highest cycle head to the // provisional cache entry. *path_from_head = path_from_head.extend(Self::cycle_path_kind( @@ -1268,6 +1271,7 @@ impl, X: Cx> SearchGraph { } /// Whether we've reached a fixpoint when evaluating a cycle head. + #[instrument(level = "trace", skip(self, stack_entry), ret)] fn reached_fixpoint( &mut self, stack_entry: &StackEntry, @@ -1355,8 +1359,12 @@ impl, X: Cx> SearchGraph { // As we only get to this branch if we haven't yet reached a fixpoint, // we also taint all provisional cache entries which depend on the // current goal. - if D::is_ambiguous_result(result) { - self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Ambiguity); + if let Some(info) = D::is_ambiguous_result(result) { + self.rebase_provisional_cache_entries( + cx, + &stack_entry, + RebaseReason::Ambiguity(info), + ); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); }; diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 7f2a40f753fa6..06d2c93cc698f 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -575,7 +575,8 @@ mod impls { ($($t:ty)*) => { $( #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for $t { + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + impl const Clone for $t { #[inline(always)] fn clone(&self) -> Self { *self @@ -593,7 +594,8 @@ mod impls { } #[unstable(feature = "never_type", issue = "35121")] - impl Clone for ! { + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + impl const Clone for ! { #[inline] fn clone(&self) -> Self { *self @@ -601,7 +603,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for *const T { + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + impl const Clone for *const T { #[inline(always)] fn clone(&self) -> Self { *self @@ -609,7 +612,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for *mut T { + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + impl const Clone for *mut T { #[inline(always)] fn clone(&self) -> Self { *self @@ -618,7 +622,8 @@ mod impls { /// Shared references can be cloned, but mutable references *cannot*! #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for &T { + #[rustc_const_unstable(feature = "const_clone", issue = "142757")] + impl const Clone for &T { #[inline(always)] #[rustc_diagnostic_item = "noop_method_clone"] fn clone(&self) -> Self { diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index f21fe0b4438fb..a2ae034e55e66 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -59,8 +59,7 @@ impl_full_ops! { u8: add(intrinsics::u8_add_with_overflow), mul/div(u16); u16: add(intrinsics::u16_add_with_overflow), mul/div(u32); u32: add(intrinsics::u32_add_with_overflow), mul/div(u64); - // See RFC #521 for enabling this. - // u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); + u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); } /// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index de220e7e38a4b..a9806060d3d81 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -564,7 +564,10 @@ unsafe impl const SliceIndex<[T]> for ops::RangeFrom { slice_index_fail(self.start, slice.len(), slice.len()) } // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } + unsafe { + let new_len = crate::intrinsics::unchecked_sub(slice.len(), self.start); + &*get_offset_len_noubcheck(slice, self.start, new_len) + } } #[inline] @@ -573,7 +576,10 @@ unsafe impl const SliceIndex<[T]> for ops::RangeFrom { slice_index_fail(self.start, slice.len(), slice.len()) } // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } + unsafe { + let new_len = crate::intrinsics::unchecked_sub(slice.len(), self.start); + &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) + } } } diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 92558f2b7d9cc..bdaa865a998d6 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -58,7 +58,7 @@ macro_rules! define_client_handles { } } - impl DecodeMut<'_, '_, S> for $oty { + impl Decode<'_, '_, S> for $oty { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $oty { handle: handle::Handle::decode(r, s), @@ -82,7 +82,7 @@ macro_rules! define_client_handles { } } - impl DecodeMut<'_, '_, S> for $ity { + impl Decode<'_, '_, S> for $ity { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $ity { handle: handle::Handle::decode(r, s), @@ -276,7 +276,7 @@ fn maybe_install_panic_hook(force_show_panics: bool) { /// Client-side helper for handling client panics, entering the bridge, /// deserializing input and serializing output. // FIXME(eddyb) maybe replace `Bridge::enter` with this? -fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( +fn run_client Decode<'a, 's, ()>, R: Encode<()>>( config: BridgeConfig<'_>, f: impl FnOnce(A) -> R, ) -> Buffer { diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 582c43c78fcbb..b0ee9c0cc3027 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -143,7 +143,7 @@ mod symbol; use buffer::Buffer; pub use rpc::PanicMessage; -use rpc::{DecodeMut, Encode, Reader, Writer}; +use rpc::{Decode, Encode, Reader, Writer}; /// Configuration for establishing an active connection between a server and a /// client. The server creates the bridge config (`run_server` in `server.rs`), @@ -168,7 +168,7 @@ impl !Sync for BridgeConfig<'_> {} #[forbid(unsafe_code)] #[allow(non_camel_case_types)] mod api_tags { - use super::rpc::{DecodeMut, Encode, Reader, Writer}; + use super::rpc::{Decode, Encode, Reader, Writer}; macro_rules! declare_tags { ($($name:ident { diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 7f4f5fc3a97d5..ed67674a74ab7 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -12,7 +12,7 @@ pub(super) trait Encode: Sized { pub(super) type Reader<'a> = &'a [u8]; -pub(super) trait DecodeMut<'a, 's, S>: Sized { +pub(super) trait Decode<'a, 's, S>: Sized { fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; } @@ -24,7 +24,7 @@ macro_rules! rpc_encode_decode { } } - impl DecodeMut<'_, '_, S> for $ty { + impl Decode<'_, '_, S> for $ty { fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { const N: usize = size_of::<$ty>(); @@ -43,12 +43,12 @@ macro_rules! rpc_encode_decode { } } - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> + impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S> for $name $(<$($T),+>)? { fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { $name { - $($field: DecodeMut::decode(r, s)),* + $($field: Decode::decode(r, s)),* } } } @@ -58,23 +58,18 @@ macro_rules! rpc_encode_decode { fn encode(self, w: &mut Writer, s: &mut S) { // HACK(eddyb): `Tag` enum duplicated between the // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub(crate) const $variant: u8 = Tag::$variant as u8;)* - } + #[repr(u8)] enum Tag { $($variant),* } match self { $($name::$variant $(($field))* => { - tag::$variant.encode(w, s); + (Tag::$variant as u8).encode(w, s); $($field.encode(w, s);)* })* } } } - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> + impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S> for $name $(<$($T),+>)? { fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { @@ -89,7 +84,7 @@ macro_rules! rpc_encode_decode { match u8::decode(r, s) { $(tag::$variant => { - $(let $field = DecodeMut::decode(r, s);)* + $(let $field = Decode::decode(r, s);)* $name::$variant $(($field))* })* _ => unreachable!(), @@ -103,7 +98,7 @@ impl Encode for () { fn encode(self, _: &mut Writer, _: &mut S) {} } -impl DecodeMut<'_, '_, S> for () { +impl Decode<'_, '_, S> for () { fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} } @@ -113,7 +108,7 @@ impl Encode for u8 { } } -impl DecodeMut<'_, '_, S> for u8 { +impl Decode<'_, '_, S> for u8 { fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { let x = r[0]; *r = &r[1..]; @@ -130,7 +125,7 @@ impl Encode for bool { } } -impl DecodeMut<'_, '_, S> for bool { +impl Decode<'_, '_, S> for bool { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { match u8::decode(r, s) { 0 => false, @@ -146,7 +141,7 @@ impl Encode for char { } } -impl DecodeMut<'_, '_, S> for char { +impl Decode<'_, '_, S> for char { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { char::from_u32(u32::decode(r, s)).unwrap() } @@ -158,7 +153,7 @@ impl Encode for NonZero { } } -impl DecodeMut<'_, '_, S> for NonZero { +impl Decode<'_, '_, S> for NonZero { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { Self::new(u32::decode(r, s)).unwrap() } @@ -171,11 +166,11 @@ impl, B: Encode> Encode for (A, B) { } } -impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> +impl<'a, S, A: for<'s> Decode<'a, 's, S>, B: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S> for (A, B) { fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) + (Decode::decode(r, s), Decode::decode(r, s)) } } @@ -186,7 +181,7 @@ impl Encode for &[u8] { } } -impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { +impl<'a, S> Decode<'a, '_, S> for &'a [u8] { fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { let len = usize::decode(r, s); let xs = &r[..len]; @@ -201,7 +196,7 @@ impl Encode for &str { } } -impl<'a, S> DecodeMut<'a, '_, S> for &'a str { +impl<'a, S> Decode<'a, '_, S> for &'a str { fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { str::from_utf8(<&[u8]>::decode(r, s)).unwrap() } @@ -213,7 +208,7 @@ impl Encode for String { } } -impl DecodeMut<'_, '_, S> for String { +impl Decode<'_, '_, S> for String { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { <&str>::decode(r, s).to_string() } @@ -228,7 +223,7 @@ impl> Encode for Vec { } } -impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec { +impl<'a, S, T: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S> for Vec { fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { let len = usize::decode(r, s); let mut vec = Vec::with_capacity(len); @@ -288,7 +283,7 @@ impl Encode for PanicMessage { } } -impl DecodeMut<'_, '_, S> for PanicMessage { +impl Decode<'_, '_, S> for PanicMessage { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { match Option::::decode(r, s) { Some(s) => PanicMessage::String(s), diff --git a/library/proc_macro/src/bridge/selfless_reify.rs b/library/proc_macro/src/bridge/selfless_reify.rs index b06434a5ffee2..a53550e0b9e0c 100644 --- a/library/proc_macro/src/bridge/selfless_reify.rs +++ b/library/proc_macro/src/bridge/selfless_reify.rs @@ -50,7 +50,7 @@ macro_rules! define_reify_functions { >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic // formatting becomes possible in `const fn`. - assert!(size_of::() == 0, "selfless_reify: closure must be zero-sized"); + const { assert!(size_of::() == 0, "selfless_reify: closure must be zero-sized"); } $(extern $abi)? fn wrapper< $($($param,)*)? diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 2850e1099b700..e9ef26c07f24f 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -32,7 +32,7 @@ macro_rules! define_server_handles { } } - impl DecodeMut<'_, '_, HandleStore>> + impl Decode<'_, '_, HandleStore>> for Marked { fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { @@ -40,7 +40,7 @@ macro_rules! define_server_handles { } } - impl<'s, S: Types> DecodeMut<'_, 's, HandleStore>> + impl<'s, S: Types> Decode<'_, 's, HandleStore>> for &'s Marked { fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore>) -> Self { @@ -48,7 +48,7 @@ macro_rules! define_server_handles { } } - impl<'s, S: Types> DecodeMut<'_, 's, HandleStore>> + impl<'s, S: Types> Decode<'_, 's, HandleStore>> for &'s mut Marked { fn decode( @@ -67,7 +67,7 @@ macro_rules! define_server_handles { } } - impl DecodeMut<'_, '_, HandleStore>> + impl Decode<'_, '_, HandleStore>> for Marked { fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { @@ -355,7 +355,7 @@ pub trait MessagePipe: Sized { fn run_server< S: Server, I: Encode>>, - O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, + O: for<'a, 's> Decode<'a, 's, HandleStore>>, >( strategy: &impl ExecutionStrategy, handle_counters: &'static client::HandleCounters, diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index eb7d30f9a6cc9..0d6a725fddd98 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -102,7 +102,7 @@ impl Encode for Symbol { } } -impl DecodeMut<'_, '_, server::HandleStore>> +impl Decode<'_, '_, server::HandleStore>> for Marked { fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore>) -> Self { @@ -118,7 +118,7 @@ impl Encode>> } } -impl DecodeMut<'_, '_, S> for Symbol { +impl Decode<'_, '_, S> for Symbol { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { Symbol::new(<&str>::decode(r, s)) } diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 61a34b0f68a30..3a37c8f2d4885 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,4 +1,3 @@ -#[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/pal/vexos/os.rs b/library/std/src/sys/pal/vexos/os.rs new file mode 100644 index 0000000000000..405f7c918f4a5 --- /dev/null +++ b/library/std/src/sys/pal/vexos/os.rs @@ -0,0 +1,19 @@ +#[expect(dead_code)] +#[path = "../unsupported/os.rs"] +mod unsupported_os; +pub use unsupported_os::{ + JoinPathsError, SplitPaths, chdir, current_exe, errno, error_string, getcwd, getpid, home_dir, + join_paths, split_paths, temp_dir, +}; + +pub use super::unsupported; + +pub fn exit(_code: i32) -> ! { + unsafe { + vex_sdk::vexSystemExitRequest(); + + loop { + vex_sdk::vexTasksRun(); + } + } +} diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index bd5ba89229117..6ab99ae799d70 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -274,6 +274,8 @@ impl Step for GenerateCopyright { cache_dir }; + let _guard = builder.group("generate-copyright"); + let mut cmd = builder.tool_cmd(Tool::GenerateCopyright); cmd.env("CARGO_MANIFESTS", &cargo_manifests); cmd.env("LICENSE_METADATA", &license_metadata); diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 0e9d4e7e32ba1..72250a26f376e 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -74,7 +74,7 @@ impl Step for Vendor { /// This function runs `cargo vendor` and ensures all required submodules /// are initialized before vendoring begins. fn run(self, builder: &Builder<'_>) -> Self::Output { - builder.info(&format!("Vendoring sources to {:?}", self.root_dir)); + let _guard = builder.group(&format!("Vendoring sources to {:?}", self.root_dir)); let mut cmd = command(&builder.initial_cargo); cmd.arg("vendor"); diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index e59012ff6afa9..ab29d0e80ac2a 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -111,12 +111,12 @@ ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf -ENV TARGETS=$TARGETS,armebv7r-none-eabi -ENV TARGETS=$TARGETS,armebv7r-none-eabihf ENV TARGETS=$TARGETS,armv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf +ENV TARGETS=$TARGETS,armv8r-none-eabihf ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf ENV TARGETS=$TARGETS,armv7a-none-eabi +ENV TARGETS=$TARGETS,armv7a-none-eabihf ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \ CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \ @@ -130,7 +130,9 @@ ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft CC_armv7a_none_eabi=arm-none-eabi-gcc \ CC_armv7a_none_eabihf=arm-none-eabi-gcc \ CFLAGS_armv7a_none_eabi=-march=armv7-a \ - CFLAGS_armv7a_none_eabihf=-march=armv7-a+vfpv3 \ + CFLAGS_armv7a_none_eabihf=-march=armv7-a+fp \ + CC_armv8r_none_eabihf=arm-none-eabi-gcc \ + CFLAGS_armv8r_none_eabihf="-march=armv8-r+fp.sp -mfpu=fp-armv8" \ CC_aarch64_unknown_none_softfloat=aarch64-none-elf-gcc \ CFLAGS_aarch64_unknown_none_softfloat=-mstrict-align -march=armv8-a+nofp+nosimd \ CC_aarch64_unknown_none=aarch64-none-elf-gcc \ diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 2890d26d3f447..9bae8b241a941 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -89,6 +89,7 @@ static TARGETS: &[&str] = &[ "armv7-unknown-linux-gnueabi", "armv7-unknown-linux-gnueabihf", "armv7a-none-eabi", + "armv7a-none-eabihf", "thumbv7neon-unknown-linux-gnueabihf", "armv7-unknown-linux-musleabi", "armv7-unknown-linux-musleabihf", diff --git a/tests/mir-opt/gvn_loop.loop_deref_mut.GVN.diff b/tests/mir-opt/gvn_loop.loop_deref_mut.GVN.diff new file mode 100644 index 0000000000000..92e5ccabedf9e --- /dev/null +++ b/tests/mir-opt/gvn_loop.loop_deref_mut.GVN.diff @@ -0,0 +1,115 @@ +- // MIR for `loop_deref_mut` before GVN ++ // MIR for `loop_deref_mut` after GVN + + fn loop_deref_mut(_1: &mut Value) -> Value { + debug val => _1; + let mut _0: Value; + let _2: &Value; + let _3: &Value; + let mut _4: &Value; + let mut _6: !; + let mut _8: isize; + let mut _9: !; + let mut _10: (); + let mut _12: i32; + let _13: (); + let mut _14: bool; + let mut _15: !; + let mut _16: Value; + scope 1 { + debug val_alias => _2; + let mut _5: bool; + scope 2 { + debug stop => _5; + let _7: i32; + scope 3 { + debug v => _7; + let _11: Value; + scope 4 { + debug v => _11; + } + } + } + } + + bb0: { + StorageLive(_2); +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = &(*_1); + _3 = get::(move _4) -> [return: bb1, unwind unreachable]; + } + + bb1: { + _2 = &(*_3); + StorageDead(_4); +- StorageDead(_3); ++ nop; + StorageLive(_5); + _5 = const false; +- _8 = discriminant((*_2)); ++ _8 = discriminant((*_3)); + switchInt(move _8) -> [0: bb3, otherwise: bb2]; + } + + bb2: { + unreachable; + } + + bb3: { +- StorageLive(_7); +- _7 = copy (((*_2) as V0).0: i32); ++ nop; ++ _7 = copy (((*_3) as V0).0: i32); + StorageLive(_9); + goto -> bb4; + } + + bb4: { + StorageLive(_11); + StorageLive(_12); + _12 = copy _7; +- _11 = Value::V0(move _12); ++ _11 = Value::V0(copy _7); + StorageDead(_12); + StorageLive(_13); + StorageLive(_14); + _14 = copy _5; + switchInt(move _14) -> [0: bb6, otherwise: bb5]; + } + + bb5: { + _0 = move _11; + StorageDead(_14); + StorageDead(_13); + StorageDead(_11); + StorageDead(_9); +- StorageDead(_7); ++ nop; + StorageDead(_5); + StorageDead(_2); + return; + } + + bb6: { + _13 = const (); + StorageDead(_14); + StorageDead(_13); + _5 = const true; + StorageLive(_16); +- _16 = Value::V1; +- (*_1) = move _16; ++ _16 = const Value::V1; ++ (*_1) = const Value::V1; + StorageDead(_16); + _10 = const (); + StorageDead(_11); + goto -> bb4; + } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 01 00 00 00 __ __ __ __ │ ....░░░░ + } + diff --git a/tests/mir-opt/gvn_loop.rs b/tests/mir-opt/gvn_loop.rs new file mode 100644 index 0000000000000..6e9df55a968dc --- /dev/null +++ b/tests/mir-opt/gvn_loop.rs @@ -0,0 +1,39 @@ +//@ test-mir-pass: GVN + +#![crate_type = "lib"] +#![feature(core_intrinsics, rustc_attrs)] + +pub enum Value { + V0(i32), + V1, +} + +// Check that we do not use the dereferenced value of `val_alias` when returning. + +// EMIT_MIR gvn_loop.loop_deref_mut.GVN.diff +fn loop_deref_mut(val: &mut Value) -> Value { + // CHECK-LABEL: fn loop_deref_mut( + // CHECK: [[VAL_REF:_.*]] = get::( + // CHECK: [[V:_.*]] = copy (((*[[VAL_REF]]) as V0).0: i32); + // CEHCK-NOT: copy (*[[VAL_REF]]); + // CHECK: [[RET:_*]] = Value::V0(copy [[V]]); + // CEHCK-NOT: copy (*[[VAL_REF]]); + // CHECK: _0 = move [[RET]] + let val_alias: &Value = get(val); + let mut stop = false; + let Value::V0(v) = *val_alias else { unsafe { core::intrinsics::unreachable() } }; + loop { + let v = Value::V0(v); + if stop { + return v; + } + stop = true; + *val = Value::V1; + } +} + +#[inline(never)] +#[rustc_nounwind] +fn get(v: &T) -> &T { + v +} diff --git a/tests/ui/lint/unused/break-label-with-parens-147542.rs b/tests/ui/lint/unused/break-label-with-parens-147542.rs new file mode 100644 index 0000000000000..227a00ad40882 --- /dev/null +++ b/tests/ui/lint/unused/break-label-with-parens-147542.rs @@ -0,0 +1,22 @@ +//@ check-pass + +// Regression test for #147542 +// Ensures that we don't suggest removing parens in a break with label and loop +// when the parens are necessary for correct parsing. + +#![warn(unused_parens)] +#![warn(break_with_label_and_loop)] + +fn xyz() -> usize { + 'foo: { + // parens bellow are necessary break of break with label and loop + break 'foo ({ + println!("Hello!"); + 123 + }); + } +} + +fn main() { + xyz(); +} diff --git a/tests/ui/mir/gvn-loop-miscompile.rs b/tests/ui/mir/gvn-loop-miscompile.rs new file mode 100644 index 0000000000000..8e987c5c94662 --- /dev/null +++ b/tests/ui/mir/gvn-loop-miscompile.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -O +//@ run-pass + +pub enum Value { + V0(i32), + V1, +} + +fn set_discriminant(val: &mut Value) -> Value { + let val_alias: &Value = get(val); + let mut stop = false; + let Value::V0(v) = *val_alias else { + unreachable!(); + }; + loop { + let v = Value::V0(v); + if stop { + return v; + } + stop = true; + *val = Value::V1; + } +} + +fn main() { + let mut v = Value::V0(1); + let v = set_discriminant(&mut v); + assert!(matches!(v, Value::V0(1))); +} + +#[inline(never)] +fn get(v: &T) -> &T { + v +} diff --git a/tests/ui/never_type/never-pattern-as-closure-param-141592.rs b/tests/ui/never_type/never-pattern-as-closure-param-141592.rs new file mode 100644 index 0000000000000..78939199d09cc --- /dev/null +++ b/tests/ui/never_type/never-pattern-as-closure-param-141592.rs @@ -0,0 +1,24 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Never {} + +fn example(x: Never) -> [i32; 1] { + let ! = x; + [1] +} + +fn function_param_never(!: Never) -> [i32; 1] { + [1] +} + +fn generic_never(!: T) -> [i32; 1] //~ ERROR mismatched types +where + T: Copy, +{ + [1] +} + +fn main() { + let _ = "12".lines().map(|!| [1]); //~ ERROR mismatched types +} diff --git a/tests/ui/never_type/never-pattern-as-closure-param-141592.stderr b/tests/ui/never_type/never-pattern-as-closure-param-141592.stderr new file mode 100644 index 0000000000000..ce5d3a57862bf --- /dev/null +++ b/tests/ui/never_type/never-pattern-as-closure-param-141592.stderr @@ -0,0 +1,18 @@ +error: mismatched types + --> $DIR/never-pattern-as-closure-param-141592.rs:15:21 + | +LL | fn generic_never(!: T) -> [i32; 1] + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `T` + +error: mismatched types + --> $DIR/never-pattern-as-closure-param-141592.rs:23:31 + | +LL | let _ = "12".lines().map(|!| [1]); + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `str` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.rs b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.rs new file mode 100644 index 0000000000000..aa5893d621cdb --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Znext-solver +#![feature(rustc_attrs)] +#![rustc_no_implicit_bounds] + +// A regression test making sure that when forcing dependent +// provisional cache entries to ambiguous, we use the `MaybeCause` +// of the cycle head. We ended up trying to use the current result +// of the provisional cache entry, which is incorrect and caused an +// ICE when trying to unwrap it. + +struct Root(T); +struct Head(T); +struct Error(T); +struct NotImplemented(T); + +#[rustc_coinductive] +trait Trait {} +impl Trait for Root +where + Head: Trait, +{} + +impl Trait for Head +where + Root: Trait, + T: Trait, // ambiguous +{} + +impl Trait for Head +where + Error: Trait, + NotImplemented: Trait, +{} + +impl Trait for Error +where + Head: Trait, + NotImplemented: Trait, +{} + +fn impls_trait() {} +fn main() { + impls_trait::>() //~ ERROR type annotations needed +} diff --git a/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr new file mode 100644 index 0000000000000..dd4049a66d0b4 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/forced_ambiguity-use-head-maybe-cause.stderr @@ -0,0 +1,27 @@ +error[E0283]: type annotations needed + --> $DIR/forced_ambiguity-use-head-maybe-cause.rs:43:19 + | +LL | impls_trait::>() + | ^^^^^^^ cannot infer type for struct `Head<_>` + | + = note: cannot satisfy `Head<_>: Trait` + = help: the trait `Trait` is implemented for `Head` +note: required for `Root<_>` to implement `Trait` + --> $DIR/forced_ambiguity-use-head-maybe-cause.rs:18:9 + | +LL | impl Trait for Root + | ^^^^^ ^^^^^^^ +LL | where +LL | Head: Trait, + | ----- unsatisfied trait bound introduced here + = note: 8 redundant requirements hidden + = note: required for `Root<_>` to implement `Trait` +note: required by a bound in `impls_trait` + --> $DIR/forced_ambiguity-use-head-maybe-cause.rs:41:19 + | +LL | fn impls_trait() {} + | ^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs new file mode 100644 index 0000000000000..0bd01e66b02b8 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs @@ -0,0 +1,44 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#240. Hidden types should +// equate *before* inference var fallback, otherwise we can get mismatched types. + +#[derive(Clone, Copy)] +struct FileSystem; +impl FileSystem { + fn build(self, commands: T) -> Option { + match false { + true => Some(commands), + false => { + drop(match self.build::<_>(commands) { + Some(x) => x, + None => return None, + }); + panic!() + }, + } + } +} + +fn build2() -> impl Sized { + if false { + build2::() + } else { + loop {} + }; + 1u32 +} + +fn build3<'a>() -> impl Sized + use<'a> { + if false { + build3() + } else { + loop {} + }; + 1u32 +} + +fn main() {}