diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 9bbb42eb01961..44da27a43db0a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -265,12 +265,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::discriminant_value => { let place = self.deref_operand(&args[0])?; - if M::enforce_validity(self) { - // This is 'using' the value, so make sure the validity invariant is satisfied. - // (Also see https://github.com/rust-lang/rust/pull/89764.) - self.validate_operand(&place.into())?; - } - let discr_val = self.read_discriminant(&place.into())?.0; self.write_scalar(discr_val, dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 2759a7d9d268f..e6037d561dedc 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -304,12 +304,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Discriminant(place) => { let op = self.eval_place_to_op(place, None)?; - if M::enforce_validity(self) { - // This is 'using' the value, so make sure the validity invariant is satisfied. - // (Also see https://github.com/rust-lang/rust/pull/89764.) - self.validate_operand(&op)?; - } - let discr_val = self.read_discriminant(&op)?.0; self.write_scalar(discr_val, &dest)?; } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c25ec1356e230..3c2f990008062 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -310,6 +310,34 @@ pub fn unexpected_hidden_region_diagnostic( err } +/// Structurally compares two types, modulo any inference variables. +/// +/// Returns `true` if two types are equal, or if one type is an inference variable compatible +/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or +/// FloatVar inference type are compatible with themselves or their concrete types (Int and +/// Float types, respectively). When comparing two ADTs, these rules apply recursively. +pub fn same_type_modulo_infer(a: Ty<'tcx>, b: Ty<'ctx>) -> bool { + match (&a.kind(), &b.kind()) { + (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => { + if did_a != did_b { + return false; + } + + substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b)) + } + (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) + | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_))) + | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) + | ( + &ty::Infer(ty::InferTy::FloatVar(_)), + &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), + ) + | (&ty::Infer(ty::InferTy::TyVar(_)), _) + | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, + _ => a == b, + } +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_region_errors(&self, errors: &Vec>) { debug!("report_region_errors(): {} errors to start", errors.len()); @@ -1761,7 +1789,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.get_impl_future_output_ty(exp_found.expected), self.get_impl_future_output_ty(exp_found.found), ) { - (Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code { + (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code { ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => { diag.multipart_suggestion( "consider `await`ing on both `Future`s", @@ -1793,7 +1821,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag.help("consider `await`ing on both `Future`s"); } }, - (_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => { + (_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => { diag.span_suggestion_verbose( exp_span.shrink_to_hi(), "consider `await`ing on the `Future`", @@ -1801,7 +1829,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - (Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => match cause.code { + (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code { ObligationCauseCode::Pattern { span: Some(span), .. } | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => { diag.span_suggestion_verbose( diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6320d5d47497f..e3a05e01ea8f0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1606,13 +1606,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // encounter a candidate where the test is not relevant; at // that point, we stop sorting. while let Some(candidate) = candidates.first_mut() { - if let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) { - let (candidate, rest) = candidates.split_first_mut().unwrap(); - target_candidates[idx].push(candidate); - candidates = rest; - } else { + let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) else { break; - } + }; + let (candidate, rest) = candidates.split_first_mut().unwrap(); + target_candidates[idx].push(candidate); + candidates = rest; } // at least the first candidate ought to be tested assert!(total_candidate_count > candidates.len()); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 4108ad50470b7..cb94e75997237 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -966,59 +966,58 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { DropKind::Value, ); - if let Some(arg) = arg_opt { - let pat = match tcx.hir().get(arg.pat.hir_id) { - Node::Pat(pat) | Node::Binding(pat) => pat, - node => bug!("pattern became {:?}", node), - }; - let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat); - let original_source_scope = self.source_scope; - let span = pattern.span; - self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); - match *pattern.kind { - // Don't introduce extra copies for simple bindings - PatKind::Binding { - mutability, - var, - mode: BindingMode::ByValue, - subpattern: None, - .. - } => { - self.local_decls[local].mutability = mutability; - self.local_decls[local].source_info.scope = self.source_scope; - self.local_decls[local].local_info = if let Some(kind) = self_binding { - Some(Box::new(LocalInfo::User(ClearCrossCrate::Set( - BindingForm::ImplicitSelf(*kind), - )))) - } else { - let binding_mode = ty::BindingMode::BindByValue(mutability); - Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { - binding_mode, - opt_ty_info, - opt_match_place: Some((Some(place), span)), - pat_span: span, - }, - ))))) - }; - self.var_indices.insert(var, LocalsForNode::One(local)); - } - _ => { - scope = self.declare_bindings( - scope, - expr.span, - &pattern, - matches::ArmHasGuard(false), - Some((Some(&place), span)), - ); - let place_builder = PlaceBuilder::from(local); - unpack!( - block = self.place_into_pattern(block, pattern, place_builder, false) - ); - } + let Some(arg) = arg_opt else { + continue; + }; + let pat = match tcx.hir().get(arg.pat.hir_id) { + Node::Pat(pat) | Node::Binding(pat) => pat, + node => bug!("pattern became {:?}", node), + }; + let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat); + let original_source_scope = self.source_scope; + let span = pattern.span; + self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); + match *pattern.kind { + // Don't introduce extra copies for simple bindings + PatKind::Binding { + mutability, + var, + mode: BindingMode::ByValue, + subpattern: None, + .. + } => { + self.local_decls[local].mutability = mutability; + self.local_decls[local].source_info.scope = self.source_scope; + self.local_decls[local].local_info = if let Some(kind) = self_binding { + Some(Box::new(LocalInfo::User(ClearCrossCrate::Set( + BindingForm::ImplicitSelf(*kind), + )))) + } else { + let binding_mode = ty::BindingMode::BindByValue(mutability); + Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { + binding_mode, + opt_ty_info, + opt_match_place: Some((Some(place), span)), + pat_span: span, + }, + ))))) + }; + self.var_indices.insert(var, LocalsForNode::One(local)); + } + _ => { + scope = self.declare_bindings( + scope, + expr.span, + &pattern, + matches::ArmHasGuard(false), + Some((Some(&place), span)), + ); + let place_builder = PlaceBuilder::from(local); + unpack!(block = self.place_into_pattern(block, pattern, place_builder, false)); } - self.source_scope = original_source_scope; } + self.source_scope = original_source_scope; } // Enter the argument pattern bindings source scope, if it exists. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0e82b18720142..7940bd1f33dc1 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -256,23 +256,22 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } PatKind::Binding { mode: BindingMode::ByRef(borrow_kind), ty, .. } => { if self.inside_adt { - if let ty::Ref(_, ty, _) = ty.kind() { - match borrow_kind { - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => { - if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) { - self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); - } - } - BorrowKind::Mut { .. } => { - self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField); - } - } - } else { + let ty::Ref(_, ty, _) = ty.kind() else { span_bug!( pat.span, "BindingMode::ByRef in pattern, but found non-reference type {}", ty ); + }; + match borrow_kind { + BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => { + if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) { + self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); + } + } + BorrowKind::Mut { .. } => { + self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField); + } } } visit::walk_pat(self, pat); diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 03e33a1ff2bc3..c4e5e44fec0b2 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -341,12 +341,12 @@ impl Rc { unsafe { self.ptr.as_ref() } } - fn from_inner(ptr: NonNull>) -> Self { + unsafe fn from_inner(ptr: NonNull>) -> Self { Self { ptr, phantom: PhantomData } } unsafe fn from_ptr(ptr: *mut RcBox) -> Self { - Self::from_inner(unsafe { NonNull::new_unchecked(ptr) }) + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } } } @@ -367,9 +367,11 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - Self::from_inner( - Box::leak(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value }).into(), - ) + unsafe { + Self::from_inner( + Box::leak(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value }).into(), + ) + } } /// Constructs a new `Rc` using a weak reference to itself. Attempting @@ -420,16 +422,16 @@ impl Rc { // otherwise. let data = data_fn(&weak); - unsafe { + let strong = unsafe { let inner = init_ptr.as_ptr(); ptr::write(ptr::addr_of_mut!((*inner).value), data); let prev_value = (*inner).strong.get(); debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); (*inner).strong.set(1); - } - let strong = Rc::from_inner(init_ptr); + Rc::from_inner(init_ptr) + }; // Strong references should collectively own a shared weak reference, // so don't run the destructor for our old weak reference. @@ -521,10 +523,12 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - Ok(Self::from_inner( - Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?) - .into(), - )) + unsafe { + Ok(Self::from_inner( + Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?) + .into(), + )) + } } /// Constructs a new `Rc` with uninitialized contents, returning an error if the allocation fails @@ -746,7 +750,7 @@ impl Rc> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Rc { - Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) + unsafe { Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) } } } @@ -1214,9 +1218,11 @@ impl Rc { /// ``` pub fn downcast(self) -> Result, Rc> { if (*self).is::() { - let ptr = self.ptr.cast::>(); - forget(self); - Ok(Rc::from_inner(ptr)) + unsafe { + let ptr = self.ptr.cast::>(); + forget(self); + Ok(Rc::from_inner(ptr)) + } } else { Err(self) } @@ -1489,8 +1495,10 @@ impl Clone for Rc { /// ``` #[inline] fn clone(&self) -> Rc { - self.inner().inc_strong(); - Self::from_inner(self.ptr) + unsafe { + self.inner().inc_strong(); + Self::from_inner(self.ptr) + } } } @@ -2245,11 +2253,14 @@ impl Weak { #[stable(feature = "rc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { let inner = self.inner()?; + if inner.strong() == 0 { None } else { - inner.inc_strong(); - Some(Rc::from_inner(self.ptr)) + unsafe { + inner.inc_strong(); + Some(Rc::from_inner(self.ptr)) + } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index b738337a2ddd1..733a898b285ac 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -252,7 +252,7 @@ impl, U: ?Sized> CoerceUnsized> for Arc {} impl, U: ?Sized> DispatchFromDyn> for Arc {} impl Arc { - fn from_inner(ptr: NonNull>) -> Self { + unsafe fn from_inner(ptr: NonNull>) -> Self { Self { ptr, phantom: PhantomData } } @@ -348,7 +348,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data, }; - Self::from_inner(Box::leak(x).into()) + unsafe { Self::from_inner(Box::leak(x).into()) } } /// Constructs a new `Arc` using a weak reference to itself. Attempting @@ -397,7 +397,7 @@ impl Arc { // Now we can properly initialize the inner value and turn our weak // reference into a strong reference. - unsafe { + let strong = unsafe { let inner = init_ptr.as_ptr(); ptr::write(ptr::addr_of_mut!((*inner).data), data); @@ -415,9 +415,9 @@ impl Arc { // possible with safe code alone. let prev_value = (*inner).strong.fetch_add(1, Release); debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); - } - let strong = Arc::from_inner(init_ptr); + Arc::from_inner(init_ptr) + }; // Strong references should collectively own a shared weak reference, // so don't run the destructor for our old weak reference. @@ -529,7 +529,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data, })?; - Ok(Self::from_inner(Box::leak(x).into())) + unsafe { Ok(Self::from_inner(Box::leak(x).into())) } } /// Constructs a new `Arc` with uninitialized contents, returning an error @@ -743,7 +743,7 @@ impl Arc> { #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub unsafe fn assume_init(self) -> Arc { - Arc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) + unsafe { Arc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) } } } @@ -1341,7 +1341,7 @@ impl Clone for Arc { abort(); } - Self::from_inner(self.ptr) + unsafe { Self::from_inner(self.ptr) } } } @@ -1668,9 +1668,11 @@ impl Arc { T: Any + Send + Sync + 'static, { if (*self).is::() { - let ptr = self.ptr.cast::>(); - mem::forget(self); - Ok(Arc::from_inner(ptr)) + unsafe { + let ptr = self.ptr.cast::>(); + mem::forget(self); + Ok(Arc::from_inner(ptr)) + } } else { Err(self) } @@ -1899,7 +1901,7 @@ impl Weak { // value can be initialized after `Weak` references have already been created. In that case, we // expect to observe the fully initialized value. match inner.strong.compare_exchange_weak(n, n + 1, Acquire, Relaxed) { - Ok(_) => return Some(Arc::from_inner(self.ptr)), // null checked above + Ok(_) => return Some(unsafe { Arc::from_inner(self.ptr) }), // null checked above Err(old) => n = old, } } diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs index df74df79d9f47..c7c5b51e7334b 100644 --- a/src/test/ui/async-await/suggest-missing-await.rs +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -54,4 +54,21 @@ async fn suggest_await_on_match_expr() { }; } +async fn dummy_result() -> Result<(), ()> { + Ok(()) +} + +#[allow(unused)] +async fn suggest_await_in_generic_pattern() { + match dummy_result() { + //~^ HELP consider `await`ing on the `Future` + //~| HELP consider `await`ing on the `Future` + //~| SUGGESTION .await + Ok(_) => {} + //~^ ERROR mismatched types [E0308] + Err(_) => {} + //~^ ERROR mismatched types [E0308] + } +} + fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index bea50b3bfc036..3cca9616a358a 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -106,6 +106,42 @@ help: consider `await`ing on the `Future` LL | let _x = match dummy().await { | ++++++ -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:67:9 + | +LL | Ok(_) => {} + | ^^^^^ expected opaque type, found enum `Result` + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:57:28 + | +LL | async fn dummy_result() -> Result<(), ()> { + | ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future>` + found enum `Result<_, _>` +help: consider `await`ing on the `Future` + | +LL | match dummy_result().await { + | ++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:69:9 + | +LL | Err(_) => {} + | ^^^^^^ expected opaque type, found enum `Result` + | +note: while checking the return type of the `async fn` + --> $DIR/suggest-missing-await.rs:57:28 + | +LL | async fn dummy_result() -> Result<(), ()> { + | ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type + = note: expected opaque type `impl Future>` + found enum `Result<_, _>` +help: consider `await`ing on the `Future` + | +LL | match dummy_result().await { + | ++++++ + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0308`.