From 4b162141631e900f760752eacdd6d5e510ac4e42 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 13 Aug 2022 18:39:30 +0200 Subject: [PATCH 1/3] Ban references to `Self` in trait object substs for projection predicates too. --- compiler/rustc_typeck/src/astconv/mod.rs | 46 +++++++++++++------ src/test/ui/traits/alias/self-in-generics.rs | 7 +++ .../ui/traits/alias/self-in-generics.stderr | 2 +- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 1e6cb53f3eeae..ff81747cafe6f 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_target::spec::abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::astconv_object_safety_violations; @@ -1458,16 +1458,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if ty == dummy_self { let param = &generics.params[index]; missing_type_params.push(param.name); - tcx.ty_error().into() + return tcx.ty_error().into(); } else if ty.walk().any(|arg| arg == dummy_self.into()) { references_self = true; - tcx.ty_error().into() - } else { - arg + return tcx.ty_error().into(); } - } else { - arg } + arg }) .collect(); let substs = tcx.intern_substs(&substs[..]); @@ -1506,13 +1503,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }); let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { - bound.map_bound(|b| { - if b.projection_ty.self_ty() != dummy_self { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b), - ); + bound.map_bound(|mut b| { + assert_eq!(b.projection_ty.self_ty(), dummy_self); + + // Like for trait refs, verify that `dummy_self` did not leak inside default type + // parameters. + let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() { + if ty == dummy_self || ty.walk().any(|arg| arg == dummy_self.into()) { + return true; + } + } + false + }); + if references_self { + tcx.sess + .delay_span_bug(span, "trait object projection bounds reference `Self`"); + let substs: Vec<_> = b + .projection_ty + .substs + .iter() + .map(|arg| { + if let ty::GenericArgKind::Type(_) = arg.unpack() { + return tcx.ty_error().into(); + } + arg + }) + .collect(); + b.projection_ty.substs = tcx.intern_substs(&substs[..]); } + ty::ExistentialProjection::erase_self_ty(tcx, b) }) }); diff --git a/src/test/ui/traits/alias/self-in-generics.rs b/src/test/ui/traits/alias/self-in-generics.rs index 6b99431f5bbcf..0bb6335f91e4b 100644 --- a/src/test/ui/traits/alias/self-in-generics.rs +++ b/src/test/ui/traits/alias/self-in-generics.rs @@ -1,3 +1,10 @@ +// astconv uses `FreshTy(0)` as a dummy `Self` type when instanciating trait objects. +// This `FreshTy(0)` can leak into substs, causing ICEs in several places. +// Using `save-analysis` triggers type-checking `f` that would be normally skipped +// as `type_of` emitted an error. +// +// compile-flags: -Zsave-analysis + #![feature(trait_alias)] pub trait SelfInput = Fn(&mut Self); diff --git a/src/test/ui/traits/alias/self-in-generics.stderr b/src/test/ui/traits/alias/self-in-generics.stderr index a1056872ea641..110d60e6e9116 100644 --- a/src/test/ui/traits/alias/self-in-generics.stderr +++ b/src/test/ui/traits/alias/self-in-generics.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait alias `SelfInput` cannot be made into an object - --> $DIR/self-in-generics.rs:5:19 + --> $DIR/self-in-generics.rs:12:19 | LL | pub fn f(_f: &dyn SelfInput) {} | ^^^^^^^^^ From be2641a61f2d34fe4f937a49dacfcb82bf0b9075 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 17 Aug 2022 20:22:52 +0200 Subject: [PATCH 2/3] Fortify check for const generics. --- compiler/rustc_typeck/src/astconv/mod.rs | 25 ++++++++++-------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index ff81747cafe6f..5bb02bc246caf 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1453,16 +1453,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .enumerate() .skip(1) // Remove `Self` for `ExistentialPredicate`. .map(|(index, arg)| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() { - debug!(?ty); - if ty == dummy_self { - let param = &generics.params[index]; - missing_type_params.push(param.name); - return tcx.ty_error().into(); - } else if ty.walk().any(|arg| arg == dummy_self.into()) { - references_self = true; - return tcx.ty_error().into(); - } + if arg == dummy_self.into() { + let param = &generics.params[index]; + missing_type_params.push(param.name); + return tcx.ty_error().into(); + } else if arg.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + return tcx.ty_error().into(); } arg }) @@ -1509,10 +1506,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Like for trait refs, verify that `dummy_self` did not leak inside default type // parameters. let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() { - if ty == dummy_self || ty.walk().any(|arg| arg == dummy_self.into()) { - return true; - } + if arg.walk().any(|arg| arg == dummy_self.into()) { + return true; } false }); @@ -1524,7 +1519,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .substs .iter() .map(|arg| { - if let ty::GenericArgKind::Type(_) = arg.unpack() { + if arg.walk().any(|arg| arg == dummy_self.into()) { return tcx.ty_error().into(); } arg From 72acd94117e784d4e7425e827c60d6a6748d7a88 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 17 Aug 2022 21:50:59 +0200 Subject: [PATCH 3/3] Add const-generics test. --- src/test/ui/traits/alias/self-in-const-generics.rs | 12 ++++++++++++ .../ui/traits/alias/self-in-const-generics.stderr | 11 +++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/test/ui/traits/alias/self-in-const-generics.rs create mode 100644 src/test/ui/traits/alias/self-in-const-generics.stderr diff --git a/src/test/ui/traits/alias/self-in-const-generics.rs b/src/test/ui/traits/alias/self-in-const-generics.rs new file mode 100644 index 0000000000000..b0de8ccd67847 --- /dev/null +++ b/src/test/ui/traits/alias/self-in-const-generics.rs @@ -0,0 +1,12 @@ +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] +#![feature(trait_alias)] + +trait Bar {} + +trait BB = Bar<{ 2 + 1 }>; + +fn foo(x: &dyn BB) {} +//~^ ERROR the trait alias `BB` cannot be made into an object [E0038] + +fn main() {} diff --git a/src/test/ui/traits/alias/self-in-const-generics.stderr b/src/test/ui/traits/alias/self-in-const-generics.stderr new file mode 100644 index 0000000000000..61cc217cfbce6 --- /dev/null +++ b/src/test/ui/traits/alias/self-in-const-generics.stderr @@ -0,0 +1,11 @@ +error[E0038]: the trait alias `BB` cannot be made into an object + --> $DIR/self-in-const-generics.rs:9:16 + | +LL | fn foo(x: &dyn BB) {} + | ^^ + | + = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`.