Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
bc8c3ef
CFI: Change type transformation to use TypeFolder
rcvalle Mar 30, 2024
e457b77
Avoid panicking unnecessarily on startup
ChrisDenton Apr 2, 2024
50103ab
Add tests
Nadrieril Mar 10, 2024
8f80259
Explain false edges in more detail
Nadrieril Mar 10, 2024
8021192
More precise false edges
Nadrieril Apr 1, 2024
61ac781
Stabilize `Literal::byte_character`
slanterns Apr 3, 2024
fbc56df
Stabilize `Literal::c_string`
slanterns Apr 3, 2024
e2ebaa1
Add `if let` tests
Nadrieril Apr 3, 2024
f029602
Tests for getting parent of synthetic HIR
compiler-errors Apr 3, 2024
e08fdb0
coverage: Remove useless constants
Zalathar Apr 4, 2024
109daa2
Fix diagnostic for qualifier in extern block
krtab Apr 3, 2024
3137143
Error out of layout calculation if a non-last struct field is unsized
gurry Apr 4, 2024
2575b8e
move hir-tree test from run-make to ui test
high-cloud Mar 13, 2024
7b8f93e
Add comments about using debug_assert
ChrisDenton Apr 4, 2024
d5a657c
Rollup merge of #121546 - gurry:121473-ice-sizeof-mir-op, r=oli-obk
matthiaskrgr Apr 4, 2024
0b54db7
Rollup merge of #122448 - high-cloud:move-hir-tree, r=oli-obk
matthiaskrgr Apr 4, 2024
f03535b
Rollup merge of #123212 - rcvalle:rust-cfi-use-type-folder, r=compile…
matthiaskrgr Apr 4, 2024
7c2d4ea
Rollup merge of #123218 - compiler-errors:synthetic-hir-parent, r=pet…
matthiaskrgr Apr 4, 2024
504a78e
Rollup merge of #123324 - Nadrieril:false-edges2, r=matthewjasper
matthiaskrgr Apr 4, 2024
ee5009e
Rollup merge of #123389 - ChrisDenton:dont-panic-on-startup, r=joboet
matthiaskrgr Apr 4, 2024
f254ab0
Rollup merge of #123397 - krtab:foreign_fn_qualif_diag, r=petrochenkov
matthiaskrgr Apr 4, 2024
ad300b6
Rollup merge of #123431 - slanterns:literal_byte_character_c_string_s…
matthiaskrgr Apr 4, 2024
4ba3f46
Rollup merge of #123439 - Zalathar:constants, r=oli-obk
matthiaskrgr Apr 4, 2024
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
Prev Previous commit
Next Next commit
Error out of layout calculation if a non-last struct field is unsized
Fixes an ICE that occurs when a struct with an unsized field
at a non-last position is const evaluated.
  • Loading branch information
gurry committed Apr 4, 2024
commit 313714331ac3fbc63e767fe95d175f293cf5d875
38 changes: 37 additions & 1 deletion compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
79 changes: 79 additions & 0 deletions tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs
Original file line number Diff line number Diff line change
@@ -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 };
}
106 changes: 106 additions & 0 deletions tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr
Original file line number Diff line number Diff line change
@@ -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`.