Skip to content
Merged
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
18 changes: 12 additions & 6 deletions compiler/rustc_ty_utils/src/layout.rs
Copy link
Member

Choose a reason for hiding this comment

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

Before 5dfbf67 (the commit that revealed the bug this fixes) we had this in the middle of borrowck:

            &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => {
                let trait_ref =
                    ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [ty]);

                self.prove_trait_ref(
                    trait_ref,
                    location.to_locations(),
                    ConstraintCategory::SizedBound,
                );
            }

Was that .prove_trait_ref(..., ..., ConstraintCategory::SizedBound) what was "rescuing" this code from having to think about this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so, the code broken by his compiled previously and this check could have at most resulted in errors.

The reason this regressed is that we've added new associated constants to the standard library causing us to evaluate things and to check their layout in more places

Original file line number Diff line number Diff line change
Expand Up @@ -764,14 +764,20 @@ fn layout_of_uncached<'tcx>(
}

ty::Alias(..) => {
// NOTE(eddyb) `layout_of` query should've normalized these away,
// if that was possible, so there's no reason to try again here.
let err = if ty.has_param() {
// In case we're still in a generic context, aliases might be rigid. E.g.
// if we've got a `T: Trait` where-bound, `T::Assoc` cannot be normalized
// in the current context.
//
// For some builtin traits, generic aliases can be rigid even in an empty environment,
// e.g. `<T as Pointee>::Metadata`.
//
// Due to trivial bounds, this can even be the case if the alias does not reference
// any generic parameters, e.g. a `for<'a> u32: Trait<'a>` where-bound means that
// `<u32 as Trait<'static>>::Assoc` is rigid.
let err = if ty.has_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
Copy link
Member

Choose a reason for hiding this comment

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

This seems like a weird fix? Like, just because there were where clauses, doesn't mean they they were even relevant to the alias, right? Like, this would mean that <u32 as Trait<'static>>::Assoc would be "too generic", if there is a where clause like where u8: Foo, but "unknown" if there isn't that bound, even though that where clause seemingly makes no difference?

I'm not sure I have a better easy solution in mind. As a heuristic, we could see if there is a bound like X: Y<...> if the alias is <X as Y<...>>::Z - this is not quite enough, because that doesn't guarantee that it could be normalized even if not too-generic, but is better than a blank check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, I don't care as the else branch is actually unreachable as normalization should have failed for non-wf aliases, so the only way you can get an alias in layout_of is if it is still rigid.

LayoutError::TooGeneric(ty)
} else {
// This is only reachable with unsatisfiable predicates. For example, if we have
// `u8: Iterator`, then we can't compute the layout of `<u8 as Iterator>::Item`.
LayoutError::Unknown(ty)
unreachable!("invalid rigid alias in layout_of after normalization: {ty:?}");
};
return Err(error(cx, err));
}
Expand Down
12 changes: 6 additions & 6 deletions tests/rustdoc-html/type-layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ pub type GenericTypeAlias = (Generic<(u32, ())>, Generic<u32>);
//@ hasraw type_layout/type.Edges.html 'Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.'
pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>;

pub trait Project { type Assoc; }
// We can't compute layout as the alias stays rigid. A `LayoutError::TooGeneric` is returned.
//@ hasraw type_layout/struct.RigidAlias.html 'Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.'
//@ !hasraw - 'Size: '
pub struct RigidAlias(<() as Project>::Assoc) where for<'a> (): Project;

//@ !hasraw type_layout/trait.MyTrait.html 'Size: '
pub trait MyTrait {}

Expand Down Expand Up @@ -92,9 +98,3 @@ pub enum Uninhabited {}
//@ hasraw type_layout/struct.Uninhabited2.html 'Size: '
//@ hasraw - '8 bytes (<a href="{{channel}}/reference/glossary.html#uninhabited">uninhabited</a>)'
pub struct Uninhabited2(std::convert::Infallible, u64);

pub trait Project { type Assoc; }
// We can't compute layout. A `LayoutError::Unknown` is returned.
//@ hasraw type_layout/struct.Unknown.html 'Unable to compute type layout.'
//@ !hasraw - 'Size: '
pub struct Unknown(<() as Project>::Assoc) where for<'a> (): Project;
30 changes: 30 additions & 0 deletions tests/ui/layout/rigid-alias-no-params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//@ compile-flags: -O -Cdebug-assertions=on
//@ build-pass

// A regression test for #151791. Computing the layout of
// `<AsOwned as ArchiveWith<'a>>::Archived` fails as the alias
// is still rigid as the where-bound in scope shadows the impl.
//
// This previously caused an incorrect error during MIR optimizations.

struct ArchivedString;

pub trait ArchiveWith<'a> {
type Archived;
}

struct AsOwned;
impl ArchiveWith<'_> for AsOwned {
type Archived = ArchivedString;
}

fn foo<'a>()
where
AsOwned: ArchiveWith<'a>,
{
let _ = unsafe { &*std::ptr::dangling::<<AsOwned as ArchiveWith<'a>>::Archived>() };
}

fn main() {
foo();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//@ build-pass

// A regression test for #149081. The environment of `size` and `align`
// currently means that the item bound of`T::Assoc` doesn't hold. This can
// currently means that the item bound of `T::Assoc` doesn't hold. This can
// result in normalization failures and ICE during MIR optimizations.
//
// This will no longer be an issue once #149283 is implemented.
Expand Down
Loading