Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,25 +625,34 @@ impl<'tcx> Instance<'tcx> {
})
}

pub fn expect_resolve_for_vtable(
/// Fallible version of [`Instance::expect_resolve_for_vtable`].
///
/// Returns `Err` if instance resolution fails, e.g. due to a broken
/// impl with unsatisfied supertrait bounds.
pub fn try_resolve_for_vtable(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
def_id: DefId,
args: GenericArgsRef<'tcx>,
span: Span,
) -> Instance<'tcx> {
debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args);
) -> Result<Instance<'tcx>, ErrorGuaranteed> {
debug!("try_resolve_for_vtable(def_id={:?}, args={:?})", def_id, args);
let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
&& fn_sig.input(0).skip_binder().is_param(0)
&& tcx.generics_of(def_id).has_self;

if is_vtable_shim {
debug!(" => associated item with unsizeable self: Self");
return Instance { def: InstanceKind::VTableShim(def_id), args };
return Ok(Instance { def: InstanceKind::VTableShim(def_id), args });
}

let mut resolved = Instance::expect_resolve(tcx, typing_env, def_id, args, span);
let mut resolved =
Instance::try_resolve(tcx, typing_env, def_id, args)?.ok_or_else(|| {
tcx.dcx().delayed_bug(format!(
"failed to resolve instance for vtable: {}",
tcx.def_path_str_with_args(def_id, args)
))
})?;

let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
match resolved.def {
Expand Down Expand Up @@ -700,7 +709,25 @@ impl<'tcx> Instance<'tcx> {
_ => {}
}

resolved
Ok(resolved)
}

pub fn expect_resolve_for_vtable(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
def_id: DefId,
args: GenericArgsRef<'tcx>,
span: Span,
) -> Instance<'tcx> {
Instance::try_resolve_for_vtable(tcx, typing_env, def_id, args).unwrap_or_else(|e| {
let span =
if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span };
span_bug!(
span,
"failed to resolve instance for {}: {e:#?}",
tcx.def_path_str_with_args(def_id, args)
)
})
}

pub fn resolve_closure(
Expand Down
18 changes: 12 additions & 6 deletions compiler/rustc_trait_selection/src/traits/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::{
self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
};
use rustc_span::DUMMY_SP;
use smallvec::{SmallVec, smallvec};
use tracing::debug;

Expand Down Expand Up @@ -285,15 +284,22 @@ fn vtable_entries<'tcx>(
return VtblEntry::Vacant;
}

let instance = ty::Instance::expect_resolve_for_vtable(
match ty::Instance::try_resolve_for_vtable(
tcx,
ty::TypingEnv::fully_monomorphized(),
def_id,
args,
DUMMY_SP,
);

VtblEntry::Method(instance)
) {
Ok(instance) => VtblEntry::Method(instance),
Err(_guar) => {
// This can happen when building a vtable for a type
// whose impl has unsatisfied supertrait bounds (an
// error for which has already been emitted). In that
// case the supertrait's methods can't be resolved,
// so we mark the entry as vacant.
VtblEntry::Vacant
}
}
});

entries.extend(own_entries);
Expand Down
18 changes: 0 additions & 18 deletions tests/crashes/137190-2.rs

This file was deleted.

10 changes: 0 additions & 10 deletions tests/crashes/137190-3.rs

This file was deleted.

2 changes: 1 addition & 1 deletion tests/ui/limits/type-length-limit-enforcement.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//~ ERROR reached the type-length limit
//~? ERROR reached the type-length limit
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is because of the change in ordering.


//! Checks the enforcement of the type-length limit
//! and its configurability via `#![type_length_limit]`.
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/limits/type-length-limit-enforcement.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ LL | drop::<Option<A>>(None);
= note: the full name for the type has been written to '$TEST_BUILD_DIR/type-length-limit-enforcement.long-type-$LONG_TYPE_HASH.txt'
= note: consider using `--verbose` to print the full type name to the console

error: reached the type-length limit while instantiating `<{closure@...} as FnMut<()>>::call_mut`
error: reached the type-length limit while instantiating `<{closure@...} as FnOnce<()>>::call_once`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is also because of the change in ordering.

--> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
= help: consider adding a `#![type_length_limit="10"]` attribute to your crate
= note: the full name for the type has been written to '$TEST_BUILD_DIR/type-length-limit-enforcement.long-type-$LONG_TYPE_HASH.txt'
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/traits/vtable/vtable-missing-method-impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Regression test for #154073.
// Verify that we don't ICE when building vtable entries
// for a trait whose impl is missing a required method body.

//@ compile-flags: --crate-type lib

trait Bar: Sync {
fn method(&self);
}
impl<T: Sync> Bar for T {
//~^ ERROR not all trait items implemented
}

