diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 77d8141c9688..6c512a0238ee 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3393,9 +3393,15 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { fn_like.asyncness() } +pub enum NonStructuralMatchTy<'tcx> { + Adt(&'tcx AdtDef), + Param, +} + /// This method traverses the structure of `ty`, trying to find an /// instance of an ADT (i.e. struct or enum) that was declared without -/// the `#[structural_match]` attribute. +/// the `#[structural_match]` attribute, or a generic type parameter +/// (which cannot be determined to be `structural_match`). /// /// The "structure of a type" includes all components that would be /// considered when doing a pattern match on a constant of that @@ -3417,10 +3423,10 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { /// 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. -pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>) - -> Option<&'tcx AdtDef> -{ +pub fn search_for_structural_match_violation<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option> { let mut search = Search { tcx, found: None, seen: FxHashSet::default() }; ty.visit_with(&mut search); return search.found; @@ -3428,11 +3434,11 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, struct Search<'tcx> { tcx: TyCtxt<'tcx>, - // records the first ADT we find without `#[structural_match` - found: Option<&'tcx AdtDef>, + // Records the first ADT or type parameter we find without `#[structural_match`. + found: Option>, - // tracks ADT's previously encountered during search, so that - // we will not recur on them again. + // Tracks ADTs previously encountered during search, so that + // we will not recurse on them again. seen: FxHashSet, } @@ -3442,6 +3448,10 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, let (adt_def, substs) = match ty.kind { ty::Adt(adt_def, substs) => (adt_def, substs), + ty::Param(_) => { + self.found = Some(NonStructuralMatchTy::Param); + return true; // Stop visiting. + } ty::RawPtr(..) => { // `#[structural_match]` ignores substructure of // `*const _`/`*mut _`, so skip super_visit_with @@ -3468,9 +3478,9 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, }; if !self.tcx.has_attr(adt_def.did, sym::structural_match) { - self.found = Some(&adt_def); + self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); debug!("Search found adt_def: {:?}", adt_def); - return true // Halt visiting! + return true; // Stop visiting. } if !self.seen.insert(adt_def.did) { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index d99688122185..98e286e61e94 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -999,15 +999,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if self.include_lint_checks && !saw_error { // If we were able to successfully convert the const to some pat, double-check // that the type of the const obeys `#[structural_match]` constraint. - if let Some(adt_def) = ty::search_for_adt_without_structural_match(self.tcx, cv.ty) { - - let path = self.tcx.def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, - path, - ); + if let Some(non_sm_ty) = ty::search_for_structural_match_violation(self.tcx, cv.ty) { + let msg = match non_sm_ty { + ty::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, + ) + } + ty::NonStructuralMatchTy::Param => { + bug!("use of constant whose type is a parameter inside a pattern"); + } + }; // before issuing lint, double-check there even *is* a // semantic PartialEq for us to dispatch to. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d6162c0bc0e9..08fb5ae1676e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1532,11 +1532,11 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option $DIR/forbid-non-structural_match-types.rs:11:19 | LL | struct D; @@ -14,4 +14,4 @@ LL | struct D; error: aborting due to previous error -For more information about this error, try `rustc --explain E0739`. +For more information about this error, try `rustc --explain E0740`.