diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 50034fb02ace9..e68496bf244e3 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -101,20 +101,24 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { cv.ty, structural ); if let Some(non_sm_ty) = structural { - let adt_def = match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => adt_def, + let msg = match non_sm_ty { + traits::NonStructuralMatchTy::Adt(adt_def) => { + let path = self.tcx().def_path_str(adt_def.did); + format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ) + } traits::NonStructuralMatchTy::Param => { bug!("use of constant whose type is a parameter inside a pattern") } - }; - let path = self.tcx().def_path_str(adt_def.did); - - let make_msg = || -> String { - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) + traits::NonStructuralMatchTy::FnPtr => { + format!("`fn` pointers cannot be used in a patterns") + } + traits::NonStructuralMatchTy::RawPtr => { + format!("raw pointers cannot be used in a patterns") + } }; // double-check there even *is* a semantic `PartialEq` to dispatch to. @@ -145,13 +149,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { if !ty_is_partial_eq { // span_fatal avoids ICE from resolution of non-existent method (rare case). - self.tcx().sess.span_fatal(self.span, &make_msg()); + self.tcx().sess.span_fatal(self.span, &msg); } else { self.tcx().struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, self.span, - |lint| lint.build(&make_msg()).emit(), + |lint| lint.build(&msg).emit(), ); } } @@ -257,7 +261,39 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { slice: None, suffix: Vec::new(), }, - _ => PatKind::Constant { value: cv }, + _ => { + let mut leaf_ty = cv.ty; + + // HACK(eddyb) workaround missing reference destructuring. + loop { + leaf_ty = match leaf_ty.kind { + ty::Ref(_, pointee_ty, _) => pointee_ty, + + // HACK(eddyb) even worse, these show up *behind* + // references, so despite being supported above we have + // to reimplement them here (and we can't really do the + // same for nested tuples or ADTs...). + ty::Array(elem_ty, _) | ty::Slice(elem_ty) => elem_ty, + + _ => break, + }; + } + + match leaf_ty.kind { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::FnDef(..) => { + PatKind::Constant { value: cv } + } + + _ => { + debug!("non-structural leaf constant type {:?}", leaf_ty); + let msg = + format!("constants of type `{}` cannot be used in a pattern", leaf_ty); + self.saw_const_match_error.set(true); + tcx.sess.span_err(span, &msg); + PatKind::Wild + } + } + } }; Pat { span, ty: cv.ty, kind: Box::new(kind) } diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index fbe1fcb08f2ef..6d8f6d0eb7d87 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -11,6 +11,8 @@ use rustc_span::Span; pub enum NonStructuralMatchTy<'tcx> { Adt(&'tcx AdtDef), Param, + FnPtr, + RawPtr, } /// This method traverses the structure of `ty`, trying to find an @@ -138,26 +140,16 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { return true; // Stop visiting. } 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. - - // (But still tell caller to continue search.) - return false; + self.found = Some(NonStructuralMatchTy::RawPtr); + return true; // Stop visiting. + } + ty::FnPtr(..) => { + self.found = Some(NonStructuralMatchTy::FnPtr); + return true; // Stop visiting. } - ty::FnDef(..) | ty::FnPtr(..) => { - // types of formals and return in `fn(_) -> _` are also irrelevant; + ty::FnDef(..) => { + // substs of ZST function (*not* `fn(...) -> _` pointers!) types + // are also irrelevant; // so we do not recur into them via `super_visit_with` // // (But still tell caller to continue search.) diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 05d2dff8e9868..e29d7a8b5c666 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -6,44 +6,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:31 +error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq` + --> $DIR/fn-const-param-infer.rs:4:25 | -LL | let _: Checked = Checked::; - | ---------------- ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}` - | | - | expected due to this - | - = note: expected struct `Checked<{not_one as fn(usize) -> bool}>` - found struct `Checked<{not_two as fn(usize) -> bool}>` - -error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:20:24 - | -LL | let _ = Checked::<{generic_arg::}>; - | ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32` - | - = note: expected fn pointer `fn(usize) -> _` - found fn item `fn(u32) -> _ {generic_arg::}` - -error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:22:23 - | -LL | let _ = Checked::; - | ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic` - -error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:25:40 - | -LL | let _: Checked<{generic::}> = Checked::<{generic::}>; - | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic:: as fn(usize) -> bool}`, found `{generic:: as fn(usize) -> bool}` - | | - | expected due to this - | - = note: expected struct `Checked<{generic:: as fn(usize) -> bool}>` - found struct `Checked<{generic:: as fn(usize) -> bool}>` +LL | struct Checked bool>; + | ^^^^^^^^^^^^^^^^^ `fn(usize) -> bool` doesn't derive both `PartialEq` and `Eq` -error: aborting due to 4 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0282, E0308. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr index d9794f60a19ce..265ee3723c688 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -6,17 +6,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:40 +error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq` + --> $DIR/raw-ptr-const-param.rs:4:23 | -LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; - | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` - | | - | expected due to this - | - = note: expected struct `Const<{0xf as *const u32}>` - found struct `Const<{0xa as *const u32}>` +LL | struct Const; + | ^^^^^^^^^^ `*const u32` doesn't derive both `PartialEq` and `Eq` error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 5477170fb1e41..c26adf743893f 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -4,17 +4,11 @@ error: to use a constant of type `S` in a pattern, `S` must be annotated with `# LL | C => {} | ^ -error[E0004]: non-exhaustive patterns: `&T` not covered - --> $DIR/match_ice.rs:16:11 +error: constants of type `T` cannot be used in a pattern + --> $DIR/match_ice.rs:17:9 | -LL | struct T; - | --------- `T` defined here -... -LL | match K { - | ^ pattern `&T` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&T` +LL | K => {} + | ^ error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/match_ice.rs:11:9 @@ -22,6 +16,11 @@ error: to use a constant of type `S` in a pattern, `S` must be annotated with `# LL | C => {} | ^ -error: aborting due to 3 previous errors +error: constants of type `T` cannot be used in a pattern + --> $DIR/match_ice.rs:17:9 + | +LL | K => {} + | ^ + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr index dc7ef55e7ab99..2b1cefd19d776 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -25,6 +25,12 @@ LL | struct ConstFn; = note: see issue #53020 for more information = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable +error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq` + --> $DIR/feature-gate-const_generics-ptr.rs:1:25 + | +LL | struct ConstFn; + | ^^^^ `fn()` doesn't derive both `PartialEq` and `Eq` + error[E0658]: using raw pointers as const generic parameters is unstable --> $DIR/feature-gate-const_generics-ptr.rs:5:26 | @@ -34,6 +40,13 @@ LL | struct ConstPtr; = note: see issue #53020 for more information = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable -error: aborting due to 4 previous errors +error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq` + --> $DIR/feature-gate-const_generics-ptr.rs:5:26 + | +LL | struct ConstPtr; + | ^^^^^^^^^^ `*const u32` doesn't derive both `PartialEq` and `Eq` + +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0741. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr b/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr index 0bf369fa8cb87..33bb90b0cd22b 100644 --- a/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr @@ -1,8 +1,14 @@ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` +error: constants of type `B` cannot be used in a pattern --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9 | LL | A => (), | ^ -error: aborting due to previous error +error: constants of type `B` cannot be used in a pattern + --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9 + | +LL | A => (), + | ^ + +error: aborting due to 2 previous errors