Fix calling function pointer const parameters. Also fixes inference of

function pointer const parameters.
This commit is contained in:
ben 2019-10-01 17:55:26 +13:00
parent ec557aa818
commit 2afd277bc3
6 changed files with 145 additions and 30 deletions

View File

@ -8,7 +8,7 @@
use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::error::{ExpectedFound, TypeError};
use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar};
use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar, GlobalAlloc};
use std::rc::Rc;
use std::iter;
use rustc_target::spec::abi;
@ -561,37 +561,47 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
// implement both `PartialEq` and `Eq`, corresponding to
// `structural_match` types.
// FIXME(const_generics): check for `structural_match` synthetic attribute.
match (eagerly_eval(a), eagerly_eval(b)) {
let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) {
(ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
// The caller should handle these cases!
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
}
(ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => {
Ok(a)
return Ok(a);
}
(ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => {
Ok(a)
return Ok(a);
}
(a_val @ ConstValue::Scalar(Scalar::Raw { .. }), b_val @ _)
if a.ty == b.ty && a_val == b_val =>
{
Ok(tcx.mk_const(ty::Const {
val: a_val,
ty: a.ty,
}))
(ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => {
if a_val == b_val {
Ok(ConstValue::Scalar(a_val))
} else if let ty::FnPtr(_) = a.ty.kind {
let alloc_map = tcx.alloc_map.lock();
let get_fn_instance = |val: Scalar| {
let ptr = val.to_ptr().unwrap();
if let Some(GlobalAlloc::Function(instance)) = alloc_map.get(ptr.alloc_id) {
instance
} else {
bug!("Allocation for FnPtr isn't a function");
}
};
let a_instance = get_fn_instance(a_val);
let b_instance = get_fn_instance(b_val);
if a_instance == b_instance {
Ok(ConstValue::Scalar(a_val))
} else {
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
}
} else {
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
}
}
// FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment
// saying that we're not handling it intentionally.
(a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => {
let a_bytes = get_slice_bytes(&tcx, a_val);
let b_bytes = get_slice_bytes(&tcx, b_val);
if a_bytes == b_bytes {
Ok(tcx.mk_const(ty::Const {
val: a_val,
ty: a.ty,
}))
Ok(a_val)
} else {
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
}
@ -602,16 +612,16 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
// FIXME(const_generics): this is wrong, as it is a projection
(ConstValue::Unevaluated(a_def_id, a_substs),
ConstValue::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => {
let substs =
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
Ok(tcx.mk_const(ty::Const {
val: ConstValue::Unevaluated(a_def_id, &substs),
ty: a.ty,
}))
}
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
}
let substs =
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
Ok(ConstValue::Unevaluated(a_def_id, &substs))
}
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
};
new_const_val.map(|val| tcx.mk_const(ty::Const {
val,
ty: a.ty,
}))
}
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {

View File

@ -1265,7 +1265,13 @@ fn collect_const<'tcx>(
) {
debug!("visiting const {:?}", constant);
match constant.val {
let substituted_constant = if let ConstValue::Param(param) = constant.val {
param_substs.const_at(param.index as usize)
} else {
constant
};
match substituted_constant.val {
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
ConstValue::Slice { data: alloc, start: _, end: _ } |
@ -1297,7 +1303,7 @@ fn collect_const<'tcx>(
tcx.def_span(def_id), "collection encountered polymorphic constant",
),
}
}
},
_ => {},
}
}

View File

@ -0,0 +1,20 @@
// run-pass
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn function() -> u32 {
17
}
struct Wrapper<const F: fn() -> u32>;
impl<const F: fn() -> u32> Wrapper<{F}> {
fn call() -> u32 {
F()
}
}
fn main() {
assert_eq!(Wrapper::<{function}>::call(), 17);
}

View File

@ -0,0 +1,8 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/fn-const-param-call.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default

View File

@ -0,0 +1,26 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
struct Checked<const F: fn(usize) -> bool>;
fn not_one(val: usize) -> bool { val != 1 }
fn not_two(val: usize) -> bool { val != 2 }
fn generic_arg<T>(val: T) -> bool { true }
fn generic<T>(val: usize) -> bool { val != 1 }
fn main() {
let _: Option<Checked<{not_one}>> = None;
let _: Checked<{not_one}> = Checked::<{not_one}>;
let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types
let _ = Checked::<{generic_arg}>;
let _ = Checked::<{generic_arg::<usize>}>;
let _ = Checked::<{generic_arg::<u32>}>; //~ mismatched types
let _ = Checked::<{generic}>; //~ type annotations needed
let _ = Checked::<{generic::<u16>}>;
let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
}

View File

@ -0,0 +1,45 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/fn-const-param-infer.rs:1:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:16:33
|
LL | let _: Checked<{not_one}> = Checked::<{not_two}>;
| ^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(1).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(10).0x0) : fn(usize) -> bool`
|
= note: expected type `Checked<>`
found type `Checked<>`
error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:20:24
|
LL | let _ = Checked::<{generic_arg::<u32>}>;
| ^^^^^^^^^^^^^^^^^^ expected usize, found u32
|
= note: expected type `fn(usize) -> bool`
found type `fn(u32) -> bool {generic_arg::<u32>}`
error[E0282]: type annotations needed
--> $DIR/fn-const-param-infer.rs:22:24
|
LL | let _ = Checked::<{generic}>;
| ^^^^^^^ cannot infer type for `T`
error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:25:40
|
LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(7).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(20).0x0) : fn(usize) -> bool`
|
= note: expected type `Checked<>`
found type `Checked<>`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.