static BAR: &dyn Sync = &false as &dyn Bar;
12 changes: 12 additions & 0 deletions tests/ui/traits/vtable/vtable-missing-method-impl.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0046]: not all trait items implemented, missing: `method`
--> $DIR/vtable-missing-method-impl.rs:10:1
|
LL | fn method(&self);
| ----------------- `method` from trait
LL | }
LL | impl<T: Sync> Bar for T {
| ^^^^^^^^^^^^^^^^^^^^^^^ missing `method` in implementation

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0046`.
22 changes: 22 additions & 0 deletions tests/ui/traits/vtable/vtable-unsatisfied-supertrait-const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Regression test for #154073.
// Verify that we don't ICE when building vtable entries
// for a trait whose supertrait is not implemented, during
// const evaluation of a static initializer.

//@ compile-flags: --crate-type lib

trait Bar: Send + Sync + Droppable {}

impl<T: Send> Bar for T {}
//~^ ERROR the trait bound `T: Droppable` is not satisfied
//~| ERROR `T` cannot be shared between threads safely

trait Droppable {
fn drop(&self);
}

const fn upcast(x: &dyn Bar) -> &(dyn Send + Sync) {
x
}

static BAR: &(dyn Send + Sync) = upcast(&false);
35 changes: 35 additions & 0 deletions tests/ui/traits/vtable/vtable-unsatisfied-supertrait-const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
error[E0277]: the trait bound `T: Droppable` is not satisfied
--> $DIR/vtable-unsatisfied-supertrait-const.rs:10:23
|
LL | impl<T: Send> Bar for T {}
| ^ the trait `Droppable` is not implemented for `T`
|
note: required by a bound in `Bar`
--> $DIR/vtable-unsatisfied-supertrait-const.rs:8:26
|
LL | trait Bar: Send + Sync + Droppable {}
| ^^^^^^^^^ required by this bound in `Bar`
help: consider further restricting type parameter `T` with trait `Droppable`
|
LL | impl<T: Send + Droppable> Bar for T {}
| +++++++++++

error[E0277]: `T` cannot be shared between threads safely
--> $DIR/vtable-unsatisfied-supertrait-const.rs:10:23
|
LL | impl<T: Send> Bar for T {}
| ^ `T` cannot be shared between threads safely
|
note: required by a bound in `Bar`
--> $DIR/vtable-unsatisfied-supertrait-const.rs:8:19
|
LL | trait Bar: Send + Sync + Droppable {}
| ^^^^ required by this bound in `Bar`
help: consider further restricting type parameter `T` with trait `Sync`
|
LL | impl<T: Send + std::marker::Sync> Bar for T {}
| +++++++++++++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
25 changes: 25 additions & 0 deletions tests/ui/traits/vtable/vtable-unsatisfied-supertrait-generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Regression test for #137190.
// Variant of vtable-unsatisfied-supertrait.rs with generic traits.
// Verify that we don't ICE when building vtable entries
// for a generic trait whose supertrait is not implemented.

//@ compile-flags: --crate-type lib

trait Supertrait<T> {
fn method(&self) {}
}

trait Trait<P>: Supertrait<()> {}

impl<P> Trait<P> for () {}
//~^ ERROR the trait bound `(): Supertrait<()>` is not satisfied

const fn upcast<P>(x: &dyn Trait<P>) -> &dyn Supertrait<()> {
x
}

const fn foo() -> &'static dyn Supertrait<()> {
upcast::<()>(&())
}

const _: &'static dyn Supertrait<()> = foo();
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0277]: the trait bound `(): Supertrait<()>` is not satisfied
--> $DIR/vtable-unsatisfied-supertrait-generics.rs:14:22
|
LL | impl<P> Trait<P> for () {}
| ^^ the trait `Supertrait<()>` is not implemented for `()`
|
help: this trait has no implementations, consider adding one
--> $DIR/vtable-unsatisfied-supertrait-generics.rs:8:1
|
LL | trait Supertrait<T> {
| ^^^^^^^^^^^^^^^^^^^
note: required by a bound in `Trait`
--> $DIR/vtable-unsatisfied-supertrait-generics.rs:12:17
|
LL | trait Trait<P>: Supertrait<()> {}
| ^^^^^^^^^^^^^^ required by this bound in `Trait`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
16 changes: 16 additions & 0 deletions tests/ui/traits/vtable/vtable-unsatisfied-supertrait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Regression test for #137190.
// Verify that we don't ICE when building vtable entries
// for a trait whose supertrait is not implemented.

//@ compile-flags: --crate-type lib

trait Supertrait {
fn method(&self) {}
}

trait Trait: Supertrait {}

impl Trait for () {}
//~^ ERROR the trait bound `(): Supertrait` is not satisfied

const _: &dyn Supertrait = &() as &dyn Trait as &dyn Supertrait;
20 changes: 20 additions & 0 deletions tests/ui/traits/vtable/vtable-unsatisfied-supertrait.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0277]: the trait bound `(): Supertrait` is not satisfied
--> $DIR/vtable-unsatisfied-supertrait.rs:13:16
|
LL | impl Trait for () {}
| ^^ the trait `Supertrait` is not implemented for `()`
|
help: this trait has no implementations, consider adding one
--> $DIR/vtable-unsatisfied-supertrait.rs:7:1
|
LL | trait Supertrait {
| ^^^^^^^^^^^^^^^^
note: required by a bound in `Trait`
--> $DIR/vtable-unsatisfied-supertrait.rs:11:14
|
LL | trait Trait: Supertrait {}
| ^^^^^^^^^^ required by this bound in `Trait`

error: aborting due to 1 previous error

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