about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs38
-rw-r--r--tests/ui/consts/const-eval/issue-114994-fail.rs14
-rw-r--r--tests/ui/consts/const-eval/issue-114994-fail.stderr21
-rw-r--r--tests/ui/consts/const-eval/issue-114994.rs18
4 files changed, 76 insertions, 15 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index f8f9bfb0470..90819d492f4 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -9,16 +9,17 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::traits::BuiltinImplSource;
+use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
-use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_middle::ty::{TraitRef, TypeVisitableExt};
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
+use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
 
 use std::mem;
-use std::ops::Deref;
+use std::ops::{ControlFlow, Deref};
 
 use super::ops::{self, NonConstOp, Status};
 use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
@@ -188,6 +189,24 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
     }
 }
 
+struct LocalReturnTyVisitor<'ck, 'mir, 'tcx> {
+    kind: LocalKind,
+    checker: &'ck mut Checker<'mir, 'tcx>,
+}
+
+impl<'ck, 'mir, 'tcx> TypeVisitor<TyCtxt<'tcx>> for LocalReturnTyVisitor<'ck, 'mir, 'tcx> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match t.kind() {
+            ty::FnPtr(_) => ControlFlow::Continue(()),
+            ty::Ref(_, _, hir::Mutability::Mut) => {
+                self.checker.check_op(ops::ty::MutRef(self.kind));
+                t.super_visit_with(self)
+            }
+            _ => t.super_visit_with(self),
+        }
+    }
+}
+
 pub struct Checker<'mir, 'tcx> {
     ccx: &'mir ConstCx<'mir, 'tcx>,
     qualifs: Qualifs<'mir, 'tcx>,
@@ -346,20 +365,9 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
     fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
         let kind = self.body.local_kind(local);
 
-        for ty in ty.walk() {
-            let ty = match ty.unpack() {
-                GenericArgKind::Type(ty) => ty,
-
-                // No constraints on lifetimes or constants, except potentially
-                // constants' types, but `walk` will get to them as well.
-                GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
-            };
+        let mut visitor = LocalReturnTyVisitor { kind, checker: self };
 
-            match *ty.kind() {
-                ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
-                _ => {}
-            }
-        }
+        visitor.visit_ty(ty);
     }
 
     fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
diff --git a/tests/ui/consts/const-eval/issue-114994-fail.rs b/tests/ui/consts/const-eval/issue-114994-fail.rs
new file mode 100644
index 00000000000..72350464091
--- /dev/null
+++ b/tests/ui/consts/const-eval/issue-114994-fail.rs
@@ -0,0 +1,14 @@
+// This checks that function pointer signatures that are referenced mutably
+// but contain a &mut T parameter still fail in a constant context: see issue #114994.
+//
+// check-fail
+
+const fn use_mut_const_fn(_f: &mut fn(&mut String)) { //~ ERROR mutable references are not allowed in constant functions
+    ()
+}
+
+const fn use_mut_const_tuple_fn(_f: (fn(), &mut u32)) { //~ ERROR mutable references are not allowed in constant functions
+
+}
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/issue-114994-fail.stderr b/tests/ui/consts/const-eval/issue-114994-fail.stderr
new file mode 100644
index 00000000000..4dae8ea9bca
--- /dev/null
+++ b/tests/ui/consts/const-eval/issue-114994-fail.stderr
@@ -0,0 +1,21 @@
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/issue-114994-fail.rs:6:27
+   |
+LL | const fn use_mut_const_fn(_f: &mut fn(&mut String)) {
+   |                           ^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/issue-114994-fail.rs:10:33
+   |
+LL | const fn use_mut_const_tuple_fn(_f: (fn(), &mut u32)) {
+   |                                 ^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/const-eval/issue-114994.rs b/tests/ui/consts/const-eval/issue-114994.rs
new file mode 100644
index 00000000000..a4cb2e61e5f
--- /dev/null
+++ b/tests/ui/consts/const-eval/issue-114994.rs
@@ -0,0 +1,18 @@
+// This checks that function pointer signatures containing &mut T types
+// work in a constant context: see issue #114994.
+//
+// check-pass
+
+const fn use_const_fn(_f: fn(&mut String)) {
+    ()
+}
+
+const fn get_some_fn() -> fn(&mut String) {
+    String::clear
+}
+
+const fn some_const_fn() {
+    let _f: fn(&mut String) = String::clear;
+}
+
+fn main() {}