Skip to content

Commit 54769b0

Browse files
authored
Rollup merge of rust-lang#64986 - skinny121:fn-ptr-const-generics, r=varkor
Function pointers as const generic arguments Makes function pointers as const generic arguments usable. Fixes rust-lang#62395 r? @varkor
2 parents 4fde07d + 8569dd1 commit 54769b0

17 files changed

+389
-152
lines changed

src/librustc/mir/interpret/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,14 @@ impl<'tcx> AllocMap<'tcx> {
470470
}
471471
}
472472

473+
/// Panics if the `AllocId` does not refer to a function
474+
pub fn unwrap_fn(&self, id: AllocId) -> Instance<'tcx> {
475+
match self.get(id) {
476+
Some(GlobalAlloc::Function(instance)) => instance,
477+
_ => bug!("expected allocation ID {} to point to a function", id),
478+
}
479+
}
480+
473481
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
474482
/// call this function twice, even with the same `Allocation` will ICE the compiler.
475483
pub fn set_alloc_id_memory(&mut self, id: AllocId, mem: &'tcx Allocation) {

src/librustc/mir/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -2602,7 +2602,14 @@ impl<'tcx> Debug for Constant<'tcx> {
26022602
impl<'tcx> Display for Constant<'tcx> {
26032603
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
26042604
write!(fmt, "const ")?;
2605-
write!(fmt, "{}", self.literal)
2605+
// FIXME make the default pretty printing of raw pointers more detailed. Here we output the
2606+
// debug representation of raw pointers, so that the raw pointers in the mir dump output are
2607+
// detailed and just not '{pointer}'.
2608+
if let ty::RawPtr(_) = self.literal.ty.kind {
2609+
write!(fmt, "{:?} : {}", self.literal.val, self.literal.ty)
2610+
} else {
2611+
write!(fmt, "{}", self.literal)
2612+
}
26062613
}
26072614
}
26082615

src/librustc/ty/print/pretty.rs

+107-111
Original file line numberDiff line numberDiff line change
@@ -863,125 +863,121 @@ pub trait PrettyPrinter<'tcx>:
863863
}
864864

