Skip to content

Commit 80ef1af

Browse files
committed
Add NotConstPointerCast + for unsafe. Add new tests for const fn ptr. Add pretty print
1 parent 4d9b253 commit 80ef1af

File tree

23 files changed

+325
-274
lines changed

23 files changed

+325
-274
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
1717
use rustc_parse::validate_attr;
1818
use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
1919
use rustc_session::lint::LintBuffer;
20-
use rustc_session::parse::feature_err;
2120
use rustc_session::Session;
2221
use rustc_span::symbol::{kw, sym, Ident};
2322
use rustc_span::Span;
@@ -825,17 +824,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
825824
)
826825
.emit();
827826
});
828-
if !self.session.features_untracked().const_fn_pointer {
829-
if let Const::Yes(span) = bfty.constness {
830-
feature_err(
831-
&self.session.parse_sess,
832-
sym::const_fn_pointer,
833-
span,
834-
"`const fn` pointer type is unstable",
835-
)
836-
.emit()
837-
}
838-
}
839827
self.check_late_bound_lifetime_defs(&bfty.generic_params);
840828
}
841829
TyKind::TraitObject(ref bounds, ..) => {

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
629629
gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
630630
gate_all!(const_trait_impl, "const trait impls are experimental");
631631
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
632+
gate_all!(const_fn_pointer, "`const fn` pointer type is unstable");
632633

633634
// All uses of `gate_all!` below this point were added in #65742,
634635
// and subsequently disabled (with the non-early gating readded).

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ impl<'a> State<'a> {
10051005
self.pclose();
10061006
}
10071007
ast::TyKind::BareFn(ref f) => {
1008-
self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
1008+
self.print_ty_fn(f.ext, f.unsafety, f.constness, &f.decl, None, &f.generic_params);
10091009
}
10101010
ast::TyKind::Path(None, ref path) => {
10111011
self.print_path(path, false, 0);
@@ -2812,6 +2812,7 @@ impl<'a> State<'a> {
28122812
&mut self,
28132813
ext: ast::Extern,
28142814
unsafety: ast::Unsafe,
2815+
constness: ast::Const,
28152816
decl: &ast::FnDecl,
28162817
name: Option<Ident>,
28172818
generic_params: &[ast::GenericParam],
@@ -2830,7 +2831,7 @@ impl<'a> State<'a> {
28302831
},
28312832
span: rustc_span::DUMMY_SP,
28322833
};
2833-
let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
2834+
let header = ast::FnHeader { unsafety, constness, ext, ..ast::FnHeader::default() };
28342835
self.print_fn(decl, header, name, &generics);
28352836
self.end();
28362837
}

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
222222
// This is a no-op at the LLVM level.
223223
operand.val
224224
}
225+
mir::CastKind::Pointer(PointerCast::NotConstFnPointer) => {
226+
// This is a no-op at the LLVM level.
227+
operand.val
228+
}
229+
mir::CastKind::Pointer(PointerCast::UnsafeNotConstFnPointer) => {
230+
// This is a no-op at the LLVM level
231+
operand.val
232+
}
225233
mir::CastKind::Pointer(PointerCast::Unsize) => {
226234
assert!(bx.cx().is_backend_scalar_pair(cast));
227235
match operand.val {

compiler/rustc_hir/src/hir.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2518,6 +2518,15 @@ pub enum Constness {
25182518
NotConst,
25192519
}
25202520

2521+
impl Constness {
2522+
pub fn prefix_str(&self) -> &'static str {
2523+
match self {
2524+
Self::Const => "const ",
2525+
Self::NotConst => "",
2526+
}
2527+
}
2528+
}
2529+
25212530
impl fmt::Display for Constness {
25222531
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25232532
f.write_str(match *self {

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -943,39 +943,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
943943
let (lt1, sig1) = get_lifetimes(sig1);
944944
let (lt2, sig2) = get_lifetimes(sig2);
945945

946-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
946+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
947947
let mut values = (
948948
DiagnosticStyledString::normal("".to_string()),
949949
DiagnosticStyledString::normal("".to_string()),
950950
);
951951

952-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
953-
// ^^^^^^
952+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
953+
// ^^^^^
954+
values.0.push(sig1.constness.prefix_str(), sig1.constness != sig2.constness);
955+
values.1.push(sig2.constness.prefix_str(), sig1.constness != sig2.constness);
956+
957+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
958+
// ^^^^^^
954959
values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
955960
values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
956961

957-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
958-
// ^^^^^^^^^^
962+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
963+
// ^^^^^^^^^^
959964
if sig1.abi != abi::Abi::Rust {
960965
values.0.push(format!("extern {} ", sig1.abi), sig1.abi != sig2.abi);
961966
}
962967
if sig2.abi != abi::Abi::Rust {
963968
values.1.push(format!("extern {} ", sig2.abi), sig1.abi != sig2.abi);
964969
}
965970

966-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
967-
// ^^^^^^^^
971+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
972+
// ^^^^^^^^
968973
let lifetime_diff = lt1 != lt2;
969974
values.0.push(lt1, lifetime_diff);
970975
values.1.push(lt2, lifetime_diff);
971976

972-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
973-
// ^^^
977+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
978+
// ^^^
974979
values.0.push_normal("fn(");
975980
values.1.push_normal("fn(");
976981

977-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
978-
// ^^^^^
982+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
983+
// ^^^^^
979984
let len1 = sig1.inputs().len();
980985
let len2 = sig2.inputs().len();
981986
if len1 == len2 {
@@ -1013,13 +1018,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10131018
values.1.push("...", !sig1.c_variadic);
10141019
}
10151020

1016-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
1017-
// ^
1021+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
1022+
// ^
10181023
values.0.push_normal(")");
10191024
values.1.push_normal(")");
10201025

1021-
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
1022-
// ^^^^^^^^
1026+
// const unsafe extern "C" for<'a> fn(&'a T) -> &'a T
1027+
// ^^^^^^^^
10231028
let output1 = sig1.output();
10241029
let output2 = sig2.output();
10251030
let (x1, x2) = self.cmp(output1, output2);

compiler/rustc_middle/src/ty/adjustment.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ pub enum PointerCast {
1414
/// Go from a safe fn pointer to an unsafe fn pointer.
1515
UnsafeFnPointer,
1616

17+
// Go from a const fn pointer to a not const fn pointer
18+
NotConstFnPointer,
19+
20+
// Go from a safe const fn pointer to a not const unsafe fn pointer
21+
UnsafeNotConstFnPointer,
22+
1723
/// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
1824
/// It cannot convert a closure that requires unsafe.
1925
ClosureFnPointer(hir::Unsafety),

compiler/rustc_middle/src/ty/context.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,23 @@ impl<'tcx> TyCtxt<'tcx> {
20652065
self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }))
20662066
}
20672067

2068+
pub fn const_to_normal_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
2069+
assert_eq!(sig.constness(), hir::Constness::Const);
2070+
self.mk_fn_ptr(
2071+
sig.map_bound(|sig| ty::FnSig { constness: hir::Constness::NotConst, ..sig }),
2072+
)
2073+
}
2074+
2075+
pub fn const_safe_to_normal_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
2076+
assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
2077+
assert_eq!(sig.constness(), hir::Constness::Const);
2078+
self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig {
2079+
unsafety: hir::Unsafety::Unsafe,
2080+
constness: hir::Constness::NotConst,
2081+
..sig
2082+
}))
2083+
}
2084+
20682085
/// Given a closure signature, returns an equivalent fn signature. Detuples
20692086
/// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
20702087
/// you would get a `fn(u32, i32)`.

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,6 +1980,8 @@ define_print_and_forward_display! {
19801980

19811981
ty::FnSig<'tcx> {
19821982
p!(write("{}", self.unsafety.prefix_str()));
1983+
p!(write("{}", self.constness.prefix_str()));
1984+
19831985

19841986
if self.abi != Abi::Rust {
19851987
p!(write("extern {} ", self.abi));

compiler/rustc_middle/src/ty/relate.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,15 @@ impl<'tcx> Relate<'tcx> for abi::Abi {
221221

222222
impl<'tcx> Relate<'tcx> for ast::Constness {
223223
fn relate<R: TypeRelation<'tcx>>(
224-
_relation: &mut R,
224+
relation: &mut R,
225225
a: ast::Constness,
226226
b: ast::Constness,
227227
) -> RelateResult<'tcx, ast::Constness> {
228-
if a == b { Ok(a) } else { Ok(ast::Constness::NotConst) }
228+
if a == b {
229+
Ok(a)
230+
} else {
231+
Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
232+
}
229233
}
230234
}
231235

compiler/rustc_mir/src/borrow_check/type_check/mod.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,6 +2125,64 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21252125
}
21262126
}
21272127

