From 008daf0ac2f1ced416b8c0eb85f4e335d7c7bc27 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Sun, 19 Jul 2020 20:01:00 +0300 Subject: [PATCH 01/15] Add constness qualifier to fn pointer --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_parse/src/parser/ty.rs | 5 +---- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 245353c2e0756..94f98595a8fd9 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..5ee7a9bf7bf1b 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -462,7 +462,7 @@ 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_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index d42a786a18fe9..16b1b01d4916d 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -330,13 +330,10 @@ impl<'a> Parser<'a> { let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?; 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"); - } 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. From 855eca0106a48709109db1c25a9d76331bb73b78 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Mon, 20 Jul 2020 00:25:59 +0300 Subject: [PATCH 02/15] Add constness qualifier to function signature --- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 1 + compiler/rustc_codegen_llvm/src/intrinsic.rs | 3 +++ compiler/rustc_hir/src/hir.rs | 10 ++++++++++ compiler/rustc_hir_pretty/src/lib.rs | 4 +++- compiler/rustc_middle/src/ty/context.rs | 4 +++- compiler/rustc_middle/src/ty/error.rs | 10 +++++++--- compiler/rustc_middle/src/ty/layout.rs | 20 ++++++++++--------- compiler/rustc_middle/src/ty/relate.rs | 13 ++++++++++++ .../rustc_middle/src/ty/structural_impls.rs | 2 ++ compiler/rustc_middle/src/ty/sty.rs | 2 ++ .../src/traits/error_reporting/suggestions.rs | 2 ++ compiler/rustc_typeck/src/astconv/mod.rs | 4 +++- compiler/rustc_typeck/src/check/callee.rs | 1 + compiler/rustc_typeck/src/check/closure.rs | 5 +++++ compiler/rustc_typeck/src/check/intrinsic.rs | 7 ++++++- compiler/rustc_typeck/src/collect.rs | 5 ++++- compiler/rustc_typeck/src/lib.rs | 2 ++ 18 files changed, 79 insertions(+), 18 deletions(-) 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_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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 636f67a77c890..98bd98198e78e 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,15 @@ pub enum Constness { 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..e074876c33d96 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<'_>], @@ -2330,7 +2332,7 @@ impl<'a> State<'a> { hir::FnHeader { unsafety, abi, - constness: hir::Constness::NotConst, + constness, asyncness: hir::IsAsync::NotAsync, }, name, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e67a76f0111a0..0e6dd223790bd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2082,7 +2082,7 @@ 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,) }) } @@ -2459,6 +2459,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 +2469,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..f286a64a53bf1 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, @@ -197,9 +201,9 @@ impl<'tcx> TypeError<'tcx> { pub fn must_include_note(&self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) - | FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) - | VariadicMismatch(_) | TargetFeatureCast(_) => false, + CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | 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..d1111dc681413 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2339,15 +2339,16 @@ 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()), - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi, - ) - }) + + sig.map_bound(|sig| + tcx.mk_fn_sig( + iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + sig.output(), + sig.c_variadic, + sig.unsafety, + sig.abi, + hir::Constness::NotConst, + )) } ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); @@ -2373,6 +2374,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/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index c4df0bba726cb..bac659a266901 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,17 @@ 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 || (a == ast::Constness::Const && b == ast::Constness::NotConst) { 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..9fda883b045fe 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..42420697237d3 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, } } } 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..5ac08ea62eadd 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..0605738b81778 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, @@ -2184,7 +2186,7 @@ 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)); + 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..e5c037833d1a4 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/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/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 2ee867c2dd648..d2fff5162c93a 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,7 @@ 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 +473,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/collect.rs b/compiler/rustc_typeck/src/collect.rs index b64a1ce7c3082..afa607ebcdc2b 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), @@ -1569,7 +1570,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { 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 { @@ -1591,6 +1592,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { false, hir::Unsafety::Normal, abi::Abi::Rust, + hir::Constness::NotConst, )) } @@ -2263,6 +2265,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( From 05f4924d3847ab3627e67154d4ec82aa1f919ecc Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Mon, 20 Jul 2020 01:39:21 +0300 Subject: [PATCH 03/15] Allow call const function pointer in const methods --- compiler/rustc_middle/src/ty/sty.rs | 1 + compiler/rustc_mir/src/transform/check_consts/validation.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 42420697237d3..f83dfea36d778 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1179,6 +1179,7 @@ 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>>; diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 587b5b381288a..aed8d81fcef5c 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -745,7 +745,10 @@ 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 fn_sig.constness() == hir::Constness::Const { return; } self.check_op(ops::FnCallIndirect); return; } From 97d388a73b1c390852b6db817237d6d62194eba2 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Mon, 20 Jul 2020 10:05:31 +0300 Subject: [PATCH 04/15] Add feature for const pointers --- compiler/rustc_ast_passes/src/ast_validation.rs | 11 +++++++++++ compiler/rustc_feature/src/active.rs | 3 +++ compiler/rustc_middle/src/ty/relate.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 232ee35c4f7df..1c163eb7fb358 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -22,6 +22,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use std::mem; use std::ops::DerefMut; +use rustc_session::parse::feature_err; const MORE_EXTERN: &str = "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; @@ -824,6 +825,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ) .emit(); }); + if !self.session.features_untracked().const_fn_pointer { + if let Const::Yes(span) = bfty.constness { + feature_err( + &self.session.parse_sess, + sym::const_fn_pointer, + span, + "`const fn` pointer type is unstable" + ).emit() + } + } self.check_late_bound_lifetime_defs(&bfty.generic_params); } TyKind::TraitObject(ref bounds, ..) => { 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_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index bac659a266901..91e4c948f1a1f 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -225,7 +225,7 @@ impl<'tcx> Relate<'tcx> for ast::Constness { a: ast::Constness, b: ast::Constness ) -> RelateResult<'tcx, ast::Constness> { - if a == b || (a == ast::Constness::Const && b == ast::Constness::NotConst) { Ok(a) } + if a == b || (a == ast::Constness::Const && b == ast::Constness::NotConst) { Ok(b) } else { Err(TypeError::ConstnessMismatch(expected_found(relation, a, b))) } } } 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, From 7374ae7a87b95d1eb658aa9050b5733f073aa86d Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Mon, 20 Jul 2020 19:49:31 +0300 Subject: [PATCH 05/15] x.py fmt --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/mut_visit.rs | 3 +- .../rustc_ast_passes/src/ast_validation.rs | 7 +-- compiler/rustc_hir/src/hir.rs | 4 +- compiler/rustc_hir_pretty/src/lib.rs | 7 +-- compiler/rustc_middle/src/ty/context.rs | 11 ++++- compiler/rustc_middle/src/ty/error.rs | 6 +-- compiler/rustc_middle/src/ty/relate.rs | 11 +++-- .../rustc_middle/src/ty/structural_impls.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 6 ++- .../src/transform/check_consts/validation.rs | 4 +- .../src/traits/error_reporting/suggestions.rs | 2 +- compiler/rustc_typeck/src/astconv/mod.rs | 10 +++- compiler/rustc_typeck/src/check/callee.rs | 2 +- compiler/rustc_typeck/src/check/intrinsic.rs | 12 ++++- compiler/rustc_typeck/src/collect.rs | 12 +++-- .../feature-gate-const_fn_pointer.rs | 19 ++++++++ .../feature-gate-const_fn_pointer.stderr | 48 +++++++++++++++++++ 18 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-const_fn_pointer.rs create mode 100644 src/test/ui/feature-gates/feature-gate-const_fn_pointer.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 94f98595a8fd9..2d0f346c6ab4b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1900,7 +1900,7 @@ pub struct BareFnTy { pub ext: Extern, pub generic_params: Vec, pub decl: P, - pub constness: Const + 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 5ee7a9bf7bf1b..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: _, constness: _, 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_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1c163eb7fb358..1e68b0369db86 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -17,12 +17,12 @@ use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; +use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use std::mem; use std::ops::DerefMut; -use rustc_session::parse::feature_err; const MORE_EXTERN: &str = "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; @@ -831,8 +831,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &self.session.parse_sess, sym::const_fn_pointer, span, - "`const fn` pointer type is unstable" - ).emit() + "`const fn` pointer type is unstable", + ) + .emit() } } self.check_late_bound_lifetime_defs(&bfty.generic_params); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 98bd98198e78e..7c54c8de21f38 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2035,7 +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 + pub constness: Constness, } #[derive(Debug, HashStable_Generic)] @@ -2522,7 +2522,7 @@ impl fmt::Display for Constness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { Self::Const => "const", - Self::NotConst => "" + Self::NotConst => "", }) } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e074876c33d96..3bc8514ee7929 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2329,12 +2329,7 @@ impl<'a> State<'a> { }; self.print_fn( decl, - hir::FnHeader { - unsafety, - abi, - constness, - 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_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0e6dd223790bd..8eb3a43a8db32 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2082,7 +2082,14 @@ 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, hir::Constness::NotConst,) + self.mk_fn_sig( + params_iter, + s.output(), + s.c_variadic, + unsafety, + abi::Abi::Rust, + hir::Constness::NotConst, + ) }) } @@ -2469,7 +2476,7 @@ impl<'tcx> TyCtxt<'tcx> { c_variadic, unsafety, abi, - constness + constness, }) } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index f286a64a53bf1..fc12b33f6d496 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -201,9 +201,9 @@ impl<'tcx> TypeError<'tcx> { pub fn must_include_note(&self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | ConstnessMismatch(_) | FixedArraySize(_) - | Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) - | TargetFeatureCast(_) => false, + CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) + | ConstnessMismatch(_) | FixedArraySize(_) | Sorts(_) | IntMismatch(_) + | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | TupleSize(_) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 91e4c948f1a1f..87c766f0e7d20 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -190,7 +190,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { c_variadic: a.c_variadic, unsafety, abi, - constness + constness, }) } } @@ -223,10 +223,13 @@ impl<'tcx> Relate<'tcx> for ast::Constness { fn relate>( relation: &mut R, a: ast::Constness, - b: ast::Constness + b: ast::Constness, ) -> RelateResult<'tcx, ast::Constness> { - if a == b || (a == ast::Constness::Const && b == ast::Constness::NotConst) { Ok(b) } - else { Err(TypeError::ConstnessMismatch(expected_found(relation, a, b))) } + if a == b || (a == ast::Constness::Const && b == ast::Constness::NotConst) { + Ok(b) + } else { + Err(TypeError::ConstnessMismatch(expected_found(relation, a, b))) + } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 9fda883b045fe..29bbf6f0c8cd5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -648,7 +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 + constness: self.constness, }) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f83dfea36d778..fb7d707ce9e8d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1127,7 +1127,7 @@ pub struct FnSig<'tcx> { pub c_variadic: bool, pub unsafety: hir::Unsafety, pub abi: abi::Abi, - pub constness: hir::Constness + pub constness: hir::Constness, } impl<'tcx> FnSig<'tcx> { @@ -1179,7 +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 fn constness(&self) -> hir::Constness { + self.skip_binder().constness + } } pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder>>; diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index aed8d81fcef5c..4dfaefa09e8a8 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -748,7 +748,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { ty::FnPtr(fn_sig) => { // At this point, we are calling a function by raw pointer because // we know that it is const - if fn_sig.constness() == hir::Constness::Const { return; } + if fn_sig.constness() == hir::Constness::Const { + return; + } self.check_op(ops::FnCallIndirect); return; } 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 5ac08ea62eadd..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,7 +1159,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { false, hir::Unsafety::Normal, abi::Abi::Rust, - hir::Constness::NotConst + hir::Constness::NotConst, ) } else { tcx.mk_fn_sig( diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 0605738b81778..e32c287583115 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2185,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, constness,)); + 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 e5c037833d1a4..919aed44a3885 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -397,7 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, hir::Unsafety::Normal, abi::Abi::Rust, - hir::Constness::NotConst + hir::Constness::NotConst, )), None, ) diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index d2fff5162c93a..436c23813e160 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -380,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, hir::Constness::NotConst, 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. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index afa607ebcdc2b..c4d49f87b6820 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1569,9 +1569,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { ident, generics, .. - }) => { - AstConv::ty_of_fn(&icx, header.unsafety, header.abi, header.constness, 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, _, _), 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`. From 4d9b253a07b7bd2fa5b78ec01e08f4fc6af8ff6e Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Mon, 20 Jul 2020 21:00:52 +0300 Subject: [PATCH 06/15] Fix coerce-unify test --- compiler/rustc_middle/src/ty/relate.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 87c766f0e7d20..4c12df719ac87 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -221,15 +221,11 @@ impl<'tcx> Relate<'tcx> for abi::Abi { impl<'tcx> Relate<'tcx> for ast::Constness { fn relate>( - relation: &mut R, + _relation: &mut R, a: ast::Constness, b: ast::Constness, ) -> RelateResult<'tcx, ast::Constness> { - if a == b || (a == ast::Constness::Const && b == ast::Constness::NotConst) { - Ok(b) - } else { - Err(TypeError::ConstnessMismatch(expected_found(relation, a, b))) - } + if a == b { Ok(a) } else { Ok(ast::Constness::NotConst) } } } From 80ef1afaf4b085fd387bd62c735de7867a79f7af Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Tue, 21 Jul 2020 17:49:13 +0300 Subject: [PATCH 07/15] Add NotConstPointerCast + for unsafe. Add new tests for const fn ptr. Add pretty print --- .../rustc_ast_passes/src/ast_validation.rs | 12 -- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_ast_pretty/src/pprust/state.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 8 ++ compiler/rustc_hir/src/hir.rs | 9 ++ .../src/infer/error_reporting/mod.rs | 35 +++--- compiler/rustc_middle/src/ty/adjustment.rs | 6 + compiler/rustc_middle/src/ty/context.rs | 17 +++ compiler/rustc_middle/src/ty/print/pretty.rs | 2 + compiler/rustc_middle/src/ty/relate.rs | 8 +- .../src/borrow_check/type_check/mod.rs | 58 ++++++++++ compiler/rustc_mir/src/interpret/cast.rs | 22 ++++ compiler/rustc_parse/src/parser/ty.rs | 3 + compiler/rustc_typeck/src/check/coercion.rs | 79 +++++++++++-- src/test/ui/consts/const_fn_pointer.rs | 27 +++++ src/test/ui/consts/const_fn_ptr_cast.rs | 25 +++++ src/test/ui/consts/const_fn_ptr_cast.stderr | 30 +++++ src/test/ui/parser/bad-fn-ptr-qualifier.fixed | 12 -- src/test/ui/parser/bad-fn-ptr-qualifier.rs | 12 -- .../ui/parser/bad-fn-ptr-qualifier.stderr | 104 ++--------------- .../ui/parser/recover-const-async-fn-ptr.rs | 12 -- .../parser/recover-const-async-fn-ptr.stderr | 106 ++---------------- .../src/utils/qualify_min_const_fn.rs | 6 +- 23 files changed, 325 insertions(+), 274 deletions(-) create mode 100644 src/test/ui/consts/const_fn_pointer.rs create mode 100644 src/test/ui/consts/const_fn_ptr_cast.rs create mode 100644 src/test/ui/consts/const_fn_ptr_cast.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1e68b0369db86..232ee35c4f7df 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -17,7 +17,6 @@ use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; -use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -825,17 +824,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ) .emit(); }); - if !self.session.features_untracked().const_fn_pointer { - if let Const::Yes(span) = bfty.constness { - feature_err( - &self.session.parse_sess, - sym::const_fn_pointer, - span, - "`const fn` pointer type is unstable", - ) - .emit() - } - } self.check_late_bound_lifetime_defs(&bfty.generic_params); } TyKind::TraitObject(ref bounds, ..) => { 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_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7ce110dcbfc48..3a8675303eee8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -222,6 +222,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // This is a no-op at the LLVM level. operand.val } + mir::CastKind::Pointer(PointerCast::NotConstFnPointer) => { + // This is a no-op at the LLVM level. + operand.val + } + mir::CastKind::Pointer(PointerCast::UnsafeNotConstFnPointer) => { + // This is a no-op at the LLVM level + operand.val + } mir::CastKind::Pointer(PointerCast::Unsize) => { assert!(bx.cx().is_backend_scalar_pair(cast)); match operand.val { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 7c54c8de21f38..ac5ace179d235 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2518,6 +2518,15 @@ 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 { 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_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 8eb3a43a8db32..144c20b2d9849 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)`. 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 4c12df719ac87..14ca5ade90966 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -221,11 +221,15 @@ impl<'tcx> Relate<'tcx> for abi::Abi { impl<'tcx> Relate<'tcx> for ast::Constness { fn relate>( - _relation: &mut R, + relation: &mut R, a: ast::Constness, b: ast::Constness, ) -> RelateResult<'tcx, ast::Constness> { - if a == b { Ok(a) } else { Ok(ast::Constness::NotConst) } + if a == b { + Ok(a) + } else { + Err(TypeError::ConstnessMismatch(expected_found(relation, a, b))) + } } } 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..efacdb1baace1 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -2125,6 +2125,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..e84e67309dc35 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_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 16b1b01d4916d..9cccb2d2b5e39 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -330,6 +330,9 @@ impl<'a> Parser<'a> { let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?; 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.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"); } diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 4addee1a4c976..5c94b064e7d4a 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), 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..806035aaa9096 --- /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..274957d35b0bb --- /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() { } \ No newline at end of file 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/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, ), _, _, From d72e63b9cbe18d7e913e43e297505face55863ee Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Tue, 28 Jul 2020 17:22:22 +0300 Subject: [PATCH 08/15] Check const_fn_pointer feature in mir context --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 14 +++++--------- compiler/rustc_middle/src/ty/layout.rs | 19 ++++++++++--------- .../src/transform/check_consts/validation.rs | 3 ++- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 3a8675303eee8..1e096f0974a6d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -218,18 +218,14 @@ 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) => { - // This is a no-op at the LLVM level. - operand.val - } - mir::CastKind::Pointer(PointerCast::NotConstFnPointer) => { + mir::CastKind::Pointer( + PointerCast::UnsafeFnPointer + | PointerCast::NotConstFnPointer + | PointerCast::UnsafeNotConstFnPointer, + ) => { // This is a no-op at the LLVM level. operand.val } - mir::CastKind::Pointer(PointerCast::UnsafeNotConstFnPointer) => { - // This is a no-op at the LLVM level - operand.val - } mir::CastKind::Pointer(PointerCast::Unsize) => { assert!(bx.cx().is_backend_scalar_pair(cast)); match operand.val { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d1111dc681413..450d6b46b0d87 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2340,15 +2340,16 @@ impl<'tcx> ty::Instance<'tcx> { 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()), - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi, - hir::Constness::NotConst, - )) + sig.map_bound(|sig| { + tcx.mk_fn_sig( + iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + sig.output(), + sig.c_variadic, + sig.unsafety, + sig.abi, + hir::Constness::NotConst, + ) + }) } ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 4dfaefa09e8a8..fda9acafebc90 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -748,7 +748,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { ty::FnPtr(fn_sig) => { // At this point, we are calling a function by raw pointer because // we know that it is const - if fn_sig.constness() == hir::Constness::Const { + if self.ccx.tcx.features().const_fn_pointer && + fn_sig.constness() == hir::Constness::Const { return; } self.check_op(ops::FnCallIndirect); From 270bf4c07764e6c25142a5ae1a4d5ed8b7c2c995 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Thu, 30 Jul 2020 19:13:36 +0300 Subject: [PATCH 09/15] Add example of reifyfnpointer with const drop --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 34 +++++++++---------- compiler/rustc_lint/src/builtin.rs | 4 +-- compiler/rustc_middle/src/ty/adjustment.rs | 3 ++ compiler/rustc_middle/src/ty/context.rs | 11 ++++++ .../src/borrow_check/type_check/mod.rs | 29 ++++++++++++++++ compiler/rustc_mir/src/interpret/cast.rs | 2 +- .../src/transform/check_consts/validation.rs | 5 +-- compiler/rustc_typeck/src/check/coercion.rs | 31 +++++++++++++++-- src/test/ui/consts/const_fn_pointer.rs | 6 ++-- src/test/ui/consts/const_fn_ptr_cast.rs | 2 +- .../src/utils/qualify_min_const_fn.rs | 1 + 11 files changed, 99 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 1e096f0974a6d..aa6e0b3e269c5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -184,25 +184,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast = bx.cx().layout_of(self.monomorphize(&mir_cast_ty)); let val = match *kind { - mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { - match *operand.layout.ty.kind() { - ty::FnDef(def_id, substs) => { - if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { - bug!("reifying a fn ptr that requires const arguments"); - } - let instance = ty::Instance::resolve_for_fn_ptr( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap() - .polymorphize(bx.cx().tcx()); - OperandValue::Immediate(bx.get_fn_addr(instance)) + mir::CastKind::Pointer( + PointerCast::ReifyFnPointer | PointerCast::ReifyNotConstFnPointer, + ) => match operand.layout.ty.kind() { + ty::FnDef(def_id, substs) => { + if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { + bug!("reifying a fn ptr that requires const arguments"); } - _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), + let instance = ty::Instance::resolve_for_fn_ptr( + bx.tcx(), + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .unwrap() + .polymorphize(bx.cx().tcx()); + OperandValue::Immediate(bx.get_fn_addr(instance)) } - } + _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), + }, mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { match *operand.layout.ty.kind() { ty::Closure(def_id, substs) => { 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 5c702102679f0..11106f625a934 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -11,6 +11,9 @@ pub enum PointerCast { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, + /// Go from a fn-item type to a not const fn-pointer type (drop const qualifier) + ReifyNotConstFnPointer, + /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 144c20b2d9849..a1dfdb8d59579 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2110,6 +2110,10 @@ impl<'tcx> TyCtxt<'tcx> { }) } + 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] @@ -2302,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, 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 efacdb1baace1..91aaf085e32ca 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -2072,6 +2072,35 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + CastKind::Pointer(PointerCast::ReifyNotConstFnPointer) => { + 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.mk_not_const_fn_ptr(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::ClosureFnPointer(unsafety)) => { let sig = match op.ty(body, tcx).kind() { ty::Closure(_, substs) => substs.as_closure().sig(), diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index e84e67309dc35..b7a6e950366c8 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -45,7 +45,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(*v, dest)?; } - Pointer(PointerCast::ReifyFnPointer) => { + Pointer(PointerCast::ReifyFnPointer | PointerCast::ReifyNotConstFnPointer) => { // The src operand does not matter, just its type match *src.layout.ty.kind() { ty::FnDef(def_id, substs) => { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index fda9acafebc90..4c130d7237961 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -748,8 +748,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { 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 { + if self.ccx.tcx.features().const_fn_pointer + && fn_sig.constness() == hir::Constness::Const + { return; } self.check_op(ops::FnCallIndirect); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 5c94b064e7d4a..e148db6b32a27 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -952,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, @@ -982,7 +984,18 @@ 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; + } + } + (Some(prev_sig), Some(new_sig)) } } } @@ -1028,12 +1041,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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::FnDef(..) => { + if prev_drop_const { + Adjust::Pointer(PointerCast::ReifyNotConstFnPointer) + } else { + Adjust::Pointer(PointerCast::ReifyFnPointer) + } + } _ => unreachable!(), }; let next_adjustment = match new_ty.kind() { ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), - ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + ty::FnDef(..) => { + if new_drop_const { + Adjust::Pointer(PointerCast::ReifyNotConstFnPointer) + } else { + Adjust::Pointer(PointerCast::ReifyFnPointer) + } + } _ => unreachable!(), }; for expr in exprs.iter().map(|e| e.as_coercion_site()) { diff --git a/src/test/ui/consts/const_fn_pointer.rs b/src/test/ui/consts/const_fn_pointer.rs index 806035aaa9096..2a058896468fa 100644 --- a/src/test/ui/consts/const_fn_pointer.rs +++ b/src/test/ui/consts/const_fn_pointer.rs @@ -13,15 +13,15 @@ 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; } +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; } +impl Bar for u32 { const F: const fn(Self) -> Self = map_u32; } const fn map_smth(v: T) -> T { ::F(v) } -fn main() { +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 index 274957d35b0bb..5620ca1b28e3c 100644 --- a/src/test/ui/consts/const_fn_ptr_cast.rs +++ b/src/test/ui/consts/const_fn_ptr_cast.rs @@ -22,4 +22,4 @@ const _: const unsafe fn() = unsafe_fn; const _: unsafe fn() = const_unsafe_fn; -fn main() { } \ No newline at end of file +fn main() { } 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 d1cddc910a52b..7a5ffc4ccaaa7 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 @@ -152,6 +152,7 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer + | PointerCast::ReifyNotConstFnPointer | PointerCast::NotConstFnPointer | PointerCast::UnsafeNotConstFnPointer, ), From d982864e69cb850603a630da04c1500167ab533f Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Mon, 12 Oct 2020 10:39:04 +0300 Subject: [PATCH 10/15] Resolve conflict... --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_mir/src/interpret/cast.rs | 4 ++-- compiler/rustc_mir/src/transform/check_consts/validation.rs | 3 +++ compiler/rustc_typeck/src/check/check.rs | 1 + compiler/rustc_typeck/src/check/mod.rs | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index aa6e0b3e269c5..23913ad12a25e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match *kind { mir::CastKind::Pointer( PointerCast::ReifyFnPointer | PointerCast::ReifyNotConstFnPointer, - ) => match operand.layout.ty.kind() { + ) => match *operand.layout.ty.kind() { ty::FnDef(def_id, substs) => { if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index b7a6e950366c8..d3e712951e1b5 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -87,7 +87,7 @@ 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 { + match cast_ty.kind() { ty::FnPtr(_) => { // No change to value self.write_immediate(*src, dest)?; @@ -98,7 +98,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::UnsafeNotConstFnPointer) => { let src = self.read_immediate(src)?; - match cast_ty.kind { + match cast_ty.kind() { ty::FnPtr(_) => { // No change to value self.write_immediate(*src, dest)?; diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 4c130d7237961..3bfbc23aab2a7 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -557,6 +557,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { CastKind::Pointer( PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyNotConstFnPointer + | PointerCast::NotConstFnPointer + | PointerCast::UnsafeNotConstFnPointer | PointerCast::ReifyFnPointer, ), _, 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/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, From bb4ab24468d534379a2526af269c400190856c34 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Mon, 12 Oct 2020 23:08:27 +0300 Subject: [PATCH 11/15] Match coercion --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_middle/src/ty/adjustment.rs | 3 -- .../src/borrow_check/type_check/mod.rs | 29 -------------- compiler/rustc_mir/src/interpret/cast.rs | 2 +- .../src/transform/check_consts/validation.rs | 1 - compiler/rustc_typeck/src/check/coercion.rs | 39 +++++++++++++------ .../src/utils/qualify_min_const_fn.rs | 1 - 7 files changed, 30 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 23913ad12a25e..fb8094c90cf5c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match *kind { mir::CastKind::Pointer( - PointerCast::ReifyFnPointer | PointerCast::ReifyNotConstFnPointer, + PointerCast::ReifyFnPointer, ) => match *operand.layout.ty.kind() { ty::FnDef(def_id, substs) => { if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 11106f625a934..5c702102679f0 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -11,9 +11,6 @@ pub enum PointerCast { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, - /// Go from a fn-item type to a not const fn-pointer type (drop const qualifier) - ReifyNotConstFnPointer, - /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, 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 91aaf085e32ca..efacdb1baace1 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -2072,35 +2072,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::ReifyNotConstFnPointer) => { - 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.mk_not_const_fn_ptr(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::ClosureFnPointer(unsafety)) => { let sig = match op.ty(body, tcx).kind() { ty::Closure(_, substs) => substs.as_closure().sig(), diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index d3e712951e1b5..dc37b4d294247 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -45,7 +45,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(*v, dest)?; } - Pointer(PointerCast::ReifyFnPointer | PointerCast::ReifyNotConstFnPointer) => { + Pointer(PointerCast::ReifyFnPointer) => { // The src operand does not matter, just its type match *src.layout.ty.kind() { ty::FnDef(def_id, substs) => { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 3bfbc23aab2a7..1ddb59d28387d 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -557,7 +557,6 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { CastKind::Pointer( PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyNotConstFnPointer | PointerCast::NotConstFnPointer | PointerCast::UnsafeNotConstFnPointer | PointerCast::ReifyFnPointer, diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index e148db6b32a27..20283cf6c3e8e 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -975,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 @@ -1040,34 +1040,51 @@ 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::Closure(..) => { + Some(Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety()))) + } ty::FnDef(..) => { + Some(Adjust::Pointer(PointerCast::ReifyFnPointer)) + } + ty::FnPtr(..) => { if prev_drop_const { - Adjust::Pointer(PointerCast::ReifyNotConstFnPointer) + Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) } else { - Adjust::Pointer(PointerCast::ReifyFnPointer) + None } } _ => unreachable!(), }; let next_adjustment = match new_ty.kind() { - ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), + ty::Closure(..) => { + Some(Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety()))) + } ty::FnDef(..) => { + Some(Adjust::Pointer(PointerCast::ReifyFnPointer)) + } + ty::FnPtr(..) => { if new_drop_const { - Adjust::Pointer(PointerCast::ReifyNotConstFnPointer) + Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) } else { - Adjust::Pointer(PointerCast::ReifyFnPointer) + 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/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 7a5ffc4ccaaa7..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 @@ -152,7 +152,6 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer - | PointerCast::ReifyNotConstFnPointer | PointerCast::NotConstFnPointer | PointerCast::UnsafeNotConstFnPointer, ), From 55add43fbf3343612554217f84c8693ed30a0e4f Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Tue, 13 Oct 2020 23:02:58 +0300 Subject: [PATCH 12/15] Modified apply_adjustments, add unsafety coercion --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 34 +++++++++---------- compiler/rustc_middle/src/ty/sty.rs | 1 + .../src/borrow_check/type_check/mod.rs | 14 +++++--- compiler/rustc_typeck/src/check/coercion.rs | 29 +++++++++++----- 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index fb8094c90cf5c..1e096f0974a6d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -184,25 +184,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast = bx.cx().layout_of(self.monomorphize(&mir_cast_ty)); let val = match *kind { - mir::CastKind::Pointer( - PointerCast::ReifyFnPointer, - ) => match *operand.layout.ty.kind() { - ty::FnDef(def_id, substs) => { - if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { - bug!("reifying a fn ptr that requires const arguments"); + mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { + match *operand.layout.ty.kind() { + ty::FnDef(def_id, substs) => { + if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { + bug!("reifying a fn ptr that requires const arguments"); + } + let instance = ty::Instance::resolve_for_fn_ptr( + bx.tcx(), + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .unwrap() + .polymorphize(bx.cx().tcx()); + OperandValue::Immediate(bx.get_fn_addr(instance)) } - let instance = ty::Instance::resolve_for_fn_ptr( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap() - .polymorphize(bx.cx().tcx()); - OperandValue::Immediate(bx.get_fn_addr(instance)) + _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), } - _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), - }, + } mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { match *operand.layout.ty.kind() { ty::Closure(def_id, substs) => { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index fb7d707ce9e8d..5d629d22440d2 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2081,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 efacdb1baace1..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); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 20283cf6c3e8e..ed2f07c8a89d5 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -994,6 +994,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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)) } @@ -1043,12 +1047,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Closure(..) => { Some(Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety()))) } - ty::FnDef(..) => { - Some(Adjust::Pointer(PointerCast::ReifyFnPointer)) - } + ty::FnDef(..) => Some(Adjust::Pointer(PointerCast::ReifyFnPointer)), ty::FnPtr(..) => { if prev_drop_const { - Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) + if a_sig.unsafety() != b_sig.unsafety() { + Some(Adjust::Pointer(PointerCast::UnsafeNotConstFnPointer)) + } else { + Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) + } } else { None } @@ -1059,12 +1065,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Closure(..) => { Some(Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety()))) } - ty::FnDef(..) => { - Some(Adjust::Pointer(PointerCast::ReifyFnPointer)) - } + ty::FnDef(..) => Some(Adjust::Pointer(PointerCast::ReifyFnPointer)), ty::FnPtr(..) => { if new_drop_const { - Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) + if a_sig.unsafety() != b_sig.unsafety() { + Some(Adjust::Pointer(PointerCast::UnsafeNotConstFnPointer)) + } else { + Some(Adjust::Pointer(PointerCast::NotConstFnPointer)) + } } else { None } @@ -1075,7 +1083,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 }], + vec![Adjustment { + kind: prev_adjustment.clone().unwrap().clone(), + target: fn_ptr, + }], ); } } From ed42405ba563e37527e7be158da07d48a666cc42 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Tue, 13 Oct 2020 23:13:32 +0300 Subject: [PATCH 13/15] Fix typo --- compiler/rustc_typeck/src/check/coercion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index ed2f07c8a89d5..5f5caffeb6bf0 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -996,7 +996,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } 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 });= + new_sig = new_sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }); } } (Some(prev_sig), Some(new_sig)) From be46b44283c1936e4cbdc1dd1c346116af4e3c98 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Tue, 13 Oct 2020 23:20:07 +0300 Subject: [PATCH 14/15] Add coercion unsafe --- compiler/rustc_typeck/src/check/coercion.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 5f5caffeb6bf0..782d0c5629735 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -994,10 +994,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 }); - } + } + 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)) } From c772728e0abce8f7f8008af5dfc911c1107f6b81 Mon Sep 17 00:00:00 2001 From: Ilya Filtsin Date: Wed, 14 Oct 2020 18:19:04 +0300 Subject: [PATCH 15/15] Resolve conflict --- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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. _ =>