865865
let u8 = self.tcx().types.u8;
866-
if let ty::FnDef(did, substs) = ct.ty.kind {
867-
p!(print_value_path(did, substs));
868-
return Ok(self);
869-
}
870-
if let ConstValue::Unevaluated(did, substs) = ct.val {
871-
match self.tcx().def_kind(did) {
872-
| Some(DefKind::Static)
873-
| Some(DefKind::Const)
874-
| Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
875-
_ => if did.is_local() {
876-
let span = self.tcx().def_span(did);
877-
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
878-
p!(write("{}", snip))
866+
867+
match (ct.val, &ct.ty.kind) {
868+
(_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
869+
(ConstValue::Unevaluated(did, substs), _) => {
870+
match self.tcx().def_kind(did) {
871+
| Some(DefKind::Static)
872+
| Some(DefKind::Const)
873+
| Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
874+
_ => if did.is_local() {
875+
let span = self.tcx().def_span(did);
876+
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
877+
p!(write("{}", snip))
878+
} else {
879+
p!(write("_: "), print(ct.ty))
880+
}
879881
} else {
880882
p!(write("_: "), print(ct.ty))
881-
}
883+
},
884+
}
885+
},
886+
(ConstValue::Infer(..), _) => p!(write("_: "), print(ct.ty)),
887+
(ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
888+
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) =>
889+
p!(write("{}", if data == 0 { "false" } else { "true" })),
890+
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) =>
891+
p!(write("{}f32", Single::from_bits(data))),
892+
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) =>
893+
p!(write("{}f64", Double::from_bits(data))),
894+
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => {
895+
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
896+
let max = truncate(u128::max_value(), bit_size);
897+
898+
if data == max {
899+
p!(write("std::{}::MAX", ui))
882900
} else {
883-
p!(write("_: "), print(ct.ty))
884-
},
885-
}
886-
return Ok(self);
887-
}
888-
if let ConstValue::Infer(..) = ct.val {
889-
p!(write("_: "), print(ct.ty));
890-
return Ok(self);
891-
}
892-
if let ConstValue::Param(ParamConst { name, .. }) = ct.val {
893-
p!(write("{}", name));
894-
return Ok(self);
895-
}
896-
if let ConstValue::Scalar(Scalar::Raw { data, .. }) = ct.val {
897-
match ct.ty.kind {
898-
ty::Bool => {
899-
p!(write("{}", if data == 0 { "false" } else { "true" }));
900-
return Ok(self);
901-
},
902-
ty::Float(ast::FloatTy::F32) => {
903-
p!(write("{}f32", Single::from_bits(data)));
904-
return Ok(self);
905-
},
906-
ty::Float(ast::FloatTy::F64) => {
907-
p!(write("{}f64", Double::from_bits(data)));
908-
return Ok(self);
909-
},
910-
ty::Uint(ui) => {
911-
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(ui)).size();
912-
let max = truncate(u128::max_value(), bit_size);
901+
p!(write("{}{}", data, ui))
902+
};
903+
},
904+
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => {
905+
let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i))
906+
.size().bits() as u128;
907+
let min = 1u128 << (bit_size - 1);
908+
let max = min - 1;
909+
910+
let ty = self.tcx().lift(&ct.ty).unwrap();
911+
let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
912+
.unwrap()
913+
.size;
914+
match data {
915+
d if d == min => p!(write("std::{}::MIN", i)),
916+
d if d == max => p!(write("std::{}::MAX", i)),
917+
_ => p!(write("{}{}", sign_extend(data, size) as i128, i))
918+
}
919+
},
920+
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) =>
921+
p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())),
922+
(ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")),
923+
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => {
924+
let instance = {
925+
let alloc_map = self.tcx().alloc_map.lock();
926+
alloc_map.unwrap_fn(ptr.alloc_id)
927+
};
928+
p!(print_value_path(instance.def_id(), instance.substs));
929+
},
930+
_ => {
931+
let printed = if let ty::Ref(_, ref_ty, _) = ct.ty.kind {
932+
let byte_str = match (ct.val, &ref_ty.kind) {
933+
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
934+
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
935+
Some(self.tcx()
936+
.alloc_map.lock()
937+
.unwrap_memory(ptr.alloc_id)
938+
.get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
939+
},
940+
(ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
941+
// The `inspect` here is okay since we checked the bounds, and there are
942+
// no relocations (we have an active slice reference here). We don't use
943+
// this result to affect interpreter execution.
944+
Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
945+
},
946+
_ => None,
947+
};
913948

914-
if data == max {
915-
p!(write("std::{}::MAX", ui))
949+
if let Some(byte_str) = byte_str {
950+
p!(write("b\""));
951+
for &c in byte_str {
952+
for e in std::ascii::escape_default(c) {
953+
self.write_char(e as char)?;
954+
}
955+
}
956+
p!(write("\""));
957+
true
958+
} else if let (ConstValue::Slice { data, start, end }, ty::Str) =
959+
(ct.val, &ref_ty.kind)
960+
{
961+
// The `inspect` here is okay since we checked the bounds, and there are no
962+
// relocations (we have an active `str` reference here). We don't use this
963+
// result to affect interpreter execution.
964+
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
965+
let s = ::std::str::from_utf8(slice)
966+
.expect("non utf8 str from miri");
967+
p!(write("{:?}", s));
968+
true
916969
} else {
917-
p!(write("{}{}", data, ui))
918-
};
919-
return Ok(self);
920-
},
921-
ty::Int(i) =>{
922-
let bit_size = Integer::from_attr(&self.tcx(), SignedInt(i))
923-
.size().bits() as u128;
924-
let min = 1u128 << (bit_size - 1);
925-
let max = min - 1;
926-
927-
let ty = self.tcx().lift(&ct.ty).unwrap();
928-
let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
929-
.unwrap()
930-
.size;
931-
match data {
932-
d if d == min => p!(write("std::{}::MIN", i)),
933-
d if d == max => p!(write("std::{}::MAX", i)),
934-
_ => p!(write("{}{}", sign_extend(data, size) as i128, i))
935-
}
936-
return Ok(self);
937-
},
938-
ty::Char => {
939-
p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap()));
940-
return Ok(self);
941-
}
942-
_ => {},
943-
}
944-
}
945-
if let ty::Ref(_, ref_ty, _) = ct.ty.kind {
946-
let byte_str = match (ct.val, &ref_ty.kind) {
947-
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
948-
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
949-
Some(self.tcx()
950-
.alloc_map.lock()
951-
.unwrap_memory(ptr.alloc_id)
952-
.get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
953-
},
954-
(ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
955-
// The `inspect` here is okay since we checked the bounds, and there are no
956-
// relocations (we have an active slice reference here). We don't use this
957-
// result to affect interpreter execution.
958-
Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
959-
},
960-
(ConstValue::Slice { data, start, end }, ty::Str) => {
961-
// The `inspect` here is okay since we checked the bounds, and there are no
962-
// relocations (we have an active `str` reference here). We don't use this
963-
// result to affect interpreter execution.
964-
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
965-
let s = ::std::str::from_utf8(slice)
966-
.expect("non utf8 str from miri");
967-
p!(write("{:?}", s));
968-
return Ok(self);
969-
},
970-
_ => None,
971-
};
972-
if let Some(byte_str) = byte_str {
973-
p!(write("b\""));
974-
for &c in byte_str {
975-
for e in std::ascii::escape_default(c) {
976-
self.write_char(e as char)?;
970+
false
977971
}
972+
} else {
973+
false
974+
};
975+
if !printed {
976+
// fallback
977+
p!(write("{:?} : ", ct.val), print(ct.ty))
978978
}
979-
p!(write("\""));
980-
return Ok(self);
981979
}
982-
}
983-
p!(write("{:?} : ", ct.val), print(ct.ty));
984-
980+
};
985981
Ok(self)
986982
}
987983
}

