Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[WIP] Add const qualifier in FnSig (for const fn pointers) #74553

Closed
wants to merge 15 commits into from
Closed
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1900,6 +1900,7 @@ pub struct BareFnTy {
pub ext: Extern,
pub generic_params: Vec<GenericParam>,
pub decl: P<FnDecl>,
pub constness: Const,
}

/// The various kinds of type recognized by the compiler.
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, 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);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}))
})
}),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -2812,6 +2812,7 @@ impl<'a> State<'a> {
&mut self,
ext: ast::Extern,
unsafety: ast::Unsafe,
constness: ast::Const,
decl: &ast::FnDecl,
name: Option<Ident>,
generic_params: &[ast::GenericParam],
Expand All @@ -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();
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -716,13 +717,15 @@ 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(),
tcx.mk_unit(),
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);
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
}
}
mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => {
mir::CastKind::Pointer(
PointerCast::UnsafeFnPointer
| PointerCast::NotConstFnPointer
| PointerCast::UnsafeNotConstFnPointer,
) => {
// This is a no-op at the LLVM level.
operand.val
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
// -------------------------------------------------------------------------
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -2517,6 +2518,24 @@ pub enum Constness {
NotConst,
}

impl Constness {
pub fn prefix_str(&self) -> &'static str {
match self {
Self::Const => "const ",
Self::NotConst => "",
}
}
}

impl fmt::Display for Constness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match *self {
Self::Const => "const",
Self::NotConst => "",
})
}
}

#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
pub struct FnHeader {
pub unsafety: Unsafety,
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ impl<'a> State<'a> {
self.print_ty_fn(
f.abi,
f.unsafety,
f.constness,
&f.decl,
None,
&f.generic_params,
Expand Down Expand Up @@ -2310,6 +2311,7 @@ impl<'a> State<'a> {
&mut self,
abi: Abi,
unsafety: hir::Unsafety,
constness: hir::Constness,
decl: &hir::FnDecl<'_>,
name: Option<Symbol>,
generic_params: &[hir::GenericParam<'_>],
Expand All @@ -2327,12 +2329,7 @@ impl<'a> State<'a> {
};
self.print_fn(
decl,
hir::FnHeader {
unsafety,
abi,
constness: hir::Constness::NotConst,
asyncness: hir::IsAsync::NotAsync,
},
hir::FnHeader { unsafety, abi, constness, asyncness: hir::IsAsync::NotAsync },
name,
&generics,
&Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited },
Expand Down
35 changes: 20 additions & 15 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,39 +943,44 @@ 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);
}
if sig2.abi != abi::Abi::Rust {
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 {
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/adjustment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
39 changes: 38 additions & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)`.
Expand All @@ -2082,10 +2099,21 @@ impl<'tcx> TyCtxt<'tcx> {
ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()),
_ => bug!(),
};
self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi::Abi::Rust)
self.mk_fn_sig(
params_iter,
s.output(),
s.c_variadic,
unsafety,
abi::Abi::Rust,
hir::Constness::NotConst,
)
})
}

pub fn signature_not_const_fn(self, sig: PolyFnSig<'tcx>) -> PolyFnSig<'tcx> {
sig.map_bound(|s| ty::FnSig { constness: hir::Constness::NotConst, ..s })
}

/// Same a `self.mk_region(kind)`, but avoids accessing the interners if
/// `*r == kind`.
#[inline]
Expand Down Expand Up @@ -2278,6 +2306,13 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_ty(FnPtr(fty))
}

#[inline]
pub fn mk_not_const_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
let mut not_const = fty.skip_binder();
not_const.constness = hir::Constness::NotConst;
self.mk_ty(FnPtr(ty::Binder::dummy(not_const)))
}

#[inline]
pub fn mk_dynamic(
self,
Expand Down Expand Up @@ -2459,6 +2494,7 @@ impl<'tcx> TyCtxt<'tcx> {
c_variadic: bool,
unsafety: hir::Unsafety,
abi: abi::Abi,
constness: hir::Constness,
) -> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output
where
I: Iterator<Item: InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>,
Expand All @@ -2468,6 +2504,7 @@ impl<'tcx> TyCtxt<'tcx> {
c_variadic,
unsafety,
abi,
constness,
})
}

Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub enum TypeError<'tcx> {
Mismatch,
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
AbiMismatch(ExpectedFound<abi::Abi>),
ConstnessMismatch(ExpectedFound<hir::Constness>),
Mutability,
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<u64>),
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -198,8 +202,8 @@ impl<'tcx> TypeError<'tcx> {
use self::TypeError::*;
match self {
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_)
| FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
| VariadicMismatch(_) | TargetFeatureCast(_) => false,
| ConstnessMismatch(_) | FixedArraySize(_) | Sorts(_) | IntMismatch(_)
| FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false,

Mutability
| TupleSize(_)
Expand Down
Loading