diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index a1a78371fbd25..ca4b2e5f795da 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -254,10 +254,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } for a in &adj { - if let Adjust::NeverToAny = a.kind { - if a.target.is_ty_var() { - self.diverging_type_vars.borrow_mut().insert(a.target); - debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target); + match a.kind { + Adjust::NeverToAny => { + if a.target.is_ty_var() { + self.diverging_type_vars.borrow_mut().insert(a.target); + debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target); + } + } + Adjust::Deref(Some(overloaded_deref)) => { + self.enforce_context_effects( + expr.span, + overloaded_deref.method_call(self.tcx), + self.tcx.mk_args(&[a.target.into()]), + ); + } + Adjust::Deref(None) => { + // FIXME(effects): We *could* enforce `&T: ~const Deref` here. + } + Adjust::Pointer(_pointer_coercion) => { + // FIXME(effects): We should probably enforce these. + } + Adjust::ReborrowPin(_mutability) => { + // FIXME(effects): We could enforce these; they correspond to + // `&mut T: DerefMut` tho, so it's kinda moot. + } + Adjust::Borrow(_) => { + // No effects to enforce here. } } } diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index d5c7fe5fff307..3d401cef76f7d 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -296,6 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); }; *deref = OverloadedDeref { mutbl, span: deref.span }; + self.enforce_context_effects(expr.span, method.def_id, method.args); // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). // This helps avoid accidental drops. if inside_union diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index c56038d358c8e..7ff31e8375fbe 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -1,5 +1,6 @@ -use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_hir::{self as hir}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::Span; use rustc_target::abi::FieldIdx; @@ -123,19 +124,18 @@ pub struct OverloadedDeref { } impl OverloadedDeref { - /// Get the zst function item type for this method call. - pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> Ty<'tcx> { + /// Get the [`DefId`] of the method call for the given `Deref`/`DerefMut` trait + /// for this overloaded deref's mutability. + pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>) -> DefId { let trait_def_id = match self.mutbl { hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None), hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None), }; - let method_def_id = tcx - .associated_items(trait_def_id) + tcx.associated_items(trait_def_id) .in_definition_order() .find(|m| m.kind == ty::AssocKind::Fn) .unwrap() - .def_id; - Ty::new_fn_def(tcx, method_def_id, [source]) + .def_id } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 0481f71501964..06d23d9a9685f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -136,7 +136,9 @@ impl<'tcx> Cx<'tcx> { Adjust::Deref(Some(deref)) => { // We don't need to do call adjust_span here since // deref coercions always start with a built-in deref. - let call = deref.method_call(self.tcx(), expr.ty); + let call_def_id = deref.method_call(self.tcx()); + let overloaded_callee = + Ty::new_fn_def(self.tcx(), call_def_id, self.tcx().mk_args(&[expr.ty.into()])); expr = Expr { temp_lifetime, @@ -150,7 +152,13 @@ impl<'tcx> Cx<'tcx> { let expr = Box::new([self.thir.exprs.push(expr)]); - self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span) + self.overloaded_place( + hir_expr, + adjustment.target, + Some(overloaded_callee), + expr, + deref.span, + ) } Adjust::Borrow(AutoBorrow::Ref(m)) => ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), diff --git a/tests/ui/traits/const-traits/effects/minicore.rs b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs similarity index 68% rename from tests/ui/traits/const-traits/effects/minicore.rs rename to tests/ui/traits/const-traits/effects/auxiliary/minicore.rs index 1f0d22eeb38bd..717737c05e754 100644 --- a/tests/ui/traits/const-traits/effects/minicore.rs +++ b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs @@ -1,28 +1,35 @@ -//@ known-bug: #110395 -//@ failure-status: 101 -//@ normalize-stderr-test: ".*note: .*\n\n" -> "" -//@ normalize-stderr-test: "thread 'rustc' panicked.*:\n.*\n" -> "" -//@ rustc-env:RUST_BACKTRACE=0 -// FIXME(effects) check-pass -//@ compile-flags: -Znext-solver - -#![crate_type = "lib"] -#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs, staged_api)] -#![feature(fundamental, marker_trait_attr)] -#![feature(const_trait_impl, effects)] +//@ compile-flags: -Znext-solver -Cpanic=abort +//@ no-prefer-dynamic + +#![crate_type = "rlib"] +#![feature( + no_core, + lang_items, + unboxed_closures, + auto_traits, + intrinsics, + rustc_attrs, + fundamental, + marker_trait_attr, + const_trait_impl, + effects +)] #![allow(internal_features, incomplete_features)] #![no_std] #![no_core] -#![stable(feature = "minicore", since = "1.0.0")] #[lang = "sized"] -trait Sized {} +pub trait Sized {} #[lang = "copy"] -trait Copy {} +pub trait Copy {} + +impl Copy for bool {} +impl Copy for u8 {} +impl Copy for &T {} #[lang = "add"] #[const_trait] -trait Add { +pub trait Add { type Output; fn add(self, rhs: Rhs) -> Self::Output; @@ -43,10 +50,9 @@ const fn bar() { let x = 42_i32 + 43_i32; } - #[lang = "Try"] #[const_trait] -trait Try: FromResidual { +pub trait Try: FromResidual { type Output; type Residual; @@ -57,9 +63,8 @@ trait Try: FromResidual { fn branch(self) -> ControlFlow; } -// FIXME -// #[const_trait] -trait FromResidual::Residual> { +#[const_trait] +pub trait FromResidual::Residual> { #[lang = "from_residual"] fn from_residual(residual: R) -> Self; } @@ -74,71 +79,32 @@ enum ControlFlow { #[const_trait] #[lang = "fn"] #[rustc_paren_sugar] -trait Fn: ~const FnMut { +pub trait Fn: ~const FnMut { extern "rust-call" fn call(&self, args: Args) -> Self::Output; } #[const_trait] #[lang = "fn_mut"] #[rustc_paren_sugar] -trait FnMut: ~const FnOnce { +pub trait FnMut: ~const FnOnce { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } #[const_trait] #[lang = "fn_once"] #[rustc_paren_sugar] -trait FnOnce { +pub trait FnOnce { #[lang = "fn_once_output"] type Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } -struct ConstFnMutClosure { - data: CapturedData, - func: Function, -} - #[lang = "tuple_trait"] -trait Tuple {} - -macro_rules! impl_fn_mut_tuple { - ($($var:ident)*) => { - impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const - FnOnce for ConstFnMutClosure<($(&'a mut $var),*), Function> - where - Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue, - Function: ~const Destruct, - { - type Output = ClosureReturnValue; - - extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output { - self.call_mut(args) - } - } - impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const - FnMut for ConstFnMutClosure<($(&'a mut $var),*), Function> - where - Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue, - Function: ~const Destruct, - { - extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output { - #[allow(non_snake_case)] - let ($($var),*) = &mut self.data; - (self.func)(($($var),*), args) - } - } - }; -} -//impl_fn_mut_tuple!(A); -//impl_fn_mut_tuple!(A B); -//impl_fn_mut_tuple!(A B C); -//impl_fn_mut_tuple!(A B C D); -//impl_fn_mut_tuple!(A B C D E); +pub trait Tuple {} #[lang = "legacy_receiver"] -trait LegacyReceiver {} +pub trait LegacyReceiver {} impl LegacyReceiver for &T {} @@ -146,30 +112,26 @@ impl LegacyReceiver for &mut T {} #[lang = "destruct"] #[const_trait] -trait Destruct {} +pub trait Destruct {} #[lang = "freeze"] -unsafe auto trait Freeze {} +pub unsafe auto trait Freeze {} #[lang = "drop"] #[const_trait] -trait Drop { +pub trait Drop { fn drop(&mut self); } -/* #[const_trait] -trait Residual { +pub trait Residual { type TryType: ~const Try + Try; } -*/ const fn size_of() -> usize { 42 } -impl Copy for u8 {} - impl usize { #[rustc_allow_incoherent_impl] const fn repeat_u8(x: u8) -> usize { @@ -190,15 +152,14 @@ fn panic_fmt() {} #[lang = "index"] #[const_trait] -trait Index { +pub trait Index { type Output: ?Sized; fn index(&self, index: Idx) -> &Self::Output; } - #[const_trait] -unsafe trait SliceIndex { +pub unsafe trait SliceIndex { type Output: ?Sized; fn index(self, slice: &T) -> &Self::Output; } @@ -214,7 +175,7 @@ where index.index(self) } } -/* FIXME + impl const Index for [T; N] where [T]: ~const Index, @@ -222,35 +183,29 @@ where type Output = <[T] as Index>::Output; #[inline] - // FIXME: make `Self::Output` act like `>::Output` fn index(&self, index: I) -> &<[T] as Index>::Output { Index::index(self as &[T], index) } } -*/ #[lang = "unsize"] -trait Unsize { -} +pub trait Unsize {} #[lang = "coerce_unsized"] -trait CoerceUnsized { -} +pub trait CoerceUnsized {} impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} - #[lang = "deref"] -// #[const_trait] FIXME -trait Deref { +#[const_trait] +pub trait Deref { #[lang = "deref_target"] type Target: ?Sized; fn deref(&self) -> &Self::Target; } - -impl /* const */ Deref for &T { +impl const Deref for &T { type Target = T; fn deref(&self) -> &T { @@ -258,7 +213,7 @@ impl /* const */ Deref for &T { } } -impl /* const */ Deref for &mut T { +impl const Deref for &mut T { type Target = T; fn deref(&self) -> &T { @@ -291,7 +246,6 @@ impl Option { use Option::*; -/* const fn as_deref(opt: &Option) -> Option<&T::Target> where T: ~const Deref, @@ -301,15 +255,14 @@ where Option::None => Option::None, } } -*/ #[const_trait] -trait Into: Sized { +pub trait Into: Sized { fn into(self) -> T; } #[const_trait] -trait From: Sized { +pub trait From: Sized { fn from(value: T) -> Self; } @@ -344,7 +297,7 @@ fn from_str(s: &str) -> Result { #[lang = "eq"] #[const_trait] -trait PartialEq { +pub trait PartialEq { fn eq(&self, other: &Rhs) -> bool; fn ne(&self, other: &Rhs) -> bool { !self.eq(other) @@ -366,10 +319,9 @@ impl PartialEq for str { } } - #[lang = "not"] #[const_trait] -trait Not { +pub trait Not { type Output; fn not(self) -> Self::Output; } @@ -381,9 +333,6 @@ impl const Not for bool { } } -impl Copy for bool {} -impl<'a> Copy for &'a str {} - #[lang = "pin"] #[fundamental] #[repr(transparent)] @@ -404,23 +353,21 @@ impl<'a, T: ?Sized> Pin<&'a T> { } } - impl Pin

{ - /* const */ fn as_ref(&self) -> Pin<&P::Target> + const fn as_ref(&self) -> Pin<&P::Target> where - P: /* ~const */ Deref, + P: ~const Deref, { unsafe { Pin::new_unchecked(&*self.pointer) } } } - impl<'a, T: ?Sized> Pin<&'a mut T> { const unsafe fn get_unchecked_mut(self) -> &'a mut T { self.pointer } } -/* FIXME lol + impl Option { const fn as_pin_ref(self: Pin<&Self>) -> Option> { match Pin::get_ref(self).as_ref() { @@ -438,16 +385,15 @@ impl Option { } } } -*/ -impl /* const */ Deref for Pin

{ +impl const Deref for Pin

{ type Target = P::Target; fn deref(&self) -> &P::Target { Pin::get_ref(Pin::as_ref(self)) } } -impl /* const */ Deref for Option { +impl const Deref for Option { type Target = T; fn deref(&self) -> &T { loop {} @@ -499,23 +445,22 @@ impl Deref for Ref<'_, T> { #[lang = "clone"] #[rustc_trivial_field_reads] -#[const_trait] -trait Clone: Sized { +// FIXME: #[const_trait] +pub trait Clone: Sized { fn clone(&self) -> Self; fn clone_from(&mut self, source: &Self) where - Self: ~const Destruct, + // FIXME: Self: ~const Destruct, { *self = source.clone() } } #[lang = "structural_peq"] -trait StructuralPartialEq {} +pub trait StructuralPartialEq {} -const fn drop(_: T) {} +// FIXME: const fn drop(_: T) {} -#[rustc_const_stable_indirect] #[rustc_intrinsic_must_be_overridden] #[rustc_intrinsic] const fn const_eval_select( @@ -529,10 +474,3 @@ where { loop {} } - -fn test_const_eval_select() { - const fn const_fn() {} - fn rt_fn() {} - - const_eval_select((), const_fn, rt_fn); -} diff --git a/tests/ui/traits/const-traits/effects/minicore-deref-fail.rs b/tests/ui/traits/const-traits/effects/minicore-deref-fail.rs new file mode 100644 index 0000000000000..f6fce1141c063 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-deref-fail.rs @@ -0,0 +1,21 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort + +#![feature(no_core, const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Ty; +impl Deref for Ty { + type Target = (); + fn deref(&self) -> &Self::Target { &() } +} + +const fn foo() { + *Ty; + //~^ ERROR the trait bound `Ty: ~const minicore::Deref` is not satisfied +} diff --git a/tests/ui/traits/const-traits/effects/minicore-deref-fail.stderr b/tests/ui/traits/const-traits/effects/minicore-deref-fail.stderr new file mode 100644 index 0000000000000..b3309648895df --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-deref-fail.stderr @@ -0,0 +1,18 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/minicore-deref-fail.rs:4:39 + | +LL | #![feature(no_core, const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `Ty: ~const minicore::Deref` is not satisfied + --> $DIR/minicore-deref-fail.rs:19:5 + | +LL | *Ty; + | ^^^ + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/effects/minicore-works.rs b/tests/ui/traits/const-traits/effects/minicore-works.rs new file mode 100644 index 0000000000000..23c37b1267cc1 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-works.rs @@ -0,0 +1,23 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort +//@ check-pass + +#![feature(no_core)] +#![no_std] +#![no_core] +#![feature(const_trait_impl, effects)] +//~^ WARN the feature `effects` is incomplete and may not be safe + +extern crate minicore; +use minicore::*; + +struct Custom; +impl const Add for Custom { + type Output = (); + fn add(self, _other: Self) {} +} + +const fn test_op() { + let _x = Add::add(1, 2); + let _y = Custom + Custom; +} diff --git a/tests/ui/traits/const-traits/effects/minicore-works.stderr b/tests/ui/traits/const-traits/effects/minicore-works.stderr new file mode 100644 index 0000000000000..7d602d27cac2d --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-works.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/minicore-works.rs:8:30 + | +LL | #![feature(const_trait_impl, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/const-traits/effects/minicore.stderr b/tests/ui/traits/const-traits/effects/minicore.stderr deleted file mode 100644 index 568d98cfe8715..0000000000000 --- a/tests/ui/traits/const-traits/effects/minicore.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: the compiler unexpectedly panicked. this is a bug. - -query stack during panic: -#0 [typeck] type-checking `Clone::clone_from` -#1 [analysis] running analysis passes on this crate -end of query stack - -error: the compiler unexpectedly panicked. this is a bug. - -query stack during panic: -#0 [typeck] type-checking `test_const_eval_select` -#1 [analysis] running analysis passes on this crate -end of query stack