Skip to content

Commit

Permalink
Rollup merge of #128171 - compiler-errors:arg-compat, r=oli-obk
Browse files Browse the repository at this point in the history
Make sure that args are compatible in `resolve_associated_item`

Implements a similar check to the one that we have in projection for GATs (#102488, #123240), where we check that the args of an impl item are compatible before returning it. This is done in `resolve_assoc_item`, which is backing `Instance::resolve`, so this is conceptually generalizing the check from GATs to methods/assoc consts. This is important to make sure that the inliner will only visit and substitute MIR bodies that are compatible w/ their trait definitions.

This shouldn't happen in codegen, but there are a few ways to get the inliner to be invoked (via calls to `optimized_mir`) before codegen, namely polymorphization and CTFE.

Fixes #121957
Fixes #120792
Fixes #120793
Fixes #121063
  • Loading branch information
matthiaskrgr authored Jul 25, 2024
2 parents 606c9fc + 40d132f commit 5a853d0
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 130 deletions.
15 changes: 13 additions & 2 deletions compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,22 @@ fn resolve_associated_item<'tcx>(

// Any final impl is required to define all associated items.
if !leaf_def.item.defaultness(tcx).has_value() {
let guard = tcx.dcx().span_delayed_bug(
let guar = tcx.dcx().span_delayed_bug(
tcx.def_span(leaf_def.item.def_id),
"missing value for assoc item in impl",
);
return Err(guard);
return Err(guar);
}

// Make sure that we're projecting to an item that has compatible args.
// This may happen if we are resolving an instance before codegen, such
// as during inlining. This check is also done in projection.
if !tcx.check_args_compatible(leaf_def.item.def_id, args) {
let guar = tcx.dcx().span_delayed_bug(
tcx.def_span(leaf_def.item.def_id),
"missing value for assoc item in impl",
);
return Err(guar);
}

let args = tcx.erase_regions(args);
Expand Down
25 changes: 0 additions & 25 deletions tests/crashes/120792.rs

This file was deleted.

22 changes: 0 additions & 22 deletions tests/crashes/120793-2.rs

This file was deleted.

21 changes: 0 additions & 21 deletions tests/crashes/120793.rs

This file was deleted.

20 changes: 0 additions & 20 deletions tests/crashes/121063.rs

This file was deleted.

20 changes: 0 additions & 20 deletions tests/crashes/121957-1.rs

This file was deleted.

20 changes: 0 additions & 20 deletions tests/crashes/121957-2.rs

This file was deleted.

27 changes: 27 additions & 0 deletions tests/ui/polymorphization/inline-incorrect-early-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// This test demonstrates an ICE that may occur when we try to resolve the instance
// of a impl that has different generics than the trait it's implementing. This ensures
// we first check that the args are compatible before resolving the body, just like
// we do in projection before substituting a GAT.
//
// When polymorphization is enabled, we check the optimized MIR for unused parameters.
// This will invoke the inliner, leading to this ICE.

//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes

trait Trait {
fn foo<'a, K: 'a>(self, _: K);
}

impl Trait for () {
#[inline]
fn foo<K>(self, _: K) {
//~^ ERROR lifetime parameters or bounds on method `foo` do not match the trait declaration
todo!();
}
}

pub fn qux<T>() {
().foo(());
}

fn main() {}
15 changes: 15 additions & 0 deletions tests/ui/polymorphization/inline-incorrect-early-bound.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
--> $DIR/inline-incorrect-early-bound.rs:17:11
|
LL | fn foo<'a, K: 'a>(self, _: K);
| -----------
| | |
| | this bound might be missing in the impl
| lifetimes in impl do not match this method in trait
...
LL | fn foo<K>(self, _: K) {
| ^^^ lifetimes do not match method in trait

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0195`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// This test demonstrates an ICE that may occur when we try to resolve the instance
// of a impl that has different generics than the trait it's implementing. This ensures
// we first check that the args are compatible before resolving the body, just like
// we do in projection before substituting a GAT.
//
// Const traits aren't the only way to achieve this ICE, but it's a convenient way
// to ensure the inliner is called.

//@ compile-flags: -Znext-solver -Zinline-mir=yes

#![feature(const_trait_impl, effects)]
//~^ WARN the feature `effects` is incomplete

trait Trait {
fn foo(self);
}

impl Trait for () {
#[inline]
fn foo<T>(self) {
//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters
todo!();
}
}

const fn foo() {
().foo();
}

const UWU: () = foo();

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/inline-incorrect-early-bound-in-ctfe.rs:11:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
|
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default

error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/inline-incorrect-early-bound-in-ctfe.rs:20:12
|
LL | fn foo(self);
| - expected 0 type parameters
...
LL | fn foo<T>(self) {
| ^ found 1 type parameter

error: aborting due to 1 previous error; 1 warning emitted

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

0 comments on commit 5a853d0

Please sign in to comment.