diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index dd1f2322c41..4ecb0ea7cd9 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -8,7 +8,9 @@ use rustc_middle::ty::layout::{
     IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
+};
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
@@ -506,6 +508,40 @@ fn layout_of_uncached<'tcx>(
                 ));
             }
 
+            let err_if_unsized = |field: &FieldDef, err_msg: &str| {
+                let field_ty = tcx.type_of(field.did);
+                let is_unsized = tcx
+                    .try_instantiate_and_normalize_erasing_regions(args, cx.param_env, field_ty)
+                    .map(|f| !f.is_sized(tcx, cx.param_env))
+                    .map_err(|e| {
+                        error(
+                            cx,
+                            LayoutError::NormalizationFailure(field_ty.instantiate_identity(), e),
+                        )
+                    })?;
+
+                if is_unsized {
+                    cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
+                    Err(error(cx, LayoutError::Unknown(ty)))
+                } else {
+                    Ok(())
+                }
+            };
+
+            if def.is_struct() {
+                if let Some((_, fields_except_last)) =
+                    def.non_enum_variant().fields.raw.split_last()
+                {
+                    for f in fields_except_last {
+                        err_if_unsized(f, "only the last field of a struct can be unsized")?;
+                    }
+                }
+            } else {
+                for f in def.all_fields() {
+                    err_if_unsized(f, &format!("{}s cannot have unsized fields", def.descr()))?;
+                }
+            }
+
             let get_discriminant_type =
                 |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);
 
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
new file mode 100644
index 00000000000..737a7ffbc29
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
@@ -0,0 +1,79 @@
+// Regression test for #121473
+// Checks that no ICE occurs when `size_of`
+// is applied to a struct that has an unsized
+// field which is not its last field
+
+use std::mem::size_of;
+
+pub struct BadStruct {
+    pub field1: i32,
+    pub field2: str, // Unsized field that is not the last field
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    pub field3: [u8; 16],
+}
+
+enum BadEnum1 {
+    Variant1 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+}
+
+enum BadEnum2 {
+    Variant1(
+        i32,
+        str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        [u8; 16]
+    ),
+}
+
+enum BadEnumMultiVariant {
+    Variant1(i32),
+    Variant2 {
+        field1: i32,
+        field2: str, // Unsized
+        //~^ ERROR the size for values of type `str` cannot be known at compilation time
+        field3: [u8; 16],
+    },
+    Variant3
+}
+
+union BadUnion {
+    field1: i32,
+    field2: str, // Unsized
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+    field3: [u8; 16],
+}
+
+// Used to test that projection type fields that normalize
+// to a sized type do not cause problems
+struct StructWithProjections<'a>
+{
+    field1: <&'a [i32] as IntoIterator>::IntoIter,
+    field2: i32
+}
+
+pub fn main() {
+    let _a = &size_of::<BadStruct>();
+    assert_eq!(size_of::<BadStruct>(), 21);
+
+    let _a = &size_of::<BadEnum1>();
+    assert_eq!(size_of::<BadEnum1>(), 21);
+
+    let _a = &size_of::<BadEnum2>();
+    assert_eq!(size_of::<BadEnum2>(), 21);
+
+    let _a = &size_of::<BadEnumMultiVariant>();
+    assert_eq!(size_of::<BadEnumMultiVariant>(), 21);
+
+    let _a = &size_of::<BadUnion>();
+    assert_eq!(size_of::<BadUnion>(), 21);
+
+    let _a = &size_of::<StructWithProjections>();
+    assert_eq!(size_of::<StructWithProjections>(), 21);
+    let _a = StructWithProjections { field1: [1, 3].iter(), field2: 3 };
+}
diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
new file mode 100644
index 00000000000..626be7ac283
--- /dev/null
+++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
@@ -0,0 +1,106 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:10:17
+   |
+LL |     pub field2: str, // Unsized field that is not the last field
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     pub field2: &str, // Unsized field that is not the last field
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     pub field2: Box<str>, // Unsized field that is not the last field
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:18:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:27:9
+   |
+LL |         str, // Unsized
+   |         ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         &str, // Unsized
+   |         +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         Box<str>, // Unsized
+   |         ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:37:17
+   |
+LL |         field2: str, // Unsized
+   |                 ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |         field2: &str, // Unsized
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |         field2: Box<str>, // Unsized
+   |                 ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:13
+   |
+LL |     field2: str, // Unsized
+   |             ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     field2: &str, // Unsized
+   |             +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     field2: Box<str>, // Unsized
+   |             ++++   +
+
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+  --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:5
+   |
+LL |     field2: str, // Unsized
+   |     ^^^^^^^^^^^
+   |
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
+   |
+LL |     field2: std::mem::ManuallyDrop<str>, // Unsized
+   |             +++++++++++++++++++++++   +
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0740.
+For more information about an error, try `rustc --explain E0277`.