From 1152e70363702919a729b9a83eb7550c9392d306 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 23 Jul 2022 20:09:52 +0000 Subject: [PATCH 1/3] Deeply deny fn and raw ptrs in const generics --- .../src/transform/check_consts/qualifs.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 8 ++- .../src/traits/structural_match.rs | 70 +++++++++++++------ compiler/rustc_typeck/src/check/wfcheck.rs | 38 +++++----- .../fn-const-param-call.full.stderr | 5 +- .../fn-const-param-infer.full.stderr | 3 +- .../issues/issue-71381.full.stderr | 7 +- .../issues/issue-71382.full.stderr | 3 +- .../issues/issue-71611.full.stderr | 5 +- .../issues/issue-72352.full.stderr | 3 +- .../ui/const-generics/issues/issue-99641.rs | 18 +++++ .../const-generics/issues/issue-99641.stderr | 15 ++++ .../raw-ptr-const-param-deref.full.stderr | 5 +- .../raw-ptr-const-param.full.stderr | 3 +- .../consts/refs_check_const_eq-issue-88384.rs | 4 +- .../refs_check_const_eq-issue-88384.stderr | 17 ++++- 17 files changed, 147 insertions(+), 61 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-99641.rs create mode 100644 src/test/ui/const-generics/issues/issue-99641.stderr diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 29464cf8c4e4f..b97dd1ae8d592 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -226,7 +226,7 @@ impl Qualif for CustomEq { // because that component may be part of an enum variant (e.g., // `Option::::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, false).is_some() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index a4e7a12bba323..f8792edc017b2 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -203,7 +203,7 @@ impl<'tcx> Const<'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()), } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index e32e0b11ba497..44faed3fa9fb9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { - traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map( + traits::search_for_structural_match_violation(self.span, self.tcx(), ty, false).map( |non_sm_ty| { with_no_trimmed_paths!(match non_sm_ty.kind { traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), @@ -139,6 +139,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { traits::NonStructuralMatchTyKind::Float => { "floating-point numbers cannot be used in patterns".to_string() } + traits::NonStructuralMatchTyKind::FnPtr => { + "function pointers cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::RawPtr => { + "raw pointers cannot be used in patterns".to_string() + } traits::NonStructuralMatchTyKind::Param => { bug!("use of a constant whose type is a parameter inside a pattern") } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 6c0b83fbd0304..25a66bb9d08af 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -27,6 +27,8 @@ pub enum NonStructuralMatchTyKind<'tcx> { Generator, Projection, Float, + FnPtr, + RawPtr, } /// This method traverses the structure of `ty`, trying to find an @@ -55,14 +57,15 @@ pub enum NonStructuralMatchTyKind<'tcx> { /// 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 +/// When the `valtree_semantics` flag is set, then we also deny additional +/// types that are not evaluatable to valtrees, such as floats and fn ptrs. pub fn search_for_structural_match_violation<'tcx>( span: Span, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, - floats_allowed: bool, + valtree_semantics: bool, ) -> Option> { - ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed }) + ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), valtree_semantics }) .break_value() } @@ -125,7 +128,9 @@ struct Search<'tcx> { /// we will not recur on them again. seen: FxHashSet, - floats_allowed: bool, + // Additionally deny things that have been allowed in patterns, + // but are not evaluatable to a valtree, such as floats and fn ptrs. + valtree_semantics: bool, } impl<'tcx> Search<'tcx> { @@ -170,24 +175,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { 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; - } - 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; @@ -206,8 +194,44 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { return ControlFlow::CONTINUE; } + ty::FnPtr(..) => { + if !self.valtree_semantics { + return ControlFlow::CONTINUE; + } else { + return ControlFlow::Break(NonStructuralMatchTy { + ty, + kind: NonStructuralMatchTyKind::FnPtr, + }); + } + } + + ty::RawPtr(..) => { + if !self.valtree_semantics { + // 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(NonStructuralMatchTy { + ty, + kind: NonStructuralMatchTyKind::FnPtr, + }); + } + } + ty::Float(_) => { - if self.floats_allowed { + if !self.valtree_semantics { return ControlFlow::CONTINUE; } else { return ControlFlow::Break(NonStructuralMatchTy { diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b8e998229ba8e..324b229fa5941 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -848,29 +848,13 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { 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_structural_match_violation(param.span, tcx, ty, true) { // 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.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` @@ -902,6 +886,24 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { .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, diff --git a/src/test/ui/const-generics/fn-const-param-call.full.stderr b/src/test/ui/const-generics/fn-const-param-call.full.stderr index d984449e6ca6e..b55c2449858c9 100644 --- a/src/test/ui/const-generics/fn-const-param-call.full.stderr +++ b/src/test/ui/const-generics/fn-const-param-call.full.stderr @@ -1,10 +1,10 @@ -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 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 u32> Wrapper { @@ -12,3 +12,4 @@ LL | impl u32> Wrapper { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/fn-const-param-infer.full.stderr b/src/test/ui/const-generics/fn-const-param-infer.full.stderr index f0767a10994a5..2d66a19233269 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.full.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.full.stderr @@ -1,4 +1,4 @@ -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 bool>; @@ -6,3 +6,4 @@ LL | struct Checked bool>; error: aborting due to previous error +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-71381.full.stderr b/src/test/ui/const-generics/issues/issue-71381.full.stderr index 3950317b37053..e17cf96aa3e3d 100644 --- a/src/test/ui/const-generics/issues/issue-71381.full.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.full.stderr @@ -10,13 +10,13 @@ error[E0770]: the type of const parameters must not depend on other generic para 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(&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), @@ -24,4 +24,5 @@ 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`. diff --git a/src/test/ui/const-generics/issues/issue-71382.full.stderr b/src/test/ui/const-generics/issues/issue-71382.full.stderr index 715037bd5f1e8..ab2a4e64a8389 100644 --- a/src/test/ui/const-generics/issues/issue-71382.full.stderr +++ b/src/test/ui/const-generics/issues/issue-71382.full.stderr @@ -1,4 +1,4 @@ -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(&self) { @@ -6,3 +6,4 @@ LL | fn test(&self) { error: aborting due to previous error +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-71611.full.stderr b/src/test/ui/const-generics/issues/issue-71611.full.stderr index 01a85b745ce39..656aa29e19b25 100644 --- a/src/test/ui/const-generics/issues/issue-71611.full.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.full.stderr @@ -4,7 +4,7 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn func(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(outer: A) { @@ -12,4 +12,5 @@ LL | fn func(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`. diff --git a/src/test/ui/const-generics/issues/issue-72352.full.stderr b/src/test/ui/const-generics/issues/issue-72352.full.stderr index eedd73c4dcc0a..92580b33685d1 100644 --- a/src/test/ui/const-generics/issues/issue-72352.full.stderr +++ b/src/test/ui/const-generics/issues/issue-72352.full.stderr @@ -1,4 +1,4 @@ -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 usize>(ptr: *const i8) -> usize { @@ -6,3 +6,4 @@ LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8 error: aborting due to previous error +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-99641.rs b/src/test/ui/const-generics/issues/issue-99641.rs new file mode 100644 index 0000000000000..fae6d3fc41fb8 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-99641.rs @@ -0,0 +1,18 @@ +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +fn main() { + pub struct Color; + //~^ ERROR using function pointers + + impl Color { + //~^ ERROR using function pointers + pub fn new() -> Self { + Color:: + } + } + + pub const D65: (fn(),) = (|| {},); + + Color::::new(); +} diff --git a/src/test/ui/const-generics/issues/issue-99641.stderr b/src/test/ui/const-generics/issues/issue-99641.stderr new file mode 100644 index 0000000000000..349ebba08d53f --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-99641.stderr @@ -0,0 +1,15 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/issue-99641.rs:5:35 + | +LL | pub struct Color; + | ^^^^^^^ + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/issue-99641.rs:8:23 + | +LL | impl Color { + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr index 04bc46cb4ab12..657eee2be2443 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.full.stderr @@ -1,10 +1,10 @@ -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; | ^^^^^^^^^^ -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

{ @@ -12,3 +12,4 @@ LL | impl Const

{ error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/raw-ptr-const-param.full.stderr b/src/test/ui/const-generics/raw-ptr-const-param.full.stderr index 310422aafcd35..69f1aae5681a4 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.full.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.full.stderr @@ -1,4 +1,4 @@ -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; @@ -6,3 +6,4 @@ LL | struct Const; error: aborting due to previous error +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/consts/refs_check_const_eq-issue-88384.rs b/src/test/ui/consts/refs_check_const_eq-issue-88384.rs index 204d18ea25de4..1496b28bd3ee6 100644 --- a/src/test/ui/consts/refs_check_const_eq-issue-88384.rs +++ b/src/test/ui/consts/refs_check_const_eq-issue-88384.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(fn_traits)] #![feature(adt_const_params)] //~^ WARNING the feature `adt_const_params` is incomplete @@ -10,8 +8,10 @@ struct CompileTimeSettings{ } struct Foo; +//~^ ERROR using function pointers as const generic parameters is forbidden impl Foo { + //~^ ERROR using function pointers as const generic parameters is forbidden fn call_hooks(){ } } diff --git a/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr b/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr index f2bad2f552759..4f2f5e244b67e 100644 --- a/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr +++ b/src/test/ui/consts/refs_check_const_eq-issue-88384.stderr @@ -1,5 +1,5 @@ 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)] | ^^^^^^^^^^^^^^^^ @@ -7,5 +7,18 @@ LL | #![feature(adt_const_params)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #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; + | ^^^^^^^^^^^^^^^^^^^ + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/refs_check_const_eq-issue-88384.rs:13:15 + | +LL | impl Foo { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0741`. From c1f54c30bb3200239849649ebc08d7ac2877db6c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 23 Jul 2022 23:10:08 +0000 Subject: [PATCH 2/3] Get rid of redundant NonStructuralMatchTyKind --- .../src/thir/pattern/const_to_pat.rs | 28 ++++---- .../rustc_trait_selection/src/traits/mod.rs | 1 - .../src/traits/structural_match.rs | 66 ++++--------------- compiler/rustc_typeck/src/check/wfcheck.rs | 6 +- 4 files changed, 28 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 44faed3fa9fb9..14133ebc17535 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -122,37 +122,31 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { traits::search_for_structural_match_violation(self.span, self.tcx(), ty, false).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 => { + 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() } - traits::NonStructuralMatchTyKind::Opaque => { + ty::Opaque(..) => { "opaque types cannot be used in patterns".to_string() } - traits::NonStructuralMatchTyKind::Closure => { + ty::Closure(..) => { "closures cannot be used in patterns".to_string() } - traits::NonStructuralMatchTyKind::Generator => { + ty::Generator(..) | ty::GeneratorWitness(..) => { "generators cannot be used in patterns".to_string() } - traits::NonStructuralMatchTyKind::Float => { + ty::Float(..) => { "floating-point numbers cannot be used in patterns".to_string() } - traits::NonStructuralMatchTyKind::FnPtr => { + ty::FnPtr(..) => { "function pointers cannot be used in patterns".to_string() } - traits::NonStructuralMatchTyKind::RawPtr => { + ty::RawPtr(..) => { "raw pointers 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") + _ => { + bug!("use of a value of `{non_sm_ty}` inside a pattern") } }) }, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3ef51b0c27abd..5397baefb9cf4 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -61,7 +61,6 @@ 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::util::{ elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, elaborate_trait_ref, elaborate_trait_refs, diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 25a66bb9d08af..ea11670ee777d 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -6,31 +6,10 @@ use rustc_data_structures::fx::FxHashSet; 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, - FnPtr, - RawPtr, -} - /// 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 @@ -64,7 +43,7 @@ pub fn search_for_structural_match_violation<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, valtree_semantics: bool, -) -> Option> { +) -> Option> { ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), valtree_semantics }) .break_value() } @@ -140,7 +119,7 @@ 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 { debug!("Search visiting ty: {:?}", ty); @@ -148,32 +127,25 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { 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 }); + return ControlFlow::Break(ty); } ty::FnDef(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; @@ -198,10 +170,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { if !self.valtree_semantics { return ControlFlow::CONTINUE; } else { - return ControlFlow::Break(NonStructuralMatchTy { - ty, - kind: NonStructuralMatchTyKind::FnPtr, - }); + return ControlFlow::Break(ty); } } @@ -223,10 +192,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { // pointer. Therefore, one can still use `C` in a pattern. return ControlFlow::CONTINUE; } else { - return ControlFlow::Break(NonStructuralMatchTy { - ty, - kind: NonStructuralMatchTyKind::FnPtr, - }); + return ControlFlow::Break(ty); } } @@ -234,10 +200,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { if !self.valtree_semantics { return ControlFlow::CONTINUE; } else { - return ControlFlow::Break(NonStructuralMatchTy { - ty, - kind: NonStructuralMatchTyKind::Float, - }); + return ControlFlow::Break(ty); } } @@ -263,8 +226,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { 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 diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 324b229fa5941..3bf76ad38ee2b 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -854,7 +854,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { // 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 non_structural_match_ty.ty.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` @@ -911,10 +911,10 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { 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`"), From 10b69ab0d20bdbbcdfc5bfe443a50cf2b12b66de Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 24 Jul 2022 20:44:19 +0000 Subject: [PATCH 3/3] Remove non-descriptive boolean from search_for_structural_match_violation --- .../src/transform/check_consts/qualifs.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 60 +++++++++---------- .../rustc_trait_selection/src/traits/mod.rs | 4 +- .../src/traits/structural_match.rs | 33 ++++++---- compiler/rustc_typeck/src/check/wfcheck.rs | 2 +- 5 files changed, 57 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index b97dd1ae8d592..e099445117225 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -226,7 +226,7 @@ impl Qualif for CustomEq { // because that component may be part of an enum variant (e.g., // `Option::::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, false).is_some() + traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 14133ebc17535..d6dd0f017941a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -120,37 +120,35 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { - traits::search_for_structural_match_violation(self.span, self.tcx(), ty, false).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") - } - }) - }, - ) + 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 { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 5397baefb9cf4..d0a17f712d3df 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -60,7 +60,9 @@ pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError 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::{ + 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, diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index ea11670ee777d..c278752e3d9f4 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -35,16 +35,28 @@ use std::ops::ControlFlow; /// 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. -/// -/// When the `valtree_semantics` flag is set, then we also deny additional -/// types that are not evaluatable to valtrees, such as floats and fn ptrs. pub fn search_for_structural_match_violation<'tcx>( span: Span, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, - valtree_semantics: bool, ) -> Option> { - ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), valtree_semantics }) + 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.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: true }) .break_value() } @@ -108,8 +120,9 @@ struct Search<'tcx> { seen: FxHashSet, // Additionally deny things that have been allowed in patterns, - // but are not evaluatable to a valtree, such as floats and fn ptrs. - valtree_semantics: bool, + // but are not allowed in adt const params, such as floats and + // fn ptrs. + adt_const_param: bool, } impl<'tcx> Search<'tcx> { @@ -167,7 +180,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { } ty::FnPtr(..) => { - if !self.valtree_semantics { + if !self.adt_const_param { return ControlFlow::CONTINUE; } else { return ControlFlow::Break(ty); @@ -175,7 +188,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { } ty::RawPtr(..) => { - if !self.valtree_semantics { + if !self.adt_const_param { // structural-match ignores substructure of // `*const _`/`*mut _`, so skip `super_visit_with`. // @@ -197,7 +210,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { } ty::Float(_) => { - if !self.valtree_semantics { + if !self.adt_const_param { return ControlFlow::CONTINUE; } else { return ControlFlow::Break(ty); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 3bf76ad38ee2b..ca5defd16882a 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -849,7 +849,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { if tcx.features().adt_const_params { if let Some(non_structural_match_ty) = - traits::search_for_structural_match_violation(param.span, tcx, ty, true) + 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