src/librustc/ty/relate.rs

+30-28
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::hir::def_id::DefId;
88
use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
99
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
1010
use crate::ty::error::{ExpectedFound, TypeError};
11-
use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar};
11+
use crate::mir::interpret::{ConstValue, get_slice_bytes};
1212
use std::rc::Rc;
1313
use std::iter;
1414
use rustc_target::spec::abi;
@@ -561,37 +561,39 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
561561
// implement both `PartialEq` and `Eq`, corresponding to
562562
// `structural_match` types.
563563
// FIXME(const_generics): check for `structural_match` synthetic attribute.
564-
match (eagerly_eval(a), eagerly_eval(b)) {
564+
let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) {
565565
(ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
566566
// The caller should handle these cases!
567567
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
568568
}
569569
(ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => {
570-
Ok(a)
570+
return Ok(a);
571571
}
572572
(ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => {
573-
Ok(a)
573+
return Ok(a);
574574
}
575-
(a_val @ ConstValue::Scalar(Scalar::Raw { .. }), b_val @ _)
576-
if a.ty == b.ty && a_val == b_val =>
577-
{
578-
Ok(tcx.mk_const(ty::Const {
579-
val: a_val,
580-
ty: a.ty,
581-
}))
575+
(ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => {
576+
if a_val == b_val {
577+
Ok(ConstValue::Scalar(a_val))
578+
} else if let ty::FnPtr(_) = a.ty.kind {
579+
let alloc_map = tcx.alloc_map.lock();
580+
let a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id);
581+
let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id);
582+
if a_instance == b_instance {
583+
Ok(ConstValue::Scalar(a_val))
584+
} else {
585+
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
586+
}
587+
} else {
588+
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
589+
}
582590
}
583591

584-
// FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment
585-
// saying that we're not handling it intentionally.
586-
587592
(a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => {
588593
let a_bytes = get_slice_bytes(&tcx, a_val);
589594
let b_bytes = get_slice_bytes(&tcx, b_val);
590595
if a_bytes == b_bytes {
591-
Ok(tcx.mk_const(ty::Const {
592-
val: a_val,
593-
ty: a.ty,
594-
}))
596+
Ok(a_val)
595597
} else {
596598
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
597599
}
@@ -602,16 +604,16 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
602604
// FIXME(const_generics): this is wrong, as it is a projection
603605
(ConstValue::Unevaluated(a_def_id, a_substs),
604606
ConstValue::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => {
605-
let substs =
606-
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
607-
Ok(tcx.mk_const(ty::Const {
608-
val: ConstValue::Unevaluated(a_def_id, &substs),
609-
ty: a.ty,
610-
}))
611-
}
612-
613-
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
614-
}
607+
let substs =
608+
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
609+
Ok(ConstValue::Unevaluated(a_def_id, &substs))
610+
}
611+
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
612+
};
613+
new_const_val.map(|val| tcx.mk_const(ty::Const {
614+
val,
615+
ty: a.ty,
616+
}))
615617
}
616618

617619
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {

src/librustc_mir/monomorphize/collector.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,14 @@ fn collect_const<'tcx>(
12721272
) {
12731273
debug!("visiting const {:?}", constant);
12741274

1275-
match constant.val {
1275+
let param_env = ty::ParamEnv::reveal_all();
1276+
let substituted_constant = tcx.subst_and_normalize_erasing_regions(
1277+
param_substs,
1278+
param_env,
1279+
&constant,
1280+
);
1281+
1282+
match substituted_constant.val {
12761283
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
12771284
collect_miri(tcx, ptr.alloc_id, output),
12781285
ConstValue::Slice { data: alloc, start: _, end: _ } |
@@ -1282,12 +1289,6 @@ fn collect_const<'tcx>(
12821289
}
12831290
}
12841291
ConstValue::Unevaluated(def_id, substs) => {
1285-
let param_env = ty::ParamEnv::reveal_all();
1286-
let substs = tcx.subst_and_normalize_erasing_regions(
1287-
param_substs,
1288-
param_env,
1289-
&substs,
1290-
);
12911292
let instance = ty::Instance::resolve(tcx,
12921293
param_env,
12931294
def_id,
@@ -1304,7 +1305,7 @@ fn collect_const<'tcx>(
13041305
tcx.def_span(def_id), "collection encountered polymorphic constant",
13051306
),
13061307
}
1307-
}
1308+
},
13081309
_ => {},
13091310
}
13101311
}

0 commit comments

Comments
 (0)