mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 22:12:15 +00:00
Auto merge of #116015 - EvanMerlock:master, r=oli-obk
const_eval: allow function pointer signatures containing &mut T in const contexts potentially fixes #114994 We utilize a `TypeVisitor` here in order to more easily handle control flow. - In the event the typekind the Visitor sees is a function pointer, we skip over it - However, otherwise we do one of two things: - If we find a mutable reference, check it, then continue visiting types - If we find any other type, continue visiting types This means we will check if the function pointer _itself_ is mutable, but not if any of the types _within_ are.
This commit is contained in:
commit
139f63a6eb
@ -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,
|
||||
let mut visitor = LocalReturnTyVisitor { kind, checker: self };
|
||||
|
||||
// No constraints on lifetimes or constants, except potentially
|
||||
// constants' types, but `walk` will get to them as well.
|
||||
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
|
||||
};
|
||||
|
||||
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) {
|
||||
|
14
tests/ui/consts/const-eval/issue-114994-fail.rs
Normal file
14
tests/ui/consts/const-eval/issue-114994-fail.rs
Normal file
@ -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
tests/ui/consts/const-eval/issue-114994-fail.stderr
Normal file
21
tests/ui/consts/const-eval/issue-114994-fail.stderr
Normal file
@ -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
tests/ui/consts/const-eval/issue-114994.rs
Normal file
18
tests/ui/consts/const-eval/issue-114994.rs
Normal file
@ -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…
Reference in New Issue
Block a user