1
Fork 0

Rollup merge of #95973 - oli-obk:tait_ub3, r=compiler-errors

prevent opaque types from appearing in impl headers

cc `@lqd`

opaque types are not distinguishable from their hidden type at the codegen stage. So we could either end up with cases where the hidden type doesn't implement the trait (which will thus ICE) or where the hidden type does implement the trait (so we'd be using its impl instead of the one written for the opaque type). This can even lead to unsound behaviour without unsafe code.

Fixes https://github.com/rust-lang/rust/issues/86411.
Fixes https://github.com/rust-lang/rust/issues/84660.

rebase of #87382 plus some diagnostic tweaks
This commit is contained in:
Dylan DPC 2022-04-12 23:17:01 +02:00 committed by GitHub
commit e96304b73d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 206 additions and 50 deletions

View file

@ -7,6 +7,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_index::bit_set::GrowableBitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_session::lint;
@ -141,13 +142,56 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
}
}
if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
let reported = tcx
.sess
.struct_span_err(sp, "cannot implement trait on type alias impl trait")
.span_note(tcx.def_span(def_id), "type alias impl trait defined here")
.emit();
return Err(reported);
// Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
// and #84660 where it would otherwise allow unsoundness.
if trait_ref.has_opaque_types() {
trace!("{:#?}", item);
// First we find the opaque type in question.
for ty in trait_ref.substs {
for ty in ty.walk() {
let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
let ty::Opaque(def_id, _) = *ty.kind() else { continue };
trace!(?def_id);
// Then we search for mentions of the opaque type's type alias in the HIR
struct SpanFinder<'tcx> {
sp: Span,
def_id: DefId,
tcx: TyCtxt<'tcx>,
}
impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
#[instrument(level = "trace", skip(self, _id))]
fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
// You can't mention an opaque type directly, so we look for type aliases
if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
// And check if that type alias's type contains the opaque type we're looking for
for arg in self.tcx.type_of(def_id).walk() {
if let GenericArgKind::Type(ty) = arg.unpack() {
if let ty::Opaque(def_id, _) = *ty.kind() {
if def_id == self.def_id {
// Finally we update the span to the mention of the type alias
self.sp = path.span;
return;
}
}
}
}
}
hir::intravisit::walk_path(self, path)
}
}
let mut visitor = SpanFinder { sp, def_id, tcx };
hir::intravisit::walk_item(&mut visitor, item);
let reported = tcx
.sess
.struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
.span_note(tcx.def_span(def_id), "type alias impl trait defined here")
.emit();
return Err(reported);
}
}
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
}
Ok(())