Skip to content

Fix/issue 152607 supertrait assoc type bound#156593

Open
spirali wants to merge 4 commits into
rust-lang:mainfrom
spirali:fix/issue-152607-supertrait-assoc-type-bound
Open

Fix/issue 152607 supertrait assoc type bound#156593
spirali wants to merge 4 commits into
rust-lang:mainfrom
spirali:fix/issue-152607-supertrait-assoc-type-bound

Conversation

@spirali

@spirali spirali commented May 15, 2026

Copy link
Copy Markdown
Contributor

This tries to fix #152607.
This PR is based on #153518.

  • I have added revisions for tests.
  • The original fix does not cover the dyn case, so I have tried to fix it on my own, but I am not sure about the correctness of this fix.

r? lcnr

akhilesharora and others added 3 commits May 14, 2026 17:00
…ormedness

When forming a trait object like `dyn Sub<Assoc = String>` where
`trait Sub: Super<Assoc: Copy>`, the compiler was not verifying that
`String: Copy`. This allowed unsound code to compile, potentially
leading to use-after-free vulnerabilities.

The root cause was that both the old and new trait solvers used
`explicit_super_predicates_of` which only yields `Self: SuperTrait`
predicates, but not the associated type bounds from those supertraits.
For example, `trait Sub: Super<Assoc: Copy>` expands to both
`Self: Super` and `<Self as Super>::Assoc: Copy`, but only the first
was being checked.

This change switches to `explicit_implied_predicates_of` in both:
- The old solver's `confirm_object_candidate`
- The new solver's `predicates_for_object_candidate`

This ensures that associated type bounds from supertraits are properly
verified when constructing trait objects.
@rustbot

rustbot commented May 15, 2026

Copy link
Copy Markdown
Collaborator

changes to the core type system

cc @lcnr

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels May 15, 2026
@rust-log-analyzer

This comment has been minimized.

Comment on lines +1001 to +1018
for (pred, _) in tcx
.explicit_implied_predicates_of(principal_def_id)
.iter_instantiated_copied(tcx, args)
.map(Unnormalized::skip_norm_wip)
{
if !pred.has_escaping_bound_vars()
&& !matches!(
pred.kind().skip_binder(),
ty::ClauseKind::Trait(tp) if tp.self_ty() == t
)
{
self.out.push(traits::Obligation::with_depth(
tcx,
self.cause(ObligationCauseCode::WellFormed(None)),
self.recursion_depth,
self.param_env,
pred,
));

@traviscross traviscross May 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider, e.g.:

trait Tr<X>: 'static {}
struct S<'a, X>(&'a dyn Tr<X>);

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what exactly do you mean? You refer to the impact of this on implied bounds?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested that filtering out ty::ClauseKind::TypeOutlives fixes this particular problem. I am not sure if we do not hit something else by this. If this is the correct fix, we should probably also filter ty::ClauseKind::RegionOutlives(..).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what exactly do you mean?

As @spirali inferred and addressed, this branch had regressed that case.

.explicit_implied_predicates_of(principal_def_id)
.iter_instantiated_copied(tcx, args)
.map(Unnormalized::skip_norm_wip)
{

@lcnr lcnr Jun 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should already return these as part of the nominal_obligations and then filter them out, do we not?

I am not 100% sure about this, but would expect so. I don't have a good sense of whether we should filter them out, I feel like it depends on what we want to do with trait objects long term. Their current state is quite a mess sadly

This is not required for soundness, is it? as we do check these bounds when proving dyn Tr: Tr

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that I understand. I have originally tried to implement it in the nominal_obligations cycle, but then I do not know how to distinguish the case:

trait Trait<T: Sized> {}

fn foo(_: &dyn Trait<[u32]>) {}

AFAIK it should compile as we are just mentioning the type and not constructing it.

@lcnr lcnr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry for the late review, the last weeks have been quite busy :x

View changes since this review

@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job aarch64-gnu-llvm-21-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
Saved the actual stderr to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/traits/next-solver/more-object-bound/more-object-bound.stderr`
diff of stderr:

3    |
4 LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
5    |                 ^^^^^^^^^^^^^^^^^^^^^^^ types differ
+ 
+ error[E0271]: type mismatch resolving `A == B`
+   --> $DIR/more-object-bound.rs:12:5
6    |
-    = note: required because it appears within the type `dyn Trait<A = A, B = B>`
- note: required by a bound in `foo`
-   --> $DIR/more-object-bound.rs:18:8
+ LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
+    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+ 
+ error[E0271]: type mismatch resolving `A == B`
+   --> $DIR/more-object-bound.rs:12:5
10    |
- LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B
-    |    --- required by a bound in this function
- LL | where
- LL |     T: Trait<B = B>,
-    |        ^^^^^^^^^^^^ required by this bound in `foo`
+ LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
+    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
16 
- error: aborting due to 1 previous error
+ error: aborting due to 3 previous errors
18 
---
-   --> /checkout/tests/ui/traits/next-solver/more-object-bound.rs:12:5
+ 
+ error[E0271]: type mismatch resolving `A == B`
+   --> $DIR/more-object-bound.rs:12:5
+ LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
+    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+ 
+ error[E0271]: type mismatch resolving `A == B`
+   --> $DIR/more-object-bound.rs:12:5
+ LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
+    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+ error: aborting due to 3 previous errors


The actual stderr differed from the expected stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args traits/next-solver/more-object-bound.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/traits/next-solver/more-object-bound.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/traits/next-solver/more-object-bound" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "-Znext-solver"
stdout: none
--- stderr -------------------------------
error[E0271]: type mismatch resolving `A == B`
##[error]  --> /checkout/tests/ui/traits/next-solver/more-object-bound.rs:12:17
   |
LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
   |                 ^^^^^^^^^^^^^^^^^^^^^^^ types differ

error[E0271]: type mismatch resolving `A == B`
##[error]  --> /checkout/tests/ui/traits/next-solver/more-object-bound.rs:12:5
   |
LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ

error[E0271]: type mismatch resolving `A == B`
##[error]  --> /checkout/tests/ui/traits/next-solver/more-object-bound.rs:12:5
   |
LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0271`.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Associated type bound from supertrait isn't checked for trait object

6 participants