Skip to content

Commit 2afd277

Browse files
committed
Fix calling function pointer const parameters. Also fixes inference of
function pointer const parameters.
1 parent ec557aa commit 2afd277

File tree

6 files changed

+145
-30
lines changed

6 files changed

+145
-30
lines changed

src/librustc/ty/relate.rs

Lines changed: 38 additions & 28 deletions
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, Scalar, GlobalAlloc};
1212
use std::rc::Rc;
1313
use std::iter;
1414
use rustc_target::spec::abi;
@@ -561,37 +561,47 @@ 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 get_fn_instance = |val: Scalar| {
581+
let ptr = val.to_ptr().unwrap();
582+
if let Some(GlobalAlloc::Function(instance)) = alloc_map.get(ptr.alloc_id) {
583+
instance
584+
} else {
585+
bug!("Allocation for FnPtr isn't a function");
586+
}
587+
};
588+
let a_instance = get_fn_instance(a_val);
589+
let b_instance = get_fn_instance(b_val);
590+
if a_instance == b_instance {
591+
Ok(ConstValue::Scalar(a_val))
592+
} else {
593+
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
594+
}
595+
} else {
596+
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
597+
}
582598
}
583599

584-
// FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment
585-
// saying that we're not handling it intentionally.
586-
587600
(a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => {
588601
let a_bytes = get_slice_bytes(&tcx, a_val);
589602
let b_bytes = get_slice_bytes(&tcx, b_val);
590603
if a_bytes == b_bytes {
591-
Ok(tcx.mk_const(ty::Const {
592-
val: a_val,
593-
ty: a.ty,
594-
}))
604+
Ok(a_val)
595605
} else {
596606
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
597607
}
@@ -602,16 +612,16 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
602612
// FIXME(const_generics): this is wrong, as it is a projection
603613
(ConstValue::Unevaluated(a_def_id, a_substs),
604614
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-
}
615+
let substs =
616+
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
617+
Ok(ConstValue::Unevaluated(a_def_id, &substs))
618+
}
619+
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
620+
};
621+
new_const_val.map(|val| tcx.mk_const(ty::Const {
622+
val,
623+
ty: a.ty,
624+
}))
615625
}
616626

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

src/librustc_mir/monomorphize/collector.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,13 @@ fn collect_const<'tcx>(
12651265
) {
12661266
debug!("visiting const {:?}", constant);
12671267

1268-
match constant.val {
1268+
let substituted_constant = if let ConstValue::Param(param) = constant.val {
1269+
param_substs.const_at(param.index as usize)
1270+
} else {
1271+
constant
1272+
};
1273+
1274+
match substituted_constant.val {
12691275
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
12701276
collect_miri(tcx, ptr.alloc_id, output),
12711277
ConstValue::Slice { data: alloc, start: _, end: _ } |
@@ -1297,7 +1303,7 @@ fn collect_const<'tcx>(
12971303
tcx.def_span(def_id), "collection encountered polymorphic constant",
12981304
),
12991305
}
1300-
}
1306+
},
13011307
_ => {},
13021308
}
13031309
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-pass
2+
3+
#![feature(const_generics)]
4+
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
5+
6+
fn function() -> u32 {
7+
17
8+
}
9+
10+
struct Wrapper<const F: fn() -> u32>;
11+
12+
impl<const F: fn() -> u32> Wrapper<{F}> {
13+
fn call() -> u32 {
14+
F()
15+
}
16+
}
17+
18+
fn main() {
19+
assert_eq!(Wrapper::<{function}>::call(), 17);
20+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
2+
--> $DIR/fn-const-param-call.rs:3:12
3+
|
4+
LL | #![feature(const_generics)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![feature(const_generics)]
2+
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
3+
4+
struct Checked<const F: fn(usize) -> bool>;
5+
6+
fn not_one(val: usize) -> bool { val != 1 }
7+
fn not_two(val: usize) -> bool { val != 2 }
8+
9+
fn generic_arg<T>(val: T) -> bool { true }
10+
11+
fn generic<T>(val: usize) -> bool { val != 1 }
12+
13+
fn main() {
14+
let _: Option<Checked<{not_one}>> = None;
15+
let _: Checked<{not_one}> = Checked::<{not_one}>;
16+
let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types
17+
18+
let _ = Checked::<{generic_arg}>;
19+
let _ = Checked::<{generic_arg::<usize>}>;
20+
let _ = Checked::<{generic_arg::<u32>}>; //~ mismatched types
21+
22+
let _ = Checked::<{generic}>; //~ type annotations needed
23+
let _ = Checked::<{generic::<u16>}>;
24+
let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
25+
let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
26+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
2+
--> $DIR/fn-const-param-infer.rs:1:12
3+
|
4+
LL | #![feature(const_generics)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/fn-const-param-infer.rs:16:33
11+
|
12+
LL | let _: Checked<{not_one}> = Checked::<{not_two}>;
13+
| ^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(1).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(10).0x0) : fn(usize) -> bool`
14+
|
15+
= note: expected type `Checked<>`
16+
found type `Checked<>`
17+
18+
error[E0308]: mismatched types
19+
--> $DIR/fn-const-param-infer.rs:20:24
20+
|
21+
LL | let _ = Checked::<{generic_arg::<u32>}>;
22+
| ^^^^^^^^^^^^^^^^^^ expected usize, found u32
23+
|
24+
= note: expected type `fn(usize) -> bool`
25+
found type `fn(u32) -> bool {generic_arg::<u32>}`
26+
27+
error[E0282]: type annotations needed
28+
--> $DIR/fn-const-param-infer.rs:22:24
29+
|
30+
LL | let _ = Checked::<{generic}>;
31+
| ^^^^^^^ cannot infer type for `T`
32+
33+
error[E0308]: mismatched types
34+
--> $DIR/fn-const-param-infer.rs:25:40
35+
|
36+
LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(7).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(20).0x0) : fn(usize) -> bool`
38+
|
39+
= note: expected type `Checked<>`
40+
found type `Checked<>`
41+
42+
error: aborting due to 4 previous errors
43+
44+
Some errors have detailed explanations: E0282, E0308.
45+
For more information about an error, try `rustc --explain E0282`.

0 commit comments

Comments
 (0)