Skip to content

Commit

Permalink
Rollup merge of #127808 - oli-obk:tainting_visitors2, r=lcnr,nnethercote
Browse files Browse the repository at this point in the history
Make ErrorGuaranteed discoverable outside types, consts, and lifetimes

types like `PatKind` could contain `ErrorGuaranteed`, but not return them via `tainted_by_errors` or `error_reported` (see #127687 (comment)). Now this happens, but it's a bit fragile as you can see with the `TypeSuperVisitable for Ty` impl.

We will catch any problems around Ty, Region or Const at runtime with an assert, and everything using derives will not have such issues, as it will just invoke the `TypeVisitable for ErrorGuaranteed` impl
  • Loading branch information
matthiaskrgr authored Jul 16, 2024
2 parents 2876b1b + 53f7f8c commit 8fd1df8
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 32 deletions.
25 changes: 17 additions & 8 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ TrivialTypeTraversalImpls! {
crate::ty::adjustment::PointerCoercion,
::rustc_span::Span,
::rustc_span::symbol::Ident,
::rustc_errors::ErrorGuaranteed,
ty::BoundVar,
ty::ValTree<'tcx>,
}
Expand Down Expand Up @@ -443,13 +442,14 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
pat.visit_with(visitor)
}

ty::Error(guar) => guar.visit_with(visitor),

ty::Bool
| ty::Char
| ty::Str
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Error(_)
| ty::Infer(_)
| ty::Bound(..)
| ty::Placeholder(..)
Expand Down Expand Up @@ -602,6 +602,21 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
}
}

impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for rustc_span::ErrorGuaranteed {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
visitor.visit_error(*self)
}
}

impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for rustc_span::ErrorGuaranteed {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
_folder: &mut F,
) -> Result<Self, F::Error> {
Ok(self)
}
}

impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
Expand All @@ -617,12 +632,6 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst {
}
}

impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
self.args.visit_with(visitor)
}
}

impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for TyAndLayout<'tcx, Ty<'tcx>> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
visitor.visit_ty(self.ty)
Expand Down
45 changes: 21 additions & 24 deletions compiler/rustc_type_ir/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,12 @@ pub trait TypeVisitor<I: Interner>: Sized {

// The default region visitor is a no-op because `Region` is non-recursive
// and has no `super_visit_with` method to call.
fn visit_region(&mut self, _r: I::Region) -> Self::Result {
Self::Result::output()
fn visit_region(&mut self, r: I::Region) -> Self::Result {
if let ty::ReError(guar) = r.kind() {
self.visit_error(guar)
} else {
Self::Result::output()
}
}

fn visit_const(&mut self, c: I::Const) -> Self::Result {
Expand All @@ -116,6 +120,10 @@ pub trait TypeVisitor<I: Interner>: Sized {
fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result {
p.super_visit_with(self)
}

fn visit_error(&mut self, _guar: I::ErrorGuaranteed) -> Self::Result {
Self::Result::output()
}
}

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -439,6 +447,15 @@ impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
ControlFlow::Continue(())
}
}

#[inline]
fn visit_error(&mut self, _guar: <I as Interner>::ErrorGuaranteed) -> Self::Result {
if self.flags.intersects(TypeFlags::HAS_ERROR) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::Continue(())
}
}
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
Expand Down Expand Up @@ -547,27 +564,7 @@ struct HasErrorVisitor;
impl<I: Interner> TypeVisitor<I> for HasErrorVisitor {
type Result = ControlFlow<I::ErrorGuaranteed>;

fn visit_ty(&mut self, t: <I as Interner>::Ty) -> Self::Result {
if let ty::Error(guar) = t.kind() {
ControlFlow::Break(guar)
} else {
t.super_visit_with(self)
}
}

fn visit_const(&mut self, c: <I as Interner>::Const) -> Self::Result {
if let ty::ConstKind::Error(guar) = c.kind() {
ControlFlow::Break(guar)
} else {
c.super_visit_with(self)
}
}

fn visit_region(&mut self, r: <I as Interner>::Region) -> Self::Result {
if let ty::ReError(guar) = r.kind() {
ControlFlow::Break(guar)
} else {
ControlFlow::Continue(())
}
fn visit_error(&mut self, guar: <I as Interner>::ErrorGuaranteed) -> Self::Result {
ControlFlow::Break(guar)
}
}

0 comments on commit 8fd1df8

Please sign in to comment.