about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-11-04 12:12:55 +0000
committerbors <bors@rust-lang.org>2024-11-04 12:12:55 +0000
commit432972cae64d736b892e7a4c8b4fe7fe0e888904 (patch)
tree8c96044d7fe46e27d14655d0925d226901a483a8
parentca87b535a05097df6abbe2a031b057de2cefac5b (diff)
parente3bd6b27f3e788c20598cae3aa57a914142606e4 (diff)
downloadrust-432972cae64d736b892e7a4c8b4fe7fe0e888904.tar.gz
rust-432972cae64d736b892e7a4c8b4fe7fe0e888904.zip
Auto merge of #132275 - compiler-errors:deref-effects, r=fee1-dead
Register `~const` preds for `Deref` adjustments in HIR typeck

This doesn't *do* anything yet, since `Deref` and `DerefMut` aren't constified, and we explicitly don't error on calling non-const trait methods in HIR yet -- presumably that will wait until std is re-constified. But I'm confident this logic is correct, and this (afaict?) is the only major hole left in enforcing `~const` in HIR typeck.

r? fee1-dead
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs30
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs1
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs12
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs12
-rw-r--r--tests/ui/traits/const-traits/effects/auxiliary/minicore.rs (renamed from tests/ui/traits/const-traits/effects/minicore.rs)162
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-deref-fail.rs20
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-deref-fail.stderr9
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-works.rs22
-rw-r--r--tests/ui/traits/const-traits/effects/minicore.stderr13
9 files changed, 140 insertions, 141 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 2753bee499b..e76d9b3c942 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 d5c7fe5fff3..3d401cef76f 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 ce27e81813c..f8ab555305f 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -1,5 +1,6 @@
 use rustc_abi::FieldIdx;
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
@@ -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 0481f715019..06d23d9a968 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
index 50badcd2e87..209a111c243 100644
--- a/tests/ui/traits/const-traits/effects/minicore.rs
+++ b/tests/ui/traits/const-traits/effects/auxiliary/minicore.rs
@@ -1,12 +1,7 @@
-//@ 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(const_trait_impl) check-pass
-//@ compile-flags: -Znext-solver
-
-#![crate_type = "lib"]
+//@ compile-flags: -Znext-solver -Cpanic=abort
+//@ no-prefer-dynamic
+
+#![crate_type = "rlib"]
 #![feature(
     no_core,
     lang_items,
@@ -23,13 +18,17 @@
 #![no_core]
 
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized {}
 #[lang = "copy"]
-trait Copy {}
+pub trait Copy {}
+
+impl Copy for bool {}
+impl Copy for u8 {}
+impl<T: ?Sized> Copy for &T {}
 
 #[lang = "add"]
 #[const_trait]
