1+ use std:: assert_matches;
2+
13use rustc_ast:: TraitObjectSyntax ;
2- use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
4+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexMap , FxIndexSet } ;
35use rustc_errors:: codes:: * ;
46use rustc_errors:: {
57 Applicability , Diag , DiagCtxtHandle , Diagnostic , EmissionGuarantee , Level , StashKey ,
@@ -11,8 +13,8 @@ use rustc_hir::{self as hir, HirId, LangItem};
1113use rustc_lint_defs:: builtin:: { BARE_TRAIT_OBJECTS , UNUSED_ASSOCIATED_TYPE_BOUNDS } ;
1214use rustc_middle:: ty:: elaborate:: ClauseWithSupertraitSpan ;
1315use rustc_middle:: ty:: {
14- self , BottomUpFolder , ExistentialPredicateStableCmpExt as _, Ty , TyCtxt , TypeFoldable ,
15- TypeVisitableExt , Upcast ,
16+ self , AliasTermKind , BottomUpFolder , ExistentialPredicateStableCmpExt as _, Ty , TyCtxt ,
17+ TypeFoldable , TypeVisitableExt , Upcast ,
1618} ;
1719use rustc_span:: edit_distance:: find_best_match_for_name;
1820use rustc_span:: { ErrorGuaranteed , Span } ;
@@ -69,7 +71,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
6971 dummy_self,
7072 & mut user_written_bounds,
7173 PredicateFilter :: SelfOnly ,
72- OverlappingAsssocItemConstraints :: Forbidden ,
74+ OverlappingAsssocItemConstraints :: Allowed ,
7375 ) ;
7476 if let Err ( GenericArgCountMismatch { invalid_args, .. } ) = result. correct {
7577 potential_assoc_items. extend ( invalid_args) ;
@@ -87,6 +89,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
8789 span,
8890 ) ;
8991
92+ // Note: This only includes elaboration due to trait aliases.
93+ // It does not include elaboration due to supertraits.
9094 let ( mut elaborated_trait_bounds, elaborated_projection_bounds) =
9195 traits:: expand_trait_aliases ( tcx, user_written_bounds. iter ( ) . copied ( ) ) ;
9296
@@ -177,7 +181,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
177181 ) ;
178182 if let Some ( ( old_proj, old_proj_span) ) =
179183 projection_bounds. insert ( key, ( proj, proj_span) )
180- && tcx . anonymize_bound_vars ( proj) != tcx . anonymize_bound_vars ( old_proj)
184+ && proj != old_proj
181185 {
182186 let kind = tcx. def_descr ( item_def_id) ;
183187 let name = tcx. item_name ( item_def_id) ;
@@ -204,6 +208,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
204208 // We achieve a stable ordering by walking over the unsubstituted principal trait ref.
205209 let mut ordered_associated_items = vec ! [ ] ;
206210
211+ // Detect conflicting bounds from expanding supertraits.
212+ //
213+ // We need to prohibit conflicting bounds from the same item_def_id,
214+ // even if they have different generics. This is because those generics might
215+ // end up being instantiated with the same concrete type, causing unsoundness.
216+ // See https://github.com/rust-lang/rust/issues/154662.
217+ //
218+ // This check could be more lenient, allowing conflicting bounds on different
219+ // generics that we know for sure cannot be instantiated into identical concrete
220+ // types. But for now, we're being conservative.
221+ let mut seen_projection_bounds_ignoring_generics = FxHashMap :: default ( ) ;
222+
207223 if let Some ( ( principal_trait, ref spans) ) = principal_trait {
208224 let principal_trait = principal_trait. map_bound ( |trait_pred| {
209225 assert_eq ! ( trait_pred. polarity, ty:: PredicatePolarity :: Positive ) ;
@@ -240,6 +256,38 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
240256 ) ;
241257 }
242258 ty:: ClauseKind :: Projection ( pred) => {
259+ // See the comment above `let seen_projection_bounds_ignoring_generics`
260+ let kind = pred. projection_term . kind ;
261+ assert_matches ! (
262+ kind,
263+ AliasTermKind :: ProjectionTy { .. }
264+ | AliasTermKind :: ProjectionConst { .. } ,
265+ "Unexpected projection kind in lower_trait_object_ty"
266+ ) ;
267+ let term = pred. term ;
268+ // This clause specifies that the `kind` is equal to `term`.
269+ // We record this, and check for duplicates.
270+ if let Some ( old_term) =
271+ seen_projection_bounds_ignoring_generics. insert ( kind, term)
272+ && old_term != term
273+ {
274+ let name = tcx. item_name ( kind. def_id ( ) ) ;
275+ self . dcx ( )
276+ . struct_span_err (
277+ span,
278+ format ! (
279+ "conflicting {} bindings for `{}`" ,
280+ kind. descr( ) ,
281+ name,
282+ ) ,
283+ )
284+ // FIXME: Improve diagnostics by pointing to
285+ // where the bound is specified.
286+ . with_note ( format ! ( "`{name}` is specified to be `{old_term}`" ) )
287+ . with_note ( format ! ( "`{name}` is also specified to be `{term}`" ) )
288+ . emit ( ) ;
289+ }
290+
243291 let pred = bound_predicate. rebind ( pred) ;
244292 // A `Self` within the original bound will be instantiated with a
245293 // `trait_object_dummy_self`, so check for that.
@@ -285,6 +333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
285333 }
286334 }
287335 }
336+ drop ( seen_projection_bounds_ignoring_generics) ;
288337
289338 // Flag assoc item bindings that didn't really need to be specified.
290339 for & ( projection_bound, span) in projection_bounds. values ( ) {
0 commit comments