Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

const_eval: allow function pointer signatures containing &mut T in const contexts #116015

Merged
merged 2 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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) {
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/consts/const-eval/issue-114994-fail.rs
Original file line number Diff line number Diff line change
@@ -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() {}
21 changes: 21 additions & 0 deletions tests/ui/consts/const-eval/issue-114994-fail.stderr
Original file line number Diff line number Diff line change
@@ -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`.
18 changes: 18 additions & 0 deletions tests/ui/consts/const-eval/issue-114994.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Loading