Deny floats even when adt_const_params is enabled
This commit is contained in:
parent
c396bb3b8a
commit
a1634642e0
7 changed files with 135 additions and 66 deletions
|
@ -226,7 +226,7 @@ impl Qualif for CustomEq {
|
||||||
// because that component may be part of an enum variant (e.g.,
|
// because that component may be part of an enum variant (e.g.,
|
||||||
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
|
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
|
||||||
// structural-match (`Option::None`).
|
// structural-match (`Option::None`).
|
||||||
traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some()
|
traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_adt_inherently<'tcx>(
|
fn in_adt_inherently<'tcx>(
|
||||||
|
|
|
@ -120,32 +120,37 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
|
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
|
||||||
traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
|
traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map(
|
||||||
with_no_trimmed_paths!(match non_sm_ty.kind {
|
|non_sm_ty| {
|
||||||
traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
|
with_no_trimmed_paths!(match non_sm_ty.kind {
|
||||||
traits::NonStructuralMatchTyKind::Dynamic => {
|
traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
|
||||||
"trait objects cannot be used in patterns".to_string()
|
traits::NonStructuralMatchTyKind::Dynamic => {
|
||||||
}
|
"trait objects cannot be used in patterns".to_string()
|
||||||
traits::NonStructuralMatchTyKind::Opaque => {
|
}
|
||||||
"opaque types cannot be used in patterns".to_string()
|
traits::NonStructuralMatchTyKind::Opaque => {
|
||||||
}
|
"opaque types cannot be used in patterns".to_string()
|
||||||
traits::NonStructuralMatchTyKind::Closure => {
|
}
|
||||||
"closures cannot be used in patterns".to_string()
|
traits::NonStructuralMatchTyKind::Closure => {
|
||||||
}
|
"closures cannot be used in patterns".to_string()
|
||||||
traits::NonStructuralMatchTyKind::Generator => {
|
}
|
||||||
"generators cannot be used in patterns".to_string()
|
traits::NonStructuralMatchTyKind::Generator => {
|
||||||
}
|
"generators cannot be used in patterns".to_string()
|
||||||
traits::NonStructuralMatchTyKind::Param => {
|
}
|
||||||
bug!("use of a constant whose type is a parameter inside a pattern")
|
traits::NonStructuralMatchTyKind::Float => {
|
||||||
}
|
"floating-point numbers cannot be used in patterns".to_string()
|
||||||
traits::NonStructuralMatchTyKind::Projection => {
|
}
|
||||||
bug!("use of a constant whose type is a projection inside a pattern")
|
traits::NonStructuralMatchTyKind::Param => {
|
||||||
}
|
bug!("use of a constant whose type is a parameter inside a pattern")
|
||||||
traits::NonStructuralMatchTyKind::Foreign => {
|
}
|
||||||
bug!("use of a value of a foreign type inside a pattern")
|
traits::NonStructuralMatchTyKind::Projection => {
|
||||||
}
|
bug!("use of a constant whose type is a projection inside a pattern")
|
||||||
})
|
}
|
||||||
})
|
traits::NonStructuralMatchTyKind::Foreign => {
|
||||||
|
bug!("use of a value of a foreign type inside a pattern")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
|
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub enum NonStructuralMatchTyKind<'tcx> {
|
||||||
Closure,
|
Closure,
|
||||||
Generator,
|
Generator,
|
||||||
Projection,
|
Projection,
|
||||||
|
Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method traverses the structure of `ty`, trying to find an
|
/// This method traverses the structure of `ty`, trying to find an
|
||||||
|
@ -53,12 +54,16 @@ pub enum NonStructuralMatchTyKind<'tcx> {
|
||||||
/// For more background on why Rust has this requirement, and issues
|
/// For more background on why Rust has this requirement, and issues
|
||||||
/// that arose when the requirement was not enforced completely, see
|
/// that arose when the requirement was not enforced completely, see
|
||||||
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
|
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
|
||||||
|
///
|
||||||
|
/// The floats_allowed flag is used to deny constants in floating point
|
||||||
pub fn search_for_structural_match_violation<'tcx>(
|
pub fn search_for_structural_match_violation<'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
floats_allowed: bool,
|
||||||
) -> Option<NonStructuralMatchTy<'tcx>> {
|
) -> Option<NonStructuralMatchTy<'tcx>> {
|
||||||
ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default() }).break_value()
|
ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed })
|
||||||
|
.break_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method returns true if and only if `adt_ty` itself has been marked as
|
/// This method returns true if and only if `adt_ty` itself has been marked as
|
||||||
|
@ -119,6 +124,8 @@ struct Search<'tcx> {
|
||||||
/// Tracks ADTs previously encountered during search, so that
|
/// Tracks ADTs previously encountered during search, so that
|
||||||
/// we will not recur on them again.
|
/// we will not recur on them again.
|
||||||
seen: FxHashSet<hir::def_id::DefId>,
|
seen: FxHashSet<hir::def_id::DefId>,
|
||||||
|
|
||||||
|
floats_allowed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Search<'tcx> {
|
impl<'tcx> Search<'tcx> {
|
||||||
|
@ -192,13 +199,24 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
|
||||||
// for empty array.
|
// for empty array.
|
||||||
return ControlFlow::CONTINUE;
|
return ControlFlow::CONTINUE;
|
||||||
}
|
}
|
||||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
|
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => {
|
||||||
// These primitive types are always structural match.
|
// These primitive types are always structural match.
|
||||||
//
|
//
|
||||||
// `Never` is kind of special here, but as it is not inhabitable, this should be fine.
|
// `Never` is kind of special here, but as it is not inhabitable, this should be fine.
|
||||||
return ControlFlow::CONTINUE;
|
return ControlFlow::CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::Float(_) => {
|
||||||
|
if self.floats_allowed {
|
||||||
|
return ControlFlow::CONTINUE;
|
||||||
|
} else {
|
||||||
|
return ControlFlow::Break(NonStructuralMatchTy {
|
||||||
|
ty,
|
||||||
|
kind: NonStructuralMatchTyKind::Float,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
|
ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
|
||||||
// First check all contained types and then tell the caller to continue searching.
|
// First check all contained types and then tell the caller to continue searching.
|
||||||
return ty.super_visit_with(self);
|
return ty.super_visit_with(self);
|
||||||
|
|
|
@ -824,50 +824,62 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(non_structural_match_ty) =
|
if let Some(non_structural_match_ty) =
|
||||||
traits::search_for_structural_match_violation(param.span, tcx, ty)
|
traits::search_for_structural_match_violation(param.span, tcx, ty, false)
|
||||||
{
|
{
|
||||||
// We use the same error code in both branches, because this is really the same
|
// We use the same error code in both branches, because this is really the same
|
||||||
// issue: we just special-case the message for type parameters to make it
|
// issue: we just special-case the message for type parameters to make it
|
||||||
// clearer.
|
// clearer.
|
||||||
if let ty::Param(_) = ty.peel_refs().kind() {
|
match ty.peel_refs().kind() {
|
||||||
// Const parameters may not have type parameters as their types,
|
ty::Param(_) => {
|
||||||
// because we cannot be sure that the type parameter derives `PartialEq`
|
// Const parameters may not have type parameters as their types,
|
||||||
// and `Eq` (just implementing them is not enough for `structural_match`).
|
// because we cannot be sure that the type parameter derives `PartialEq`
|
||||||
struct_span_err!(
|
// and `Eq` (just implementing them is not enough for `structural_match`).
|
||||||
tcx.sess,
|
struct_span_err!(
|
||||||
hir_ty.span,
|
tcx.sess,
|
||||||
E0741,
|
|
||||||
"`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
|
|
||||||
used as the type of a const parameter",
|
|
||||||
ty,
|
|
||||||
)
|
|
||||||
.span_label(
|
|
||||||
hir_ty.span,
|
|
||||||
format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
|
|
||||||
)
|
|
||||||
.note(
|
|
||||||
"it is not currently possible to use a type parameter as the type of a \
|
|
||||||
const parameter",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
} else {
|
|
||||||
let mut diag = struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
hir_ty.span,
|
|
||||||
E0741,
|
|
||||||
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
|
|
||||||
the type of a const parameter",
|
|
||||||
non_structural_match_ty.ty,
|
|
||||||
);
|
|
||||||
|
|
||||||
if ty == non_structural_match_ty.ty {
|
|
||||||
diag.span_label(
|
|
||||||
hir_ty.span,
|
hir_ty.span,
|
||||||
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
|
E0741,
|
||||||
);
|
"`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
|
||||||
|
used as the type of a const parameter",
|
||||||
|
)
|
||||||
|
.span_label(
|
||||||
|
hir_ty.span,
|
||||||
|
format!("`{ty}` may not derive both `PartialEq` and `Eq`"),
|
||||||
|
)
|
||||||
|
.note(
|
||||||
|
"it is not currently possible to use a type parameter as the type of a \
|
||||||
|
const parameter",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
|
ty::Float(_) => {
|
||||||
|
struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
hir_ty.span,
|
||||||
|
E0741,
|
||||||
|
"`{ty}` is forbidden as the type of a const generic parameter",
|
||||||
|
)
|
||||||
|
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut diag = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
hir_ty.span,
|
||||||
|
E0741,
|
||||||
|
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
|
||||||
|
the type of a const parameter",
|
||||||
|
non_structural_match_ty.ty,
|
||||||
|
);
|
||||||
|
|
||||||
diag.emit();
|
if ty == non_structural_match_ty.ty {
|
||||||
|
diag.span_label(
|
||||||
|
hir_ty.span,
|
||||||
|
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
diag.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0741]: `f32` is forbidden as the type of a const generic parameter
|
||||||
|
--> $DIR/float-generic.rs:5:17
|
||||||
|
|
|
||||||
|
LL | fn foo<const F: f32>() {}
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= note: floats do not derive `Eq` or `Ord`, which are required for const parameters
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0741`.
|
12
src/test/ui/const-generics/float-generic.rs
Normal file
12
src/test/ui/const-generics/float-generic.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// revisions: simple adt_const_params
|
||||||
|
#![cfg_attr(adt_const_params, feature(adt_const_params))]
|
||||||
|
#![cfg_attr(adt_const_params, allow(incomplete_features))]
|
||||||
|
|
||||||
|
fn foo<const F: f32>() {}
|
||||||
|
//~^ ERROR `f32` is forbidden as the type of a const generic parameter
|
||||||
|
|
||||||
|
const C: f32 = 1.0;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo::<C>();
|
||||||
|
}
|
11
src/test/ui/const-generics/float-generic.simple.stderr
Normal file
11
src/test/ui/const-generics/float-generic.simple.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error: `f32` is forbidden as the type of a const generic parameter
|
||||||
|
--> $DIR/float-generic.rs:5:17
|
||||||
|
|
|
||||||
|
LL | fn foo<const F: f32>() {}
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= note: the only supported types are integers, `bool` and `char`
|
||||||
|
= help: more complex types are supported with `#![feature(adt_const_params)]`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue