diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 245353c2e0756..2d0f346c6ab4b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1900,6 +1900,7 @@ pub struct BareFnTy { pub ext: Extern, pub generic_params: Vec, pub decl: P, + pub constness: Const, } /// The various kinds of type recognized by the compiler. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 425ef83b57af5..81d90492b7138 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -462,7 +462,8 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { vis.visit_mt(mt); } TyKind::BareFn(bft) => { - let BareFnTy { unsafety: _, ext: _, generic_params, decl } = bft.deref_mut(); + let BareFnTy { unsafety: _, ext: _, constness: _, generic_params, decl } = + bft.deref_mut(); generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 617cacee0e7f1..9daf227d5d5ef 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1296,7 +1296,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_constness(&mut self, c: Const) -> hir::Constness { + pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness { match c { Const::Yes(_) => hir::Constness::Const, Const::No => hir::Constness::NotConst, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a28d022c66139..8a45757fd0ebe 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1247,6 +1247,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { abi: this.lower_extern(f.ext), decl: this.lower_fn_decl(&f.decl, None, false, None), param_names: this.lower_fn_params_to_names(&f.decl), + constness: this.lower_constness(f.constness), })) }) }), diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 00d3db73766ac..1e01a50727d44 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -629,6 +629,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental"); gate_all!(const_trait_impl, "const trait impls are experimental"); gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); + gate_all!(const_fn_pointer, "`const fn` pointer type is unstable"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 9aa066370bb5b..d78f6cbca1c7a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1005,7 +1005,7 @@ impl<'a> State<'a> { self.pclose(); } ast::TyKind::BareFn(ref f) => { - self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params); + self.print_ty_fn(f.ext, f.unsafety, f.constness, &f.decl, None, &f.generic_params); } ast::TyKind::Path(None, ref path) => { self.print_path(path, false, 0); @@ -2812,6 +2812,7 @@ impl<'a> State<'a> { &mut self, ext: ast::Extern, unsafety: ast::Unsafe, + constness: ast::Const, decl: &ast::FnDecl, name: Option, generic_params: &[ast::GenericParam], @@ -2830,7 +2831,7 @@ impl<'a> State<'a> { }, span: rustc_span::DUMMY_SP, }; - let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }; + let header = ast::FnHeader { unsafety, constness, ext, ..ast::FnHeader::default() }; self.print_fn(decl, header, name, &generics); self.end(); } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e76e86f56510b..a8523c15edd37 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -683,6 +683,7 @@ fn gen_fn<'ll, 'tcx>( false, hir::Unsafety::Unsafe, Abi::Rust, + hir::Constness::NotConst, )); let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]); let llfn = cx.declare_fn(name, &fn_abi); @@ -716,6 +717,7 @@ fn get_rust_try_fn<'ll, 'tcx>( false, hir::Unsafety::Unsafe, Abi::Rust, + hir::Constness::NotConst, ))); let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( [i8p, i8p].iter().cloned(), @@ -723,6 +725,7 @@ fn get_rust_try_fn<'ll, 'tcx>( false, hir::Unsafety::Unsafe, Abi::Rust, + hir::Constness::NotConst, ))); let output = tcx.types.i32; let rust_try = gen_fn(cx, "__rust_try", vec![try_fn_ty, i8p, catch_fn_ty], output, codegen); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7ce110dcbfc48..1e096f0974a6d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -218,7 +218,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), } } - mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => { + mir::CastKind::Pointer( + PointerCast::UnsafeFnPointer + | PointerCast::NotConstFnPointer + | PointerCast::UnsafeNotConstFnPointer, + ) => { // This is a no-op at the LLVM level. operand.val } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 8a7f0517e732b..1930b0f8fa6fb 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -602,6 +602,9 @@ declare_features! ( /// Allows `#[instruction_set(_)]` attribute (active, isa_attribute, "1.48.0", Some(74727), None), + /// Allow const fn pointer + (active, const_fn_pointer, "1.49.0", Some(63997), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 636f67a77c890..ac5ace179d235 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2035,6 +2035,7 @@ pub struct BareFnTy<'hir> { pub generic_params: &'hir [GenericParam<'hir>], pub decl: &'hir FnDecl<'hir>, pub param_names: &'hir [Ident], + pub constness: Constness, } #[derive(Debug, HashStable_Generic)] @@ -2517,6 +2518,24 @@ pub enum Constness { NotConst, } +impl Constness { + pub fn prefix_str(&self) -> &'static str { + match self { + Self::Const => "const ", + Self::NotConst => "", + } + } +} + +impl fmt::Display for Constness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { + Self::Const => "const", + Self::NotConst => "", + }) + } +} + #[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)] pub struct FnHeader { pub unsafety: Unsafety, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 72011f04d9a77..3bc8514ee7929 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -404,6 +404,7 @@ impl<'a> State<'a> { self.print_ty_fn( f.abi, f.unsafety, + f.constness, &f.decl, None, &f.generic_params, @@ -2310,6 +2311,7 @@ impl<'a> State<'a> { &mut self, abi: Abi, unsafety: hir::Unsafety, + constness: hir::Constness, decl: &hir::FnDecl<'_>, name: Option, generic_params: &[hir::GenericParam<'_>], @@ -2327,12 +2329,7 @@ impl<'a> State<'a> { }; self.print_fn( decl, - hir::FnHeader { - unsafety, - abi, - constness: hir::Constness::NotConst, - asyncness: hir::IsAsync::NotAsync, - }, + hir::FnHeader { unsafety, abi, constness, asyncness: hir::IsAsync::NotAsync }, name, &generics, &Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited }, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 795c5a64d26b7..f5631806e8977 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -943,19 +943,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let (lt1, sig1) = get_lifetimes(sig1); let (lt2, sig2) = get_lifetimes(sig2); - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T let mut values = ( DiagnosticStyledString::normal("".to_string()), DiagnosticStyledString::normal("".to_string()), ); - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^ + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^^^^^ + values.0.push(sig1.constness.prefix_str(), sig1.constness != sig2.constness); + values.1.push(sig2.constness.prefix_str(), sig1.constness != sig2.constness); + + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^^^^^^ values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^^^^^ + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^^^^^^^^^^ if sig1.abi != abi::Abi::Rust { values.0.push(format!("extern {} ", sig1.abi), sig1.abi != sig2.abi); } @@ -963,19 +968,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { values.1.push(format!("extern {} ", sig2.abi), sig1.abi != sig2.abi); } - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^^^ + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^^^^^^^^ let lifetime_diff = lt1 != lt2; values.0.push(lt1, lifetime_diff); values.1.push(lt2, lifetime_diff); - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^ + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^^^ values.0.push_normal("fn("); values.1.push_normal("fn("); - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^ + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^^^^^ let len1 = sig1.inputs().len(); let len2 = sig2.inputs().len(); if len1 == len2 { @@ -1013,13 +1018,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { values.1.push("...", !sig1.c_variadic); } - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^ + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^ values.0.push_normal(")"); values.1.push_normal(")"); - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^^^ + // const unsafe extern "C" for<'a> fn(&'a T) -> &'a T + // ^^^^^^^^ let output1 = sig1.output(); let output2 = sig2.output(); let (x1, x2) = self.cmp(output1, output2); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index abd899e8db4d3..8691365414483 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2807,8 +2807,8 @@ impl ClashingExternDeclarations { let a_sig = a_poly_sig.skip_binder(); let b_sig = b_poly_sig.skip_binder(); - (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) - == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) + (a_sig.abi, a_sig.unsafety, a_sig.c_variadic, a_sig.constness) + == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic, b_sig.constness) && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { structurally_same_type_impl(seen_types, cx, a, b, ckind) }) diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 89d0e13955122..5c702102679f0 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -14,6 +14,12 @@ pub enum PointerCast { /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, + // Go from a const fn pointer to a not const fn pointer + NotConstFnPointer, + + // Go from a safe const fn pointer to a not const unsafe fn pointer + UnsafeNotConstFnPointer, + /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. /// It cannot convert a closure that requires unsafe. ClosureFnPointer(hir::Unsafety), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e67a76f0111a0..a1dfdb8d59579 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2065,6 +2065,23 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) } + pub fn const_to_normal_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { + assert_eq!(sig.constness(), hir::Constness::Const); + self.mk_fn_ptr( + sig.map_bound(|sig| ty::FnSig { constness: hir::Constness::NotConst, ..sig }), + ) + } + + pub fn const_safe_to_normal_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { + assert_eq!(sig.unsafety(), hir::Unsafety::Normal); + assert_eq!(sig.constness(), hir::Constness::Const); + self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { + unsafety: hir::Unsafety::Unsafe, + constness: hir::Constness::NotConst, + ..sig + })) + } + /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. @@ -2082,10 +2099,21 @@ impl<'tcx> TyCtxt<'tcx> { ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()), _ => bug!(), }; - self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi::Abi::Rust) + self.mk_fn_sig( + params_iter, + s.output(), + s.c_variadic, + unsafety, + abi::Abi::Rust, + hir::Constness::NotConst, + ) }) } + pub fn signature_not_const_fn(self, sig: PolyFnSig<'tcx>) -> PolyFnSig<'tcx> { + sig.map_bound(|s| ty::FnSig { constness: hir::Constness::NotConst, ..s }) + } + /// Same a `self.mk_region(kind)`, but avoids accessing the interners if /// `*r == kind`. #[inline] @@ -2278,6 +2306,13 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(FnPtr(fty)) } + #[inline] + pub fn mk_not_const_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { + let mut not_const = fty.skip_binder(); + not_const.constness = hir::Constness::NotConst; + self.mk_ty(FnPtr(ty::Binder::dummy(not_const))) + } + #[inline] pub fn mk_dynamic( self, @@ -2459,6 +2494,7 @@ impl<'tcx> TyCtxt<'tcx> { c_variadic: bool, unsafety: hir::Unsafety, abi: abi::Abi, + constness: hir::Constness, ) -> , ty::FnSig<'tcx>>>::Output where I: Iterator, ty::FnSig<'tcx>>>, @@ -2468,6 +2504,7 @@ impl<'tcx> TyCtxt<'tcx> { c_variadic, unsafety, abi, + constness, }) } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 82d698b37ab1d..fc12b33f6d496 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -36,6 +36,7 @@ pub enum TypeError<'tcx> { Mismatch, UnsafetyMismatch(ExpectedFound), AbiMismatch(ExpectedFound), + ConstnessMismatch(ExpectedFound), Mutability, TupleSize(ExpectedFound), FixedArraySize(ExpectedFound), @@ -109,6 +110,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { AbiMismatch(values) => { write!(f, "expected {} fn, found {} fn", values.expected, values.found) } + ConstnessMismatch(values) => { + write!(f, "expected {} fn, found {} fn", values.expected, values.found) + } Mutability => write!(f, "types differ in mutability"), TupleSize(values) => write!( f, @@ -198,8 +202,8 @@ impl<'tcx> TypeError<'tcx> { use self::TypeError::*; match self { CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) - | FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) - | VariadicMismatch(_) | TargetFeatureCast(_) => false, + | ConstnessMismatch(_) | FixedArraySize(_) | Sorts(_) | IntMismatch(_) + | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | TupleSize(_) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index fd24de1529d37..450d6b46b0d87 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2339,6 +2339,7 @@ impl<'tcx> ty::Instance<'tcx> { let sig = substs.as_closure().sig(); let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); + sig.map_bound(|sig| { tcx.mk_fn_sig( iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), @@ -2346,6 +2347,7 @@ impl<'tcx> ty::Instance<'tcx> { sig.c_variadic, sig.unsafety, sig.abi, + hir::Constness::NotConst, ) }) } @@ -2373,6 +2375,7 @@ impl<'tcx> ty::Instance<'tcx> { false, hir::Unsafety::Normal, rustc_target::spec::abi::Abi::Rust, + hir::Constness::NotConst, ) }) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 68c36642c88bc..f7ad46e075863 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1980,6 +1980,8 @@ define_print_and_forward_display! { ty::FnSig<'tcx> { p!(write("{}", self.unsafety.prefix_str())); + p!(write("{}", self.constness.prefix_str())); + if self.abi != Abi::Rust { p!(write("extern {} ", self.abi)); diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index c4df0bba726cb..14ca5ade90966 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -165,6 +165,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { } let unsafety = relation.relate(a.unsafety, b.unsafety)?; let abi = relation.relate(a.abi, b.abi)?; + let constness = relation.relate(a.constness, b.constness)?; if a.inputs().len() != b.inputs().len() { return Err(TypeError::ArgCount); @@ -189,6 +190,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { c_variadic: a.c_variadic, unsafety, abi, + constness, }) } } @@ -217,6 +219,20 @@ impl<'tcx> Relate<'tcx> for abi::Abi { } } +impl<'tcx> Relate<'tcx> for ast::Constness { + fn relate>( + relation: &mut R, + a: ast::Constness, + b: ast::Constness, + ) -> RelateResult<'tcx, ast::Constness> { + if a == b { + Ok(a) + } else { + Err(TypeError::ConstnessMismatch(expected_found(relation, a, b))) + } + } +} + impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> { fn relate>( relation: &mut R, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 597ceac9386a0..29bbf6f0c8cd5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -648,6 +648,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { c_variadic: self.c_variadic, unsafety: self.unsafety, abi: self.abi, + constness: self.constness, }) } } @@ -670,6 +671,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Mismatch => Mismatch, UnsafetyMismatch(x) => UnsafetyMismatch(x), AbiMismatch(x) => AbiMismatch(x), + ConstnessMismatch(x) => ConstnessMismatch(x), Mutability => Mutability, TupleSize(x) => TupleSize(x), FixedArraySize(x) => FixedArraySize(x), diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 1af56972ad083..5d629d22440d2 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1127,6 +1127,7 @@ pub struct FnSig<'tcx> { pub c_variadic: bool, pub unsafety: hir::Unsafety, pub abi: abi::Abi, + pub constness: hir::Constness, } impl<'tcx> FnSig<'tcx> { @@ -1146,6 +1147,7 @@ impl<'tcx> FnSig<'tcx> { c_variadic: false, unsafety: hir::Unsafety::Normal, abi: abi::Abi::Rust, + constness: hir::Constness::NotConst, } } } @@ -1177,6 +1179,9 @@ impl<'tcx> PolyFnSig<'tcx> { pub fn abi(&self) -> abi::Abi { self.skip_binder().abi } + pub fn constness(&self) -> hir::Constness { + self.skip_binder().constness + } } pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder>>; @@ -2076,6 +2081,7 @@ impl<'tcx> TyS<'tcx> { FnPtr(f) => *f, Error(_) => { // ignore errors (#54954) + ty::Binder::dummy(FnSig::fake()) } Closure(..) => bug!( diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 4fc1c570e4602..691fa96ab4df9 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -26,10 +26,7 @@ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; -use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPredicate, Ty, - TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, -}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, Binder}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -2051,7 +2048,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // function definition. When we extract the // signature, it comes from the `fn_sig` query, // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); + let mut fn_sig = self.normalize(fn_sig, location); + + if let ty::FnPtr(pol_sig) = ty.kind() { + let mut sig = fn_sig.skip_binder(); + sig.constness = pol_sig.constness(); + sig.unsafety = pol_sig.unsafety(); + fn_sig = Binder::bind(sig); + } let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); @@ -2125,6 +2129,64 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + CastKind::Pointer(PointerCast::NotConstFnPointer) => { + let fn_sig = op.ty(body, tcx).fn_sig(tcx); + + // The type that we see in the fcx is like + // `foo::<'a, 'b>`, where `foo` is the path to a + // function definition. When we extract the + // signature, it comes from the `fn_sig` query, + // and hence may contain unnormalized results. + let fn_sig = self.normalize(fn_sig, location); + + let ty_fn_ptr_from = tcx.const_to_normal_fn_ty(fn_sig); + + if let Err(terr) = self.eq_types( + ty_fn_ptr_from, + ty, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + ty_fn_ptr_from, + ty, + terr + ); + } + } + + CastKind::Pointer(PointerCast::UnsafeNotConstFnPointer) => { + let fn_sig = op.ty(body, tcx).fn_sig(tcx); + + // The type that we see in the fcx is like + // `foo::<'a, 'b>`, where `foo` is the path to a + // function definition. When we extract the + // signature, it comes from the `fn_sig` query, + // and hence may contain unnormalized results. + let fn_sig = self.normalize(fn_sig, location); + + let ty_fn_ptr_from = tcx.const_safe_to_normal_unsafe_fn_ty(fn_sig); + + if let Err(terr) = self.eq_types( + ty_fn_ptr_from, + ty, + location.to_locations(), + ConstraintCategory::Cast, + ) { + span_mirbug!( + self, + rvalue, + "equating {:?} with {:?} yields {:?}", + ty_fn_ptr_from, + ty, + terr + ); + } + } + CastKind::Pointer(PointerCast::Unsize) => { let &ty = ty; let trait_ref = ty::TraitRef { diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index 0e16b0caefafa..dc37b4d294247 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -85,6 +85,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + Pointer(PointerCast::NotConstFnPointer) => { + let src = self.read_immediate(src)?; + match cast_ty.kind() { + ty::FnPtr(_) => { + // No change to value + self.write_immediate(*src, dest)?; + } + _ => span_bug!(self.cur_span(), "const fn to fn cast on {:?}", cast_ty), + } + } + + Pointer(PointerCast::UnsafeNotConstFnPointer) => { + let src = self.read_immediate(src)?; + match cast_ty.kind() { + ty::FnPtr(_) => { + // No change to value + self.write_immediate(*src, dest)?; + } + _ => span_bug!(self.cur_span(), "const fn to unsafe fn cast on {:?}", cast_ty), + } + } + Pointer(PointerCast::ClosureFnPointer(_)) => { // The src operand does not matter, just its type match *src.layout.ty.kind() { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 587b5b381288a..1ddb59d28387d 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -557,6 +557,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { CastKind::Pointer( PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) + | PointerCast::NotConstFnPointer + | PointerCast::UnsafeNotConstFnPointer | PointerCast::ReifyFnPointer, ), _, @@ -745,7 +747,14 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { let (mut callee, substs) = match *fn_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), - ty::FnPtr(_) => { + ty::FnPtr(fn_sig) => { + // At this point, we are calling a function by raw pointer because + // we know that it is const + if self.ccx.tcx.features().const_fn_pointer + && fn_sig.constness() == hir::Constness::Const + { + return; + } self.check_op(ops::FnCallIndirect); return; } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index d42a786a18fe9..9cccb2d2b5e39 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -331,12 +331,12 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?; let whole_span = lo.to(self.prev_token.span); if let ast::Const::Yes(span) = constness { - self.error_fn_ptr_bad_qualifier(whole_span, span, "const"); + self.sess.gated_spans.gate(sym::const_fn_pointer, span); } if let ast::Async::Yes { span, .. } = asyncness { self.error_fn_ptr_bad_qualifier(whole_span, span, "async"); } - Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl }))) + Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, constness }))) } /// Emit an error for the given bad function pointer qualifier. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 28fef65da070a..cbe7a534828bb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -357,6 +357,7 @@ symbols! { const_fn, const_fn_floating_point_arithmetic, const_fn_fn_ptr_basics, + const_fn_pointer, const_fn_transmute, const_fn_union, const_generics, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 0584c56c9cb66..d74fa9e0c31e8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1159,6 +1159,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { false, hir::Unsafety::Normal, abi::Abi::Rust, + hir::Constness::NotConst, ) } else { tcx.mk_fn_sig( @@ -1167,6 +1168,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { false, hir::Unsafety::Normal, abi::Abi::Rust, + hir::Constness::NotConst, ) }; ty::Binder::bind(sig).to_string() diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 170ca2ce744cd..e32c287583115 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2019,6 +2019,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_fn_ptr(self.ty_of_fn( bf.unsafety, bf.abi, + bf.constness, &bf.decl, &hir::Generics::empty(), None, @@ -2157,6 +2158,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, unsafety: hir::Unsafety, abi: abi::Abi, + constness: hir::Constness, decl: &hir::FnDecl<'_>, generics: &hir::Generics<'_>, ident_span: Option, @@ -2183,8 +2185,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("ty_of_fn: output_ty={:?}", output_ty); - let bare_fn_ty = - ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); + let bare_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( + input_tys, + output_ty, + decl.c_variadic, + unsafety, + abi, + constness, + )); if !self.allow_ty_infer() { // We always collect the spans for placeholder types when evaluating `fn`s, but we diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 740783aeb9d1e..919aed44a3885 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -397,6 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, hir::Unsafety::Normal, abi::Abi::Rust, + hir::Constness::NotConst, )), None, ) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index d319ac2cba654..3481a865b46e2 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -85,6 +85,7 @@ pub(super) fn check_fn<'a, 'tcx>( fn_sig.c_variadic, fn_sig.unsafety, fn_sig.abi, + fn_sig.constness, ); let span = body.value.span; diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 8898a5452282c..14ca0ee380896 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -125,6 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sig.c_variadic, sig.unsafety, sig.abi, + sig.constness, ) }); @@ -288,6 +289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, hir::Unsafety::Normal, Abi::Rust, + hir::Constness::NotConst, ); debug!("deduce_sig_from_projection: sig={:?}", sig); @@ -403,6 +405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, + hir::Constness::NotConst, )); // `deduce_expectations_from_expected_type` introduces @@ -582,6 +585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, + hir::Constness::NotConst, )); debug!("supplied_sig_of_closure: result={:?}", result); @@ -717,6 +721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, + hir::Constness::NotConst, )); debug!("supplied_sig_of_closure: result={:?}", result); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 4addee1a4c976..782d0c5629735 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -218,7 +218,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } ty::FnPtr(a_f) => { // We permit coercion of fn pointers to drop the - // unsafe qualifier. + // unsafe or const qualifier. self.coerce_from_fn_pointer(a, a_f, b) } ty::Closure(_, substs_a) => { @@ -660,26 +660,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(coercion) } - fn coerce_from_safe_fn( + fn coerce_from_const_safe_fn( &self, a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, to_unsafe: F, - normal: G, + to_unconst: G, + to_unsafe_unconst: H, + normal: I, ) -> CoerceResult<'tcx> where F: FnOnce(Ty<'tcx>) -> Vec>, G: FnOnce(Ty<'tcx>) -> Vec>, + H: FnOnce(Ty<'tcx>) -> Vec>, + I: FnOnce(Ty<'tcx>) -> Vec>, { if let ty::FnPtr(fn_ty_b) = b.kind() { - if let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) = - (fn_ty_a.unsafety(), fn_ty_b.unsafety()) - { - let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify_and(unsafe_a, b, to_unsafe); + let a_unsafety = fn_ty_a.unsafety(); + let b_unsafety = fn_ty_b.unsafety(); + let a_constness = fn_ty_a.constness(); + let b_constness = fn_ty_b.constness(); + + match (a_unsafety, b_unsafety) { + (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { + return match (a_constness, b_constness) { + (hir::Constness::Const, hir::Constness::NotConst) => { + let unconst_unsafe_a = + self.tcx.const_safe_to_normal_unsafe_fn_ty(fn_ty_a); + self.unify_and(unconst_unsafe_a, b, to_unsafe_unconst) + } + _ => { + let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); + self.unify_and(unsafe_a, b, to_unsafe) + } + }; + } + _ => { + if (a_constness, b_constness) + == (hir::Constness::Const, hir::Constness::NotConst) + { + let unconst_a = self.tcx.const_to_normal_fn_ty(fn_ty_a); + return self.unify_and(unconst_a, b, to_unconst); + } + } } } + self.unify_and(a, b, normal) } @@ -696,13 +723,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - self.coerce_from_safe_fn( + let InferOk { value, obligations } = self.coerce_from_const_safe_fn( a, fn_ty_a, b, simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)), + simple(Adjust::Pointer(PointerCast::NotConstFnPointer)), + simple(Adjust::Pointer(PointerCast::UnsafeNotConstFnPointer)), identity, - ) + )?; + + Ok(InferOk { value, obligations }) } fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { @@ -733,7 +764,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig); let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig); - let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( + + let InferOk { value, obligations: o2 } = self.coerce_from_const_safe_fn( a_fn_pointer, a_sig, b, @@ -749,10 +781,35 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }, ] }, + |unconst_ty| { + vec![ + Adjustment { + kind: Adjust::Pointer(PointerCast::ReifyFnPointer), + target: a_fn_pointer, + }, + Adjustment { + kind: Adjust::Pointer(PointerCast::NotConstFnPointer), + target: unconst_ty, + }, + ] + }, + |unsafe_unconst_ty| { + vec![ + Adjustment { + kind: Adjust::Pointer(PointerCast::ReifyFnPointer), + target: a_fn_pointer, + }, + Adjustment { + kind: Adjust::Pointer(PointerCast::UnsafeNotConstFnPointer), + target: unsafe_unconst_ty, + }, + ] + }, simple(Adjust::Pointer(PointerCast::ReifyFnPointer)), )?; obligations.extend(o2); + Ok(InferOk { value, obligations }) } _ => self.unify_and(a, b, identity), @@ -895,6 +952,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let prev_ty = self.resolve_vars_with_obligations(prev_ty); let new_ty = self.resolve_vars_with_obligations(new_ty); + let mut prev_drop_const = false; + let mut new_drop_const = false; debug!( "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", prev_ty, @@ -916,7 +975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, None) } else { match (&prev_ty.kind(), &new_ty.kind()) { - (&ty::FnDef(..), &ty::FnDef(..)) => { + (&ty::FnDef(..) | &ty::FnPtr(..), &ty::FnDef(..) | &ty::FnPtr(..)) => { // Don't reify if the function types have a LUB, i.e., they // are the same function and their parameters have a LUB. match self @@ -925,7 +984,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We have a LUB of prev_ty and new_ty, just return it. Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), Err(_) => { - (Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx))) + let mut prev_sig = prev_ty.fn_sig(self.tcx); + let mut new_sig = new_ty.fn_sig(self.tcx); + if prev_sig.constness() != new_sig.constness() { + if prev_sig.constness() == hir::Constness::Const { + prev_sig = self.tcx.signature_not_const_fn(prev_sig); + prev_drop_const = true; + } else { + new_sig = self.tcx.signature_not_const_fn(prev_sig); + new_drop_const = true; + } + } + if prev_sig.unsafety() != new_sig.unsafety() { + prev_sig = prev_sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }); + new_sig = new_sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }); + } + (Some(prev_sig), Some(new_sig)) } } } @@ -970,22 +1044,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = self.tcx.mk_fn_ptr(sig); let prev_adjustment = match prev_ty.kind() { - ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())), - ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + ty::Closure(..) => { + Some(Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety()))) + } + ty::FnDef(..) => Some(Adjust::Pointer(PointerCast::ReifyFnPointer)), + ty::FnPtr(..) => { + if prev_drop_const { + if a_sig.unsafety() != b_sig.unsafety() { + Some(Adjust::Pointer(PointerCast::UnsafeNotConstFnPointer)) + } else { + Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) + } + } else { + None + } + } _ => unreachable!(), }; let next_adjustment = match new_ty.kind() { - ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), - ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + ty::Closure(..) => { + Some(Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety()))) + } + ty::FnDef(..) => Some(Adjust::Pointer(PointerCast::ReifyFnPointer)), + ty::FnPtr(..) => { + if new_drop_const { + if a_sig.unsafety() != b_sig.unsafety() { + Some(Adjust::Pointer(PointerCast::UnsafeNotConstFnPointer)) + } else { + Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) + } + } else { + None + } + } _ => unreachable!(), }; - for expr in exprs.iter().map(|e| e.as_coercion_site()) { + if prev_adjustment.is_some() { + for expr in exprs.iter().map(|e| e.as_coercion_site()) { + self.apply_adjustments( + expr, + vec![Adjustment { + kind: prev_adjustment.clone().unwrap().clone(), + target: fn_ptr, + }], + ); + } + } + if next_adjustment.is_some() { self.apply_adjustments( - expr, - vec![Adjustment { kind: prev_adjustment.clone(), target: fn_ptr }], + new, + vec![Adjustment { kind: next_adjustment.unwrap(), target: fn_ptr }], ); } - self.apply_adjustments(new, vec![Adjustment { kind: next_adjustment, target: fn_ptr }]); return Ok(fn_ptr); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 017b0abd1d607..c447c300b7512 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -16,7 +16,7 @@ use rustc_hir::{ExprKind, GenericArg, Node, QPath}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::{InferOk, InferResult}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{ self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, @@ -302,6 +302,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ]) => { // A reborrow has no effect before a dereference. } + (&[Adjustment { kind: Adjust::Pointer(PointerCast::ReifyFnPointer), .. }], + &[Adjustment { kind: Adjust::Pointer(PointerCast::NotConstFnPointer), .. }]) => { + entry.get_mut().push(adj[0].clone()); + return; + } // FIXME: currently we never try to compose autoderefs // and ReifyFnPointer/UnsafeFnPointer, but we could. _ => diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 2ee867c2dd648..436c23813e160 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -25,6 +25,7 @@ fn equate_intrinsic_type<'tcx>( n_tps: usize, abi: Abi, safety: hir::Unsafety, + constness: hir::Constness, inputs: Vec>, output: Ty<'tcx>, ) { @@ -59,6 +60,7 @@ fn equate_intrinsic_type<'tcx>( false, safety, abi, + constness, ))); let cause = ObligationCause::new(it.span, it.hir_id, ObligationCauseCode::IntrinsicType); require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty); @@ -334,6 +336,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { false, hir::Unsafety::Normal, Abi::Rust, + hir::Constness::NotConst, )); let catch_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( [mut_u8, mut_u8].iter().cloned(), @@ -341,6 +344,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { false, hir::Unsafety::Normal, Abi::Rust, + hir::Constness::NotConst, )); ( 0, @@ -376,7 +380,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { }; (n_tps, inputs, output, unsafety) }; - equate_intrinsic_type(tcx, it, def_id, n_tps, Abi::RustIntrinsic, unsafety, inputs, output) + equate_intrinsic_type( + tcx, + it, + def_id, + n_tps, + Abi::RustIntrinsic, + unsafety, + hir::Constness::NotConst, + inputs, + output, + ) } /// Type-check `extern "platform-intrinsic" { ... }` functions. @@ -469,6 +483,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) n_tps, Abi::PlatformIntrinsic, hir::Unsafety::Unsafe, + hir::Constness::NotConst, inputs, output, ) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 24ffe944128c9..302efe3558161 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -498,6 +498,7 @@ fn typeck_with_fallback<'tcx>( &fcx, header.unsafety, header.abi, + header.constness, decl, &hir::Generics::empty(), None, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b64a1ce7c3082..c4d49f87b6820 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1556,6 +1556,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { &icx, sig.header.unsafety, sig.header.abi, + sig.header.constness, &sig.decl, &generics, Some(ident.span), @@ -1568,9 +1569,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { ident, generics, .. - }) => { - AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl, &generics, Some(ident.span)) - } + }) => AstConv::ty_of_fn( + &icx, + header.unsafety, + header.abi, + header.constness, + decl, + &generics, + Some(ident.span), + ), ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(ref fn_decl, _, _), @@ -1591,6 +1598,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { false, hir::Unsafety::Normal, abi::Abi::Rust, + hir::Constness::NotConst, )) } @@ -2263,6 +2271,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( &ItemCtxt::new(tcx, def_id), unsafety, abi, + hir::Constness::NotConst, decl, &hir::Generics::empty(), Some(ident.span), diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 7efda54fbe035..5e19ed30e8255 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -236,6 +236,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { false, hir::Unsafety::Normal, Abi::Rust, + hir::Constness::NotConst, ))); require_same_types( @@ -323,6 +324,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) { false, hir::Unsafety::Normal, Abi::Rust, + hir::Constness::NotConst, ))); require_same_types( diff --git a/src/test/ui/consts/const_fn_pointer.rs b/src/test/ui/consts/const_fn_pointer.rs new file mode 100644 index 0000000000000..2a058896468fa --- /dev/null +++ b/src/test/ui/consts/const_fn_pointer.rs @@ -0,0 +1,27 @@ +// run-pass +#![allow(dead_code)] +#![feature(const_fn_pointer)] +#![feature(const_fn)] + + +const fn foo() {} +const FOO: const fn() = foo; +const fn bar() { FOO() } +const fn baz(x: const fn()) { x() } +const fn bazz() { baz(FOO) } + +trait Bar { const F: const fn(Self) -> Self; } + +const fn map_i32(x: i32) -> i32 { x * 2 } +impl Bar for i32 { const F: const fn(Self) -> Self = map_i32; } +const fn map_u32(x: u32) -> u32 { x * 3 } +impl Bar for u32 { const F: const fn(Self) -> Self = map_u32; } + +const fn map_smth(v: T) -> T { + ::F(v) +} + +fn main() { + const VAR: i32 = map_smth(2); + assert_eq!(VAR, 4); +} diff --git a/src/test/ui/consts/const_fn_ptr_cast.rs b/src/test/ui/consts/const_fn_ptr_cast.rs new file mode 100644 index 0000000000000..5620ca1b28e3c --- /dev/null +++ b/src/test/ui/consts/const_fn_ptr_cast.rs @@ -0,0 +1,25 @@ +#![feature(const_fn)] +#![feature(const_fn_pointer)] +#[allow(dead_code)] + +const fn const_fn() { } +fn not_const_fn() { } +unsafe fn unsafe_fn() { } +const unsafe fn const_unsafe_fn() { } + +const _: fn() = const_fn; +const _: unsafe fn() = const_fn; +const _: const unsafe fn() = const_fn; + +const _: const fn() = not_const_fn; +//~^ ERROR mismatched types + +const _: const fn() = unsafe_fn; +//~^ ERROR mismatched types + +const _: const unsafe fn() = unsafe_fn; +//~^ ERROR mismatched types + +const _: unsafe fn() = const_unsafe_fn; + +fn main() { } diff --git a/src/test/ui/consts/const_fn_ptr_cast.stderr b/src/test/ui/consts/const_fn_ptr_cast.stderr new file mode 100644 index 0000000000000..efb3c050ee8e0 --- /dev/null +++ b/src/test/ui/consts/const_fn_ptr_cast.stderr @@ -0,0 +1,30 @@ +error[E0308]: mismatched types + --> $DIR/const_fn_ptr_cast.rs:14:23 + | +LL | const _: const fn() = not_const_fn; + | ^^^^^^^^^^^^ expected const fn, found fn + | + = note: expected fn pointer `const fn()` + found fn item `fn() {not_const_fn}` + +error[E0308]: mismatched types + --> $DIR/const_fn_ptr_cast.rs:17:23 + | +LL | const _: const fn() = unsafe_fn; + | ^^^^^^^^^ expected normal fn, found unsafe fn + | + = note: expected fn pointer `const fn()` + found fn item `unsafe fn() {unsafe_fn}` + +error[E0308]: mismatched types + --> $DIR/const_fn_ptr_cast.rs:20:30 + | +LL | const _: const unsafe fn() = unsafe_fn; + | ^^^^^^^^^ expected const fn, found fn + | + = note: expected fn pointer `const unsafe fn()` + found fn item `unsafe fn() {unsafe_fn}` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_pointer.rs b/src/test/ui/feature-gates/feature-gate-const_fn_pointer.rs new file mode 100644 index 0000000000000..020b3bc7c0ee9 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_fn_pointer.rs @@ -0,0 +1,19 @@ +const fn foo() { } +const x: const fn() = foo; +//~^ ERROR `const fn` pointer type is unstable + +static y: const fn() = foo; +//~^ ERROR `const fn` pointer type is unstable + +const fn bar(f: const fn()) { f() } +//~^ ERROR `const fn` pointer type is unstable + +struct Foo { field: const fn() } +//~^ ERROR `const fn` pointer type is unstable + +fn main() { + let local: fn() = foo; + let local2: const fn() = foo; + //~^ ERROR `const fn` pointer type is unstable + let local3 = foo; +} diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_pointer.stderr b/src/test/ui/feature-gates/feature-gate-const_fn_pointer.stderr new file mode 100644 index 0000000000000..699be8190a132 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_fn_pointer.stderr @@ -0,0 +1,48 @@ +error[E0658]: `const fn` pointer type is unstable + --> $DIR/feature-gate-const_fn_pointer.rs:2:10 + | +LL | const x: const fn() = foo; + | ^^^^^ + | + = note: see issue #63997 for more information + = help: add `#![feature(const_fn_pointer)]` to the crate attributes to enable + +error[E0658]: `const fn` pointer type is unstable + --> $DIR/feature-gate-const_fn_pointer.rs:5:11 + | +LL | static y: const fn() = foo; + | ^^^^^ + | + = note: see issue #63997 for more information + = help: add `#![feature(const_fn_pointer)]` to the crate attributes to enable + +error[E0658]: `const fn` pointer type is unstable + --> $DIR/feature-gate-const_fn_pointer.rs:8:17 + | +LL | const fn bar(f: const fn()) { f() } + | ^^^^^ + | + = note: see issue #63997 for more information + = help: add `#![feature(const_fn_pointer)]` to the crate attributes to enable + +error[E0658]: `const fn` pointer type is unstable + --> $DIR/feature-gate-const_fn_pointer.rs:11:21 + | +LL | struct Foo { field: const fn() } + | ^^^^^ + | + = note: see issue #63997 for more information + = help: add `#![feature(const_fn_pointer)]` to the crate attributes to enable + +error[E0658]: `const fn` pointer type is unstable + --> $DIR/feature-gate-const_fn_pointer.rs:16:15 + | +LL | let local2: const fn() = foo; + | ^^^^^ + | + = note: see issue #63997 for more information + = help: add `#![feature(const_fn_pointer)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/bad-fn-ptr-qualifier.fixed b/src/test/ui/parser/bad-fn-ptr-qualifier.fixed index ad8e718cf88a5..80b9814704765 100644 --- a/src/test/ui/parser/bad-fn-ptr-qualifier.fixed +++ b/src/test/ui/parser/bad-fn-ptr-qualifier.fixed @@ -2,25 +2,13 @@ // edition:2018 // Most of items are taken from ./recover-const-async-fn-ptr.rs but this is able to apply rustfix. -pub type T0 = fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type T1 = extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type T2 = unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const` pub type T3 = fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type T4 = extern fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type T5 = unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` -pub type T6 = unsafe extern "C" fn(); -//~^ ERROR an `fn` pointer type cannot be `const` -//~| ERROR an `fn` pointer type cannot be `async` -pub type FTT0 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type FTT1 = for<'a> extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type FTT2 = for<'a> unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const` pub type FTT3 = for<'a> fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type FTT4 = for<'a> extern fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type FTT5 = for<'a> unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `async` -pub type FTT6 = for<'a> unsafe extern "C" fn(); -//~^ ERROR an `fn` pointer type cannot be `const` -//~| ERROR an `fn` pointer type cannot be `async` fn main() {} diff --git a/src/test/ui/parser/bad-fn-ptr-qualifier.rs b/src/test/ui/parser/bad-fn-ptr-qualifier.rs index c04813dadff7b..d1ff418fcd81b 100644 --- a/src/test/ui/parser/bad-fn-ptr-qualifier.rs +++ b/src/test/ui/parser/bad-fn-ptr-qualifier.rs @@ -2,25 +2,13 @@ // edition:2018 // Most of items are taken from ./recover-const-async-fn-ptr.rs but this is able to apply rustfix. -pub type T0 = const fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type T1 = const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type T2 = const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const` pub type T3 = async fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type T4 = async extern fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type T5 = async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` -pub type T6 = const async unsafe extern "C" fn(); -//~^ ERROR an `fn` pointer type cannot be `const` -//~| ERROR an `fn` pointer type cannot be `async` -pub type FTT0 = for<'a> const fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type FTT1 = for<'a> const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -pub type FTT2 = for<'a> const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const` pub type FTT3 = for<'a> async fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type FTT4 = for<'a> async extern fn(); //~ ERROR an `fn` pointer type cannot be `async` pub type FTT5 = for<'a> async unsafe extern "C" fn(); //~^ ERROR an `fn` pointer type cannot be `async` -pub type FTT6 = for<'a> const async unsafe extern "C" fn(); -//~^ ERROR an `fn` pointer type cannot be `const` -//~| ERROR an `fn` pointer type cannot be `async` fn main() {} diff --git a/src/test/ui/parser/bad-fn-ptr-qualifier.stderr b/src/test/ui/parser/bad-fn-ptr-qualifier.stderr index 265e31329ca54..737aaa6007718 100644 --- a/src/test/ui/parser/bad-fn-ptr-qualifier.stderr +++ b/src/test/ui/parser/bad-fn-ptr-qualifier.stderr @@ -1,32 +1,5 @@ -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:5:15 - | -LL | pub type T0 = const fn(); - | -----^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:6:15 - | -LL | pub type T1 = const extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:7:15 - | -LL | pub type T2 = const unsafe extern fn(); - | -----^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:8:15 + --> $DIR/bad-fn-ptr-qualifier.rs:5:15 | LL | pub type T3 = async fn(); | -----^^^^^ @@ -35,7 +8,7 @@ LL | pub type T3 = async fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:9:15 + --> $DIR/bad-fn-ptr-qualifier.rs:6:15 | LL | pub type T4 = async extern fn(); | -----^^^^^^^^^^^^ @@ -44,7 +17,7 @@ LL | pub type T4 = async extern fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:10:15 + --> $DIR/bad-fn-ptr-qualifier.rs:7:15 | LL | pub type T5 = async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,53 +25,8 @@ LL | pub type T5 = async unsafe extern "C" fn(); | `async` because of this | help: remove the `async` qualifier -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:11:15 - | -LL | pub type T6 = const async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:11:15 - | -LL | pub type T6 = const async unsafe extern "C" fn(); - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | help: remove the `async` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:15:17 - | -LL | pub type FTT0 = for<'a> const fn(); - | ^^^^^^^^-----^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:16:17 - | -LL | pub type FTT1 = for<'a> const extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:17:17 - | -LL | pub type FTT2 = for<'a> const unsafe extern fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:18:17 + --> $DIR/bad-fn-ptr-qualifier.rs:9:17 | LL | pub type FTT3 = for<'a> async fn(); | ^^^^^^^^-----^^^^^ @@ -107,7 +35,7 @@ LL | pub type FTT3 = for<'a> async fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:19:17 + --> $DIR/bad-fn-ptr-qualifier.rs:10:17 | LL | pub type FTT4 = for<'a> async extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^ @@ -116,7 +44,7 @@ LL | pub type FTT4 = for<'a> async extern fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:20:17 + --> $DIR/bad-fn-ptr-qualifier.rs:11:17 | LL | pub type FTT5 = for<'a> async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,23 +52,5 @@ LL | pub type FTT5 = for<'a> async unsafe extern "C" fn(); | `async` because of this | help: remove the `async` qualifier -error: an `fn` pointer type cannot be `const` - --> $DIR/bad-fn-ptr-qualifier.rs:22:17 - | -LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `async` - --> $DIR/bad-fn-ptr-qualifier.rs:22:17 - | -LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | help: remove the `async` qualifier - -error: aborting due to 16 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/recover-const-async-fn-ptr.rs b/src/test/ui/parser/recover-const-async-fn-ptr.rs index 25af8772cedbd..62a21ff9ac3a8 100644 --- a/src/test/ui/parser/recover-const-async-fn-ptr.rs +++ b/src/test/ui/parser/recover-const-async-fn-ptr.rs @@ -1,24 +1,12 @@ // edition:2018 -type T0 = const fn(); //~ ERROR an `fn` pointer type cannot be `const` -type T1 = const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -type T2 = const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const` type T3 = async fn(); //~ ERROR an `fn` pointer type cannot be `async` type T4 = async extern fn(); //~ ERROR an `fn` pointer type cannot be `async` type T5 = async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` -type T6 = const async unsafe extern "C" fn(); -//~^ ERROR an `fn` pointer type cannot be `const` -//~| ERROR an `fn` pointer type cannot be `async` -type FT0 = for<'a> const fn(); //~ ERROR an `fn` pointer type cannot be `const` -type FT1 = for<'a> const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const` -type FT2 = for<'a> const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const` type FT3 = for<'a> async fn(); //~ ERROR an `fn` pointer type cannot be `async` type FT4 = for<'a> async extern fn(); //~ ERROR an `fn` pointer type cannot be `async` type FT5 = for<'a> async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async` -type FT6 = for<'a> const async unsafe extern "C" fn(); -//~^ ERROR an `fn` pointer type cannot be `const` -//~| ERROR an `fn` pointer type cannot be `async` fn main() { let _recovery_witness: () = 0; //~ ERROR mismatched types diff --git a/src/test/ui/parser/recover-const-async-fn-ptr.stderr b/src/test/ui/parser/recover-const-async-fn-ptr.stderr index 7012096b64450..e5873d3aab083 100644 --- a/src/test/ui/parser/recover-const-async-fn-ptr.stderr +++ b/src/test/ui/parser/recover-const-async-fn-ptr.stderr @@ -1,32 +1,5 @@ -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:3:11 - | -LL | type T0 = const fn(); - | -----^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:4:11 - | -LL | type T1 = const extern "C" fn(); - | -----^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:5:11 - | -LL | type T2 = const unsafe extern fn(); - | -----^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:6:11 + --> $DIR/recover-const-async-fn-ptr.rs:3:11 | LL | type T3 = async fn(); | -----^^^^^ @@ -35,7 +8,7 @@ LL | type T3 = async fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:7:11 + --> $DIR/recover-const-async-fn-ptr.rs:4:11 | LL | type T4 = async extern fn(); | -----^^^^^^^^^^^^ @@ -44,7 +17,7 @@ LL | type T4 = async extern fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:8:11 + --> $DIR/recover-const-async-fn-ptr.rs:5:11 | LL | type T5 = async unsafe extern "C" fn(); | -----^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,53 +25,8 @@ LL | type T5 = async unsafe extern "C" fn(); | `async` because of this | help: remove the `async` qualifier -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:9:11 - | -LL | type T6 = const async unsafe extern "C" fn(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:9:11 - | -LL | type T6 = const async unsafe extern "C" fn(); - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | help: remove the `async` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:13:12 - | -LL | type FT0 = for<'a> const fn(); - | ^^^^^^^^-----^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:14:12 - | -LL | type FT1 = for<'a> const extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:15:12 - | -LL | type FT2 = for<'a> const unsafe extern fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:16:12 + --> $DIR/recover-const-async-fn-ptr.rs:7:12 | LL | type FT3 = for<'a> async fn(); | ^^^^^^^^-----^^^^^ @@ -107,7 +35,7 @@ LL | type FT3 = for<'a> async fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:17:12 + --> $DIR/recover-const-async-fn-ptr.rs:8:12 | LL | type FT4 = for<'a> async extern fn(); | ^^^^^^^^-----^^^^^^^^^^^^ @@ -116,7 +44,7 @@ LL | type FT4 = for<'a> async extern fn(); | help: remove the `async` qualifier error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:18:12 + --> $DIR/recover-const-async-fn-ptr.rs:9:12 | LL | type FT5 = for<'a> async unsafe extern "C" fn(); | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,32 +52,14 @@ LL | type FT5 = for<'a> async unsafe extern "C" fn(); | `async` because of this | help: remove the `async` qualifier -error: an `fn` pointer type cannot be `const` - --> $DIR/recover-const-async-fn-ptr.rs:19:12 - | -LL | type FT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `const` because of this - | help: remove the `const` qualifier - -error: an `fn` pointer type cannot be `async` - --> $DIR/recover-const-async-fn-ptr.rs:19:12 - | -LL | type FT6 = for<'a> const async unsafe extern "C" fn(); - | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | help: remove the `async` qualifier - error[E0308]: mismatched types - --> $DIR/recover-const-async-fn-ptr.rs:24:33 + --> $DIR/recover-const-async-fn-ptr.rs:12:33 | LL | let _recovery_witness: () = 0; | -- ^ expected `()`, found integer | | | expected due to this -error: aborting due to 17 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs index 7cb7d0a26b65e..d1cddc910a52b 100644 --- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -149,7 +149,11 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv }, Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer + | PointerCast::NotConstFnPointer + | PointerCast::UnsafeNotConstFnPointer, ), _, _,