2128+
CastKind::Pointer(PointerCast::NotConstFnPointer) => {
2129+
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
2130+
2131+
// The type that we see in the fcx is like
2132+
// `foo::<'a, 'b>`, where `foo` is the path to a
2133+
// function definition. When we extract the
2134+
// signature, it comes from the `fn_sig` query,
2135+
// and hence may contain unnormalized results.
2136+
let fn_sig = self.normalize(fn_sig, location);
2137+
2138+
let ty_fn_ptr_from = tcx.const_to_normal_fn_ty(fn_sig);
2139+
2140+
if let Err(terr) = self.eq_types(
2141+
ty_fn_ptr_from,
2142+
ty,
2143+
location.to_locations(),
2144+
ConstraintCategory::Cast,
2145+
) {
2146+
span_mirbug!(
2147+
self,
2148+
rvalue,
2149+
"equating {:?} with {:?} yields {:?}",
2150+
ty_fn_ptr_from,
2151+
ty,
2152+
terr
2153+
);
2154+
}
2155+
}
2156+
2157+
CastKind::Pointer(PointerCast::UnsafeNotConstFnPointer) => {
2158+
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
2159+
2160+
// The type that we see in the fcx is like
2161+
// `foo::<'a, 'b>`, where `foo` is the path to a
2162+
// function definition. When we extract the
2163+
// signature, it comes from the `fn_sig` query,
2164+
// and hence may contain unnormalized results.
2165+
let fn_sig = self.normalize(fn_sig, location);
2166+
2167+
let ty_fn_ptr_from = tcx.const_safe_to_normal_unsafe_fn_ty(fn_sig);
2168+
2169+
if let Err(terr) = self.eq_types(
2170+
ty_fn_ptr_from,
2171+
ty,
2172+
location.to_locations(),
2173+
ConstraintCategory::Cast,
2174+
) {
2175+
span_mirbug!(
2176+
self,
2177+
rvalue,
2178+
"equating {:?} with {:?} yields {:?}",
2179+
ty_fn_ptr_from,
2180+
ty,
2181+
terr
2182+
);
2183+
}
2184+
}
2185+
21282186
CastKind::Pointer(PointerCast::Unsize) => {
21292187
let &ty = ty;
21302188
let trait_ref = ty::TraitRef {

compiler/rustc_mir/src/interpret/cast.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
8585
}
8686
}
8787

