// 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
// structural-match (`Option::None`).
- traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some()
+ traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some()
}
fn in_adt_inherently<'tcx>(
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
match self.kind() {
ty::ConstKind::Value(valtree) => valtree,
- _ => bug!("expected ConstKind::Value"),
+ _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
}
}
}
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
- traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map(
- |non_sm_ty| {
- with_no_trimmed_paths!(match non_sm_ty.kind {
- traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
- 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::Closure => {
- "closures cannot be used in patterns".to_string()
- }
- traits::NonStructuralMatchTyKind::Generator => {
- "generators cannot be used in patterns".to_string()
- }
- traits::NonStructuralMatchTyKind::Float => {
- "floating-point numbers 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::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")
- }
- })
- },
- )
+ traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
+ with_no_trimmed_paths!(match non_sm_ty.kind() {
+ ty::Adt(adt, _) => self.adt_derive_msg(*adt),
+ ty::Dynamic(..) => {
+ "trait objects cannot be used in patterns".to_string()
+ }
+ ty::Opaque(..) => {
+ "opaque types cannot be used in patterns".to_string()
+ }
+ ty::Closure(..) => {
+ "closures cannot be used in patterns".to_string()
+ }
+ ty::Generator(..) | ty::GeneratorWitness(..) => {
+ "generators cannot be used in patterns".to_string()
+ }
+ ty::Float(..) => {
+ "floating-point numbers cannot be used in patterns".to_string()
+ }
+ ty::FnPtr(..) => {
+ "function pointers cannot be used in patterns".to_string()
+ }
+ ty::RawPtr(..) => {
+ "raw pointers cannot be used in patterns".to_string()
+ }
+ _ => {
+ bug!("use of a value of `{non_sm_ty}` inside a pattern")
+ }
+ })
+ })
}
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
-pub use self::structural_match::search_for_structural_match_violation;
-pub use self::structural_match::{NonStructuralMatchTy, NonStructuralMatchTyKind};
+pub use self::structural_match::{
+ search_for_adt_const_param_violation, search_for_structural_match_violation,
+};
pub use self::util::{
elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
elaborate_trait_ref, elaborate_trait_refs,
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_span::Span;
use std::ops::ControlFlow;
-#[derive(Debug)]
-pub struct NonStructuralMatchTy<'tcx> {
- pub ty: Ty<'tcx>,
- pub kind: NonStructuralMatchTyKind<'tcx>,
-}
-
-#[derive(Debug)]
-pub enum NonStructuralMatchTyKind<'tcx> {
- Adt(AdtDef<'tcx>),
- Param,
- Dynamic,
- Foreign,
- Opaque,
- Closure,
- Generator,
- Projection,
- Float,
-}
-
/// This method traverses the structure of `ty`, trying to find an
/// instance of an ADT (i.e. struct or enum) that doesn't implement
/// the structural-match traits, or a generic type parameter
/// For more background on why Rust has this requirement, and issues
/// that arose when the requirement was not enforced completely, see
/// 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>(
span: Span,
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
- floats_allowed: bool,
-) -> Option<NonStructuralMatchTy<'tcx>> {
- ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed })
+) -> Option<Ty<'tcx>> {
+ ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: false })
+ .break_value()
+}
+
+/// This method traverses the structure of `ty`, trying to find any
+/// types that are not allowed to be used in a const generic.
+///
+/// This is either because the type does not implement `StructuralEq`
+/// and `StructuralPartialEq`, or because the type is intentionally
+/// not supported in const generics (such as floats and raw pointers,
+/// which are allowed in match blocks).
+pub fn search_for_adt_const_param_violation<'tcx>(
+ span: Span,
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+) -> Option<Ty<'tcx>> {
+ ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: true })
.break_value()
}
/// we will not recur on them again.
seen: FxHashSet<hir::def_id::DefId>,
- floats_allowed: bool,
+ // Additionally deny things that have been allowed in patterns,
+ // but are not allowed in adt const params, such as floats and
+ // fn ptrs.
+ adt_const_param: bool,
}
impl<'tcx> Search<'tcx> {
}
impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
- type BreakTy = NonStructuralMatchTy<'tcx>;
+ type BreakTy = Ty<'tcx>;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("Search visiting ty: {:?}", ty);
let (adt_def, substs) = match *ty.kind() {
ty::Adt(adt_def, substs) => (adt_def, substs),
ty::Param(_) => {
- let kind = NonStructuralMatchTyKind::Param;
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
+ return ControlFlow::Break(ty);
}
ty::Dynamic(..) => {
- let kind = NonStructuralMatchTyKind::Dynamic;
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
+ return ControlFlow::Break(ty);
}
ty::Foreign(_) => {
- let kind = NonStructuralMatchTyKind::Foreign;
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
+ return ControlFlow::Break(ty);
}
ty::Opaque(..) => {
- let kind = NonStructuralMatchTyKind::Opaque;
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
+ return ControlFlow::Break(ty);
}
ty::Projection(..) => {
- let kind = NonStructuralMatchTyKind::Projection;
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
+ return ControlFlow::Break(ty);
}
ty::Closure(..) => {
- let kind = NonStructuralMatchTyKind::Closure;
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
+ return ControlFlow::Break(ty);
}
ty::Generator(..) | ty::GeneratorWitness(..) => {
- let kind = NonStructuralMatchTyKind::Generator;
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
- }
- ty::RawPtr(..) => {
- // structural-match ignores substructure of
- // `*const _`/`*mut _`, so skip `super_visit_with`.
- //
- // For example, if you have:
- // ```
- // struct NonStructural;
- // #[derive(PartialEq, Eq)]
- // struct T(*const NonStructural);
- // const C: T = T(std::ptr::null());
- // ```
- //
- // Even though `NonStructural` does not implement `PartialEq`,
- // structural equality on `T` does not recur into the raw
- // pointer. Therefore, one can still use `C` in a pattern.
- return ControlFlow::CONTINUE;
+ return ControlFlow::Break(ty);
}
- ty::FnDef(..) | ty::FnPtr(..) => {
+ ty::FnDef(..) => {
// Types of formals and return in `fn(_) -> _` are also irrelevant;
// so we do not recur into them via `super_visit_with`
return ControlFlow::CONTINUE;
return ControlFlow::CONTINUE;
}
+ ty::FnPtr(..) => {
+ if !self.adt_const_param {
+ return ControlFlow::CONTINUE;
+ } else {
+ return ControlFlow::Break(ty);
+ }
+ }
+
+ ty::RawPtr(..) => {
+ if !self.adt_const_param {
+ // structural-match ignores substructure of
+ // `*const _`/`*mut _`, so skip `super_visit_with`.
+ //
+ // For example, if you have:
+ // ```
+ // struct NonStructural;
+ // #[derive(PartialEq, Eq)]
+ // struct T(*const NonStructural);
+ // const C: T = T(std::ptr::null());
+ // ```
+ //
+ // Even though `NonStructural` does not implement `PartialEq`,
+ // structural equality on `T` does not recur into the raw
+ // pointer. Therefore, one can still use `C` in a pattern.
+ return ControlFlow::CONTINUE;
+ } else {
+ return ControlFlow::Break(ty);
+ }
+ }
+
ty::Float(_) => {
- if self.floats_allowed {
+ if !self.adt_const_param {
return ControlFlow::CONTINUE;
} else {
- return ControlFlow::Break(NonStructuralMatchTy {
- ty,
- kind: NonStructuralMatchTyKind::Float,
- });
+ return ControlFlow::Break(ty);
}
}
if !self.type_marked_structural(ty) {
debug!("Search found ty: {:?}", ty);
- let kind = NonStructuralMatchTyKind::Adt(adt_def);
- return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
+ return ControlFlow::Break(ty);
}
// structural-match does not care about the
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
if tcx.features().adt_const_params {
- let err = match ty.peel_refs().kind() {
- ty::FnPtr(_) => Some("function pointers"),
- ty::RawPtr(_) => Some("raw pointers"),
- _ => None,
- };
-
- if let Some(unsupported_type) = err {
- tcx.sess.span_err(
- hir_ty.span,
- &format!(
- "using {} as const generic parameters is forbidden",
- unsupported_type
- ),
- );
- }
-
if let Some(non_structural_match_ty) =
- traits::search_for_structural_match_violation(param.span, tcx, ty, false)
+ traits::search_for_adt_const_param_violation(param.span, tcx, ty)
{
// 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
// clearer.
- match ty.peel_refs().kind() {
+ match non_structural_match_ty.kind() {
ty::Param(_) => {
// Const parameters may not have type parameters as their types,
// because we cannot be sure that the type parameter derives `PartialEq`
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
.emit();
}
+ ty::FnPtr(_) => {
+ struct_span_err!(
+ tcx.sess,
+ hir_ty.span,
+ E0741,
+ "using function pointers as const generic parameters is forbidden",
+ )
+ .emit();
+ }
+ ty::RawPtr(_) => {
+ struct_span_err!(
+ tcx.sess,
+ hir_ty.span,
+ E0741,
+ "using raw pointers as const generic parameters is forbidden",
+ )
+ .emit();
+ }
_ => {
let mut diag = struct_span_err!(
tcx.sess,
E0741,
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
the type of a const parameter",
- non_structural_match_ty.ty,
+ non_structural_match_ty,
);
- if ty == non_structural_match_ty.ty {
+ if ty == non_structural_match_ty {
diag.span_label(
hir_ty.span,
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:11:25
|
LL | struct Wrapper<const F: fn() -> u32>;
| ^^^^^^^^^^^
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-call.rs:13:15
|
LL | impl<const F: fn() -> u32> Wrapper<F> {
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0741`.
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/fn-const-param-infer.rs:6:25
|
LL | struct Checked<const F: fn(usize) -> bool>;
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0741`.
LL | const FN: unsafe extern "C" fn(Args),
| ^^^^ the type must not depend on the parameter `Args`
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71381.rs:14:61
|
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71381.rs:23:19
|
LL | const FN: unsafe extern "C" fn(Args),
error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0770`.
+Some errors have detailed explanations: E0741, E0770.
+For more information about an error, try `rustc --explain E0741`.
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71382.rs:16:23
|
LL | fn test<const FN: fn()>(&self) {
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0741`.
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
| ^ the type must not depend on the parameter `A`
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-71611.rs:5:21
|
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0770`.
+Some errors have detailed explanations: E0741, E0770.
+For more information about an error, try `rustc --explain E0741`.
-error: using function pointers as const generic parameters is forbidden
+error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/issue-72352.rs:7:42
|
LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0741`.
--- /dev/null
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+fn main() {
+ pub struct Color<const WHITE: (fn(),)>;
+ //~^ ERROR using function pointers
+
+ impl<const WHITE: (fn(),)> Color<WHITE> {
+ //~^ ERROR using function pointers
+ pub fn new() -> Self {
+ Color::<WHITE>
+ }
+ }
+
+ pub const D65: (fn(),) = (|| {},);
+
+ Color::<D65>::new();
+}
--- /dev/null
+error[E0741]: using function pointers as const generic parameters is forbidden
+ --> $DIR/issue-99641.rs:5:35
+ |
+LL | pub struct Color<const WHITE: (fn(),)>;
+ | ^^^^^^^
+
+error[E0741]: using function pointers as const generic parameters is forbidden
+ --> $DIR/issue-99641.rs:8:23
+ |
+LL | impl<const WHITE: (fn(),)> Color<WHITE> {
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0741`.
-error: using raw pointers as const generic parameters is forbidden
+error[E0741]: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:9:23
|
LL | struct Const<const P: *const u32>;
| ^^^^^^^^^^
-error: using raw pointers as const generic parameters is forbidden
+error[E0741]: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param-deref.rs:11:15
|
LL | impl<const P: *const u32> Const<P> {
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0741`.
-error: using raw pointers as const generic parameters is forbidden
+error[E0741]: using raw pointers as const generic parameters is forbidden
--> $DIR/raw-ptr-const-param.rs:6:23
|
LL | struct Const<const P: *const u32>;
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0741`.
-// check-pass
-
#![feature(fn_traits)]
#![feature(adt_const_params)]
//~^ WARNING the feature `adt_const_params` is incomplete
}
struct Foo<const T: CompileTimeSettings>;
+//~^ ERROR using function pointers as const generic parameters is forbidden
impl<const T: CompileTimeSettings> Foo<T> {
+ //~^ ERROR using function pointers as const generic parameters is forbidden
fn call_hooks(){
}
}
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/refs_check_const_eq-issue-88384.rs:4:12
+ --> $DIR/refs_check_const_eq-issue-88384.rs:2:12
|
LL | #![feature(adt_const_params)]
| ^^^^^^^^^^^^^^^^
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
-warning: 1 warning emitted
+error[E0741]: using function pointers as const generic parameters is forbidden
+ --> $DIR/refs_check_const_eq-issue-88384.rs:10:21
+ |
+LL | struct Foo<const T: CompileTimeSettings>;
+ | ^^^^^^^^^^^^^^^^^^^
+
+error[E0741]: using function pointers as const generic parameters is forbidden
+ --> $DIR/refs_check_const_eq-issue-88384.rs:13:15
+ |
+LL | impl<const T: CompileTimeSettings> Foo<T> {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
+For more information about this error, try `rustc --explain E0741`.