Rollup merge of #64986 - skinny121:fn-ptr-const-generics, r=varkor
Function pointers as const generic arguments Makes function pointers as const generic arguments usable. Fixes #62395 r? @varkor
This commit is contained in:
commit
ea0d155f2d
17 changed files with 391 additions and 154 deletions
|
@ -470,6 +470,14 @@ impl<'tcx> AllocMap<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Panics if the `AllocId` does not refer to a function
|
||||
pub fn unwrap_fn(&self, id: AllocId) -> Instance<'tcx> {
|
||||
match self.get(id) {
|
||||
Some(GlobalAlloc::Function(instance)) => instance,
|
||||
_ => bug!("expected allocation ID {} to point to a function", id),
|
||||
}
|
||||
}
|
||||
|
||||
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
|
||||
/// call this function twice, even with the same `Allocation` will ICE the compiler.
|
||||
pub fn set_alloc_id_memory(&mut self, id: AllocId, mem: &'tcx Allocation) {
|
||||
|
|
|
@ -2602,9 +2602,16 @@ impl<'tcx> Debug for Constant<'tcx> {
|
|||
impl<'tcx> Display for Constant<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "const ")?;
|
||||
// FIXME make the default pretty printing of raw pointers more detailed. Here we output the
|
||||
// debug representation of raw pointers, so that the raw pointers in the mir dump output are
|
||||
// detailed and just not '{pointer}'.
|
||||
if let ty::RawPtr(_) = self.literal.ty.kind {
|
||||
write!(fmt, "{:?} : {}", self.literal.val, self.literal.ty)
|
||||
} else {
|
||||
write!(fmt, "{}", self.literal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::DirectedGraph for Body<'tcx> {
|
||||
type Node = BasicBlock;
|
||||
|
|
|
@ -863,11 +863,10 @@ pub trait PrettyPrinter<'tcx>:
|
|||
}
|
||||
|
||||
let u8 = self.tcx().types.u8;
|
||||
if let ty::FnDef(did, substs) = ct.ty.kind {
|
||||
p!(print_value_path(did, substs));
|
||||
return Ok(self);
|
||||
}
|
||||
if let ConstValue::Unevaluated(did, substs) = ct.val {
|
||||
|
||||
match (ct.val, &ct.ty.kind) {
|
||||
(_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
|
||||
(ConstValue::Unevaluated(did, substs), _) => {
|
||||
match self.tcx().def_kind(did) {
|
||||
| Some(DefKind::Static)
|
||||
| Some(DefKind::Const)
|
||||
|
@ -883,32 +882,17 @@ pub trait PrettyPrinter<'tcx>:
|
|||
p!(write("_: "), print(ct.ty))
|
||||
},
|
||||
}
|
||||
return Ok(self);
|
||||
}
|
||||
if let ConstValue::Infer(..) = ct.val {
|
||||
p!(write("_: "), print(ct.ty));
|
||||
return Ok(self);
|
||||
}
|
||||
if let ConstValue::Param(ParamConst { name, .. }) = ct.val {
|
||||
p!(write("{}", name));
|
||||
return Ok(self);
|
||||
}
|
||||
if let ConstValue::Scalar(Scalar::Raw { data, .. }) = ct.val {
|
||||
match ct.ty.kind {
|
||||
ty::Bool => {
|
||||
p!(write("{}", if data == 0 { "false" } else { "true" }));
|
||||
return Ok(self);
|
||||
},
|
||||
ty::Float(ast::FloatTy::F32) => {
|
||||
p!(write("{}f32", Single::from_bits(data)));
|
||||
return Ok(self);
|
||||
},
|
||||
ty::Float(ast::FloatTy::F64) => {
|
||||
p!(write("{}f64", Double::from_bits(data)));
|
||||
return Ok(self);
|
||||
},
|
||||
ty::Uint(ui) => {
|
||||
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(ui)).size();
|
||||
(ConstValue::Infer(..), _) => p!(write("_: "), print(ct.ty)),
|
||||
(ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
|
||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) =>
|
||||
p!(write("{}", if data == 0 { "false" } else { "true" })),
|
||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) =>
|
||||
p!(write("{}f32", Single::from_bits(data))),
|
||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) =>
|
||||
p!(write("{}f64", Double::from_bits(data))),
|
||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => {
|
||||
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
|
||||
let max = truncate(u128::max_value(), bit_size);
|
||||
|
||||
if data == max {
|
||||
|
@ -916,10 +900,9 @@ pub trait PrettyPrinter<'tcx>:
|
|||
} else {
|
||||
p!(write("{}{}", data, ui))
|
||||
};
|
||||
return Ok(self);
|
||||
},
|
||||
ty::Int(i) =>{
|
||||
let bit_size = Integer::from_attr(&self.tcx(), SignedInt(i))
|
||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => {
|
||||
let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i))
|
||||
.size().bits() as u128;
|
||||
let min = 1u128 << (bit_size - 1);
|
||||
let max = min - 1;
|
||||
|
@ -933,16 +916,19 @@ pub trait PrettyPrinter<'tcx>:
|
|||
d if d == max => p!(write("std::{}::MAX", i)),
|
||||
_ => p!(write("{}{}", sign_extend(data, size) as i128, i))
|
||||
}
|
||||
return Ok(self);
|
||||
},
|
||||
ty::Char => {
|
||||
p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap()));
|
||||
return Ok(self);
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
if let ty::Ref(_, ref_ty, _) = ct.ty.kind {
|
||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) =>
|
||||
p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())),
|
||||
(ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")),
|
||||
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => {
|
||||
let instance = {
|
||||
let alloc_map = self.tcx().alloc_map.lock();
|
||||
alloc_map.unwrap_fn(ptr.alloc_id)
|
||||
};
|
||||
p!(print_value_path(instance.def_id(), instance.substs));
|
||||
},
|
||||
_ => {
|
||||
let printed = if let ty::Ref(_, ref_ty, _) = ct.ty.kind {
|
||||
let byte_str = match (ct.val, &ref_ty.kind) {
|
||||
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
|
||||
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
|
||||
|
@ -952,23 +938,14 @@ pub trait PrettyPrinter<'tcx>:
|
|||
.get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
|
||||
},
|
||||
(ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
|
||||
// The `inspect` here is okay since we checked the bounds, and there are no
|
||||
// relocations (we have an active slice reference here). We don't use this
|
||||
// result to affect interpreter execution.
|
||||
// The `inspect` here is okay since we checked the bounds, and there are
|
||||
// no relocations (we have an active slice reference here). We don't use
|
||||
// this result to affect interpreter execution.
|
||||
Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
|
||||
},
|
||||
(ConstValue::Slice { data, start, end }, ty::Str) => {
|
||||
// The `inspect` here is okay since we checked the bounds, and there are no
|
||||
// relocations (we have an active `str` reference here). We don't use this
|
||||
// result to affect interpreter execution.
|
||||
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
|
||||
let s = ::std::str::from_utf8(slice)
|
||||
.expect("non utf8 str from miri");
|
||||
p!(write("{:?}", s));
|
||||
return Ok(self);
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(byte_str) = byte_str {
|
||||
p!(write("b\""));
|
||||
for &c in byte_str {
|
||||
|
@ -977,11 +954,30 @@ pub trait PrettyPrinter<'tcx>:
|
|||
}
|
||||
}
|
||||
p!(write("\""));
|
||||
return Ok(self);
|
||||
true
|
||||
} else if let (ConstValue::Slice { data, start, end }, ty::Str) =
|
||||
(ct.val, &ref_ty.kind)
|
||||
{
|
||||
// The `inspect` here is okay since we checked the bounds, and there are no
|
||||
// relocations (we have an active `str` reference here). We don't use this
|
||||
// result to affect interpreter execution.
|
||||
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
|
||||
let s = ::std::str::from_utf8(slice)
|
||||
.expect("non utf8 str from miri");
|
||||
p!(write("{:?}", s));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if !printed {
|
||||
// fallback
|
||||
p!(write("{:?} : ", ct.val), print(ct.ty))
|
||||
}
|
||||
}
|
||||
p!(write("{:?} : ", ct.val), print(ct.ty));
|
||||
|
||||
};
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::hir::def_id::DefId;
|
|||
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};
|
||||
use std::rc::Rc;
|
||||
use std::iter;
|
||||
use rustc_target::spec::abi;
|
||||
|
@ -561,37 +561,39 @@ 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);
|
||||
}
|
||||
(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 a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id);
|
||||
let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id);
|
||||
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)))
|
||||
}
|
||||
(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,
|
||||
}))
|
||||
}
|
||||
|
||||
// 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)))
|
||||
}
|
||||
|
@ -604,16 +606,16 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
|
|||
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),
|
||||
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,
|
||||
}))
|
||||
}
|
||||
|
||||
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
|
|
|
@ -1272,7 +1272,14 @@ fn collect_const<'tcx>(
|
|||
) {
|
||||
debug!("visiting const {:?}", constant);
|
||||
|
||||
match constant.val {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let substituted_constant = tcx.subst_and_normalize_erasing_regions(
|
||||
param_substs,
|
||||
param_env,
|
||||
&constant,
|
||||
);
|
||||
|
||||
match substituted_constant.val {
|
||||
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
|
||||
collect_miri(tcx, ptr.alloc_id, output),
|
||||
ConstValue::Slice { data: alloc, start: _, end: _ } |
|
||||
|
@ -1282,12 +1289,6 @@ fn collect_const<'tcx>(
|
|||
}
|
||||
}
|
||||
ConstValue::Unevaluated(def_id, substs) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let substs = tcx.subst_and_normalize_erasing_regions(
|
||||
param_substs,
|
||||
param_env,
|
||||
&substs,
|
||||
);
|
||||
let instance = ty::Instance::resolve(tcx,
|
||||
param_env,
|
||||
def_id,
|
||||
|
@ -1304,7 +1305,7 @@ fn collect_const<'tcx>(
|
|||
tcx.def_span(def_id), "collection encountered polymorphic constant",
|
||||
),
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1508,9 +1508,29 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
|
|||
}
|
||||
|
||||
Node::GenericParam(param) => match ¶m.kind {
|
||||
hir::GenericParamKind::Type { default: Some(ref ty), .. } |
|
||||
hir::GenericParamKind::Const { ref ty, .. } => {
|
||||
icx.to_ty(ty)
|
||||
hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
|
||||
hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
|
||||
let ty = icx.to_ty(hir_ty);
|
||||
if !tcx.features().const_compare_raw_pointers {
|
||||
let err = match ty.peel_refs().kind {
|
||||
ty::FnPtr(_) => Some("function pointers"),
|
||||
ty::RawPtr(_) => Some("raw pointers"),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(unsupported_type) = err {
|
||||
feature_gate::emit_feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::const_compare_raw_pointers,
|
||||
hir_ty.span,
|
||||
feature_gate::GateIssue::Language,
|
||||
&format!(
|
||||
"using {} as const generic parameters is unstable",
|
||||
unsupported_type
|
||||
),
|
||||
);
|
||||
};
|
||||
}
|
||||
ty
|
||||
}
|
||||
x => {
|
||||
if !fail {
|
||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
|||
// START rustc.main.ConstProp.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _3 = const Scalar(AllocId(0).0x0) : fn();
|
||||
// _3 = const main;
|
||||
// _2 = move _3 as usize (Misc);
|
||||
// ...
|
||||
// _1 = move _2 as *const fn() (Misc);
|
||||
|
|
20
src/test/ui/const-generics/fn-const-param-call.rs
Normal file
20
src/test/ui/const-generics/fn-const-param-call.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(const_generics, const_compare_raw_pointers)]
|
||||
//~^ 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);
|
||||
}
|
8
src/test/ui/const-generics/fn-const-param-call.stderr
Normal file
8
src/test/ui/const-generics/fn-const-param-call.stderr
Normal 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, const_compare_raw_pointers)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
26
src/test/ui/const-generics/fn-const-param-infer.rs
Normal file
26
src/test/ui/const-generics/fn-const-param-infer.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
#![feature(const_generics, const_compare_raw_pointers)]
|
||||
//~^ 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
|
||||
}
|
45
src/test/ui/const-generics/fn-const-param-infer.stderr
Normal file
45
src/test/ui/const-generics/fn-const-param-infer.stderr
Normal 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, const_compare_raw_pointers)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= 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 `not_one`, found `not_two`
|
||||
|
|
||||
= note: expected type `Checked<not_one>`
|
||||
found type `Checked<not_two>`
|
||||
|
||||
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 `generic::<u32>`, found `generic::<u16>`
|
||||
|
|
||||
= note: expected type `Checked<generic::<u32>>`
|
||||
found type `Checked<generic::<u16>>`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0282, E0308.
|
||||
For more information about an error, try `rustc --explain E0282`.
|
19
src/test/ui/const-generics/raw-ptr-const-param-deref.rs
Normal file
19
src/test/ui/const-generics/raw-ptr-const-param-deref.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// run-pass
|
||||
#![feature(const_generics, const_compare_raw_pointers)]
|
||||
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
|
||||
const A: u32 = 3;
|
||||
|
||||
struct Const<const P: *const u32>;
|
||||
|
||||
impl<const P: *const u32> Const<{P}> {
|
||||
fn get() -> u32 {
|
||||
unsafe {
|
||||
*P
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(Const::<{&A as *const _}>::get(), 3)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/raw-ptr-const-param-deref.rs:2:12
|
||||
|
|
||||
LL | #![feature(const_generics, const_compare_raw_pointers)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
9
src/test/ui/const-generics/raw-ptr-const-param.rs
Normal file
9
src/test/ui/const-generics/raw-ptr-const-param.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
#![feature(const_generics, const_compare_raw_pointers)]
|
||||
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
|
||||
struct Const<const P: *const u32>;
|
||||
|
||||
fn main() {
|
||||
let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; //~ mismatched types
|
||||
let _: Const<{10 as *const _}> = Const::<{10 as *const _}>;
|
||||
}
|
20
src/test/ui/const-generics/raw-ptr-const-param.stderr
Normal file
20
src/test/ui/const-generics/raw-ptr-const-param.stderr
Normal file
|
@ -0,0 +1,20 @@
|
|||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/raw-ptr-const-param.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics, const_compare_raw_pointers)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/raw-ptr-const-param.rs:7:38
|
||||
|
|
||||
LL | let _: Const<{15 as *const _}> = Const::<{10 as *const _}>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{pointer}`, found `{pointer}`
|
||||
|
|
||||
= note: expected type `Const<{pointer}>`
|
||||
found type `Const<{pointer}>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -0,0 +1,9 @@
|
|||
struct ConstFn<const F: fn()>;
|
||||
//~^ ERROR const generics are unstable
|
||||
//~^^ ERROR using function pointers as const generic parameters is unstable
|
||||
|
||||
struct ConstPtr<const P: *const u32>;
|
||||
//~^ ERROR const generics are unstable
|
||||
//~^^ ERROR using raw pointers as const generic parameters is unstable
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,39 @@
|
|||
error[E0658]: const generics are unstable
|
||||
--> $DIR/feature-gate-const_generics-ptr.rs:1:22
|
||||
|
|
||||
LL | struct ConstFn<const F: fn()>;
|
||||
| ^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
|
||||
= help: add `#![feature(const_generics)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: const generics are unstable
|
||||
--> $DIR/feature-gate-const_generics-ptr.rs:5:23
|
||||
|
|
||||
LL | struct ConstPtr<const P: *const u32>;
|
||||
| ^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
|
||||
= help: add `#![feature(const_generics)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: using function pointers as const generic parameters is unstable
|
||||
--> $DIR/feature-gate-const_generics-ptr.rs:1:25
|
||||
|
|
||||
LL | struct ConstFn<const F: fn()>;
|
||||
| ^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/53020
|
||||
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: using raw pointers as const generic parameters is unstable
|
||||
--> $DIR/feature-gate-const_generics-ptr.rs:5:26
|
||||
|
|
||||
LL | struct ConstPtr<const P: *const u32>;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/53020
|
||||
= help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
Loading…
Add table
Reference in a new issue