88+
Pointer(PointerCast::NotConstFnPointer) => {
89+
let src = self.read_immediate(src)?;
90+
match cast_ty.kind {
91+
ty::FnPtr(_) => {
92+
// No change to value
93+
self.write_immediate(*src, dest)?;
94+
}
95+
_ => span_bug!(self.cur_span(), "const fn to fn cast on {:?}", cast_ty),
96+
}
97+
}
98+
99+
Pointer(PointerCast::UnsafeNotConstFnPointer) => {
100+
let src = self.read_immediate(src)?;
101+
match cast_ty.kind {
102+
ty::FnPtr(_) => {
103+
// No change to value
104+
self.write_immediate(*src, dest)?;
105+
}
106+
_ => span_bug!(self.cur_span(), "const fn to unsafe fn cast on {:?}", cast_ty),
107+
}
108+
}
109+
88110
Pointer(PointerCast::ClosureFnPointer(_)) => {
89111
// The src operand does not matter, just its type
90112
match *src.layout.ty.kind() {

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ impl<'a> Parser<'a> {
330330
let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
331331
let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?;
332332
let whole_span = lo.to(self.prev_token.span);
333+
if let ast::Const::Yes(span) = constness {
334+
self.sess.gated_spans.gate(sym::const_fn_pointer, span);
335+
}
333336
if let ast::Async::Yes { span, .. } = asyncness {
334337
self.error_fn_ptr_bad_qualifier(whole_span, span, "async");
335338
}

0 commit comments

Comments
 (0)