-trait Add<Rhs = Self> {
+pub trait Add<Rhs = Self> {
     type Output;
 
     fn add(self, rhs: Rhs) -> Self::Output;
@@ -50,10 +49,9 @@ const fn bar() {
     let x = 42_i32 + 43_i32;
 }
 
-
 #[lang = "Try"]
 #[const_trait]
-trait Try: FromResidual<Self::Residual> {
+pub trait Try: FromResidual<Self::Residual> {
     type Output;
     type Residual;
 
@@ -64,9 +62,8 @@ trait Try: FromResidual<Self::Residual> {
     fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
 }
 
-// FIXME
-// #[const_trait]
-trait FromResidual<R = <Self as /* FIXME: ~const */ Try>::Residual> {
+#[const_trait]
+pub trait FromResidual<R = <Self as Try>::Residual> {
     #[lang = "from_residual"]
     fn from_residual(residual: R) -> Self;
 }
@@ -81,71 +78,32 @@ enum ControlFlow<B, C = ()> {
 #[const_trait]
 #[lang = "fn"]
 #[rustc_paren_sugar]
-trait Fn<Args: Tuple>: ~const FnMut<Args> {
+pub trait Fn<Args: Tuple>: ~const FnMut<Args> {
     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
 }
 
 #[const_trait]
 #[lang = "fn_mut"]
 #[rustc_paren_sugar]
-trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
+pub trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
 }
 
 #[const_trait]
 #[lang = "fn_once"]
 #[rustc_paren_sugar]
-trait FnOnce<Args: Tuple> {
+pub trait FnOnce<Args: Tuple> {
     #[lang = "fn_once_output"]
     type Output;
 
     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
 }
 
-struct ConstFnMutClosure<CapturedData, Function> {
-    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<ClosureArguments> 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<ClosureArguments> 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<T: ?Sized> LegacyReceiver for &T {}
 
@@ -153,30 +111,26 @@ impl<T: ?Sized> 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<O> {
+pub trait Residual<O> {
     type TryType: ~const Try<Output = O, Residual = Self> + Try<Output = O, Residual = Self>;
 }
-*/
 
 const fn size_of<T>() -> usize {
     42
 }
 
-impl Copy for u8 {}
-
 impl usize {
     #[rustc_allow_incoherent_impl]
     const fn repeat_u8(x: u8) -> usize {
@@ -197,15 +151,14 @@ fn panic_fmt() {}
 
 #[lang = "index"]
 #[const_trait]
-trait Index<Idx: ?Sized> {
+pub trait Index<Idx: ?Sized> {
     type Output: ?Sized;
 
     fn index(&self, index: Idx) -> &Self::Output;
 }
 
-
 #[const_trait]
-unsafe trait SliceIndex<T: ?Sized> {
+pub unsafe trait SliceIndex<T: ?Sized> {
     type Output: ?Sized;
     fn index(self, slice: &T) -> &Self::Output;
 }
@@ -221,7 +174,7 @@ where
         index.index(self)
     }
 }
-/* FIXME
+
 impl<T, I, const N: usize> const Index<I> for [T; N]
 where
     [T]: ~const Index<I>,
@@ -229,35 +182,29 @@ where
     type Output = <[T] as Index<I>>::Output;
 
     #[inline]
-    // FIXME: make `Self::Output` act like `<Self as ~const Index<I>>::Output`
     fn index(&self, index: I) -> &<[T] as Index<I>>::Output {
         Index::index(self as &[T], index)
     }
 }
-*/
 
 #[lang = "unsize"]
-trait Unsize<T: ?Sized> {
-}
+pub trait Unsize<T: ?Sized> {}
 
 #[lang = "coerce_unsized"]
-trait CoerceUnsized<T: ?Sized> {
-}
+pub trait CoerceUnsized<T: ?Sized> {}
 
 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, 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<T: ?Sized> /* const */ Deref for &T {
+impl<T: ?Sized> const Deref for &T {
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -265,7 +212,7 @@ impl<T: ?Sized> /* const */ Deref for &T {
     }
 }
 
-impl<T: ?Sized> /* const */ Deref for &mut T {
+impl<T: ?Sized> const Deref for &mut T {
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -298,7 +245,6 @@ impl<T> Option<T> {
 
 use Option::*;
 
-/*
 const fn as_deref<T>(opt: &Option<T>) -> Option<&T::Target>
 where
     T: ~const Deref,
@@ -308,15 +254,14 @@ where
         Option::None => Option::None,
     }
 }
-*/
 
 #[const_trait]
-trait Into<T>: Sized {
+pub trait Into<T>: Sized {
     fn into(self) -> T;
 }
 
 #[const_trait]
-trait From<T>: Sized {
+pub trait From<T>: Sized {
     fn from(value: T) -> Self;
 }
 
@@ -351,7 +296,7 @@ fn from_str(s: &str) -> Result<bool, ()> {
 
 #[lang = "eq"]
 #[const_trait]
-trait PartialEq<Rhs: ?Sized = Self> {
+pub trait PartialEq<Rhs: ?Sized = Self> {
     fn eq(&self, other: &Rhs) -> bool;
     fn ne(&self, other: &Rhs) -> bool {
         !self.eq(other)
@@ -373,10 +318,9 @@ impl PartialEq for str {
     }
 }
 
-
 #[lang = "not"]
 #[const_trait]
-trait Not {
+pub trait Not {
     type Output;
     fn not(self) -> Self::Output;
 }
@@ -388,9 +332,6 @@ impl const Not for bool {
     }
 }
 
-impl Copy for bool {}
-impl<'a> Copy for &'a str {}
-
 #[lang = "pin"]
 #[fundamental]
 #[repr(transparent)]
@@ -411,23 +352,21 @@ impl<'a, T: ?Sized> Pin<&'a T> {
     }
 }
 
-
 impl<P: Deref> Pin<P> {
-    /* 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<T> Option<T> {
     const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
         match Pin::get_ref(self).as_ref() {
@@ -445,16 +384,15 @@ impl<T> Option<T> {
         }
     }
 }
-*/
 
-impl<P: /* ~const */ Deref> /* const */ Deref for Pin<P> {
+impl<P: ~const Deref> const Deref for Pin<P> {
     type Target = P::Target;
     fn deref(&self) -> &P::Target {
         Pin::get_ref(Pin::as_ref(self))
     }
 }
 
-impl<T> /* const */ Deref for Option<T> {
+impl<T> const Deref for Option<T> {
     type Target = T;
     fn deref(&self) -> &T {
         loop {}
@@ -506,23 +444,22 @@ impl<T: ?Sized> 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: ~const Destruct>(_: T) {}
+// FIXME: const fn drop<T: ~const Destruct>(_: T) {}
 
-#[rustc_const_stable_indirect]
 #[rustc_intrinsic_must_be_overridden]
 #[rustc_intrinsic]
 const fn const_eval_select<ARG: Tuple, F, G, RET>(
@@ -536,10 +473,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 00000000000..f4a7678a009
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-deref-fail.rs
@@ -0,0 +1,20 @@
+//@ aux-build:minicore.rs
+//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort
+
+#![feature(no_core, const_trait_impl)]
+#![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 00000000000..a1f840114fc
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-deref-fail.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `Ty: ~const minicore::Deref` is not satisfied
+  --> $DIR/minicore-deref-fail.rs:18:5
+   |
+LL |     *Ty;
+   |     ^^^
+
+error: aborting due to 1 previous error
+
+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 00000000000..bfbfa8b2d05
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-works.rs
@@ -0,0 +1,22 @@
+//@ 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)]
+
+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.stderr b/tests/ui/traits/const-traits/effects/minicore.stderr
deleted file mode 100644
index 568d98cfe87..00000000000
--- 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