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
15 changes: 10 additions & 5 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1510,11 +1510,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
return;
}

let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did());
// For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
// "known" respecting #[non_exhaustive] attributes.
let field_infos = adt.all_fields().map(|field| {
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did);
Copy link
Member Author

Choose a reason for hiding this comment

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

Previously we used the field DefId here, now we're using the DefId of the surrounding ADT -- I hope that doesn't make a difference.

let layout = tcx.layout_of(typing_env.as_query_input(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir_span_if_local(field.did).unwrap();
Expand All @@ -1526,11 +1526,16 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)

fn check_non_exhaustive<'tcx>(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
t: Ty<'tcx>,
) -> ControlFlow<(&'static str, DefId, GenericArgsRef<'tcx>, bool)> {
// We can encounter projections during traversal, so ensure the type is normalized.
let t = tcx.try_normalize_erasing_regions(typing_env, t).unwrap_or(t);
match t.kind() {
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
ty::Tuple(list) => {
list.iter().try_for_each(|t| check_non_exhaustive(tcx, typing_env, t))
}
ty::Array(ty, _) => check_non_exhaustive(tcx, typing_env, *ty),
ty::Adt(def, args) => {
if !def.did().is_local()
&& !find_attr!(
Expand All @@ -1555,13 +1560,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
}
def.all_fields()
.map(|field| field.ty(tcx, args))
.try_for_each(|t| check_non_exhaustive(tcx, t))
.try_for_each(|t| check_non_exhaustive(tcx, typing_env, t))
}
_ => ControlFlow::Continue(()),
}
}

(span, trivial, check_non_exhaustive(tcx, ty).break_value())
(span, trivial, check_non_exhaustive(tcx, typing_env, ty).break_value())
});

let non_trivial_fields = field_infos
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/repr/repr-transparent-non-exhaustive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ pub struct InternalIndirection<T> {

pub type Sized = i32;

pub trait Trait {
type Assoc;
}
impl Trait for i32 {
type Assoc = NonExhaustive;
}

#[repr(transparent)]
pub struct T1(Sized, InternalPrivate);
#[repr(transparent)]
Expand All @@ -43,6 +50,11 @@ pub struct T6(Sized, NonExhaustive);
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
//~| WARN this was previously accepted by the compiler

#[repr(transparent)]
pub struct T6a(Sized, <i32 as Trait>::Assoc); // normalizes to `NonExhaustive`
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
//~| WARN this was previously accepted by the compiler

#[repr(transparent)]
pub struct T7(Sized, NonExhaustiveEnum);
//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
Expand Down
44 changes: 27 additions & 17 deletions tests/ui/repr/repr-transparent-non-exhaustive.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:37:22
--> $DIR/repr-transparent-non-exhaustive.rs:44:22
|
LL | pub struct T5(Sized, Private);
| ^^^^^^^
Expand All @@ -14,7 +14,7 @@ LL | #![deny(repr_transparent_external_private_fields)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:42:22
--> $DIR/repr-transparent-non-exhaustive.rs:49:22
|
LL | pub struct T6(Sized, NonExhaustive);
| ^^^^^^^^^^^^^
Expand All @@ -24,7 +24,17 @@ LL | pub struct T6(Sized, NonExhaustive);
= note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:47:22
--> $DIR/repr-transparent-non-exhaustive.rs:54:23
|
LL | pub struct T6a(Sized, <i32 as Trait>::Assoc); // normalizes to `NonExhaustive`
| ^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
= note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:59:22
|
LL | pub struct T7(Sized, NonExhaustiveEnum);
| ^^^^^^^^^^^^^^^^^
Expand All @@ -34,7 +44,7 @@ LL | pub struct T7(Sized, NonExhaustiveEnum);
= note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:52:22
--> $DIR/repr-transparent-non-exhaustive.rs:64:22
|
LL | pub struct T8(Sized, NonExhaustiveVariant);
| ^^^^^^^^^^^^^^^^^^^^
Expand All @@ -44,7 +54,7 @@ LL | pub struct T8(Sized, NonExhaustiveVariant);
= note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:57:22
--> $DIR/repr-transparent-non-exhaustive.rs:69:22
|
LL | pub struct T9(Sized, InternalIndirection<Private>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -54,7 +64,7 @@ LL | pub struct T9(Sized, InternalIndirection<Private>);
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:62:23
--> $DIR/repr-transparent-non-exhaustive.rs:74:23
|
LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -64,7 +74,7 @@ LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>);
= note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:67:23
--> $DIR/repr-transparent-non-exhaustive.rs:79:23
|
LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -74,7 +84,7 @@ LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
= note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:72:23
--> $DIR/repr-transparent-non-exhaustive.rs:84:23
|
LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -84,7 +94,7 @@ LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
= note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:77:23
--> $DIR/repr-transparent-non-exhaustive.rs:89:23
|
LL | pub struct T13(Sized, ExternalIndirection<Private>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -94,7 +104,7 @@ LL | pub struct T13(Sized, ExternalIndirection<Private>);
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:82:23
--> $DIR/repr-transparent-non-exhaustive.rs:94:23
|
LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -104,7 +114,7 @@ LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
= note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:87:23
--> $DIR/repr-transparent-non-exhaustive.rs:99:23
|
LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -114,7 +124,7 @@ LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
= note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:92:23
--> $DIR/repr-transparent-non-exhaustive.rs:104:23
|
LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -124,7 +134,7 @@ LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
= note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:97:16
--> $DIR/repr-transparent-non-exhaustive.rs:109:16
|
LL | pub struct T17(NonExhaustive, Sized);
| ^^^^^^^^^^^^^
Expand All @@ -134,7 +144,7 @@ LL | pub struct T17(NonExhaustive, Sized);
= note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:102:31
--> $DIR/repr-transparent-non-exhaustive.rs:114:31
|
LL | pub struct T18(NonExhaustive, NonExhaustive);
| ^^^^^^^^^^^^^
Expand All @@ -144,7 +154,7 @@ LL | pub struct T18(NonExhaustive, NonExhaustive);
= note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:107:31
--> $DIR/repr-transparent-non-exhaustive.rs:119:31
|
LL | pub struct T19(NonExhaustive, Private);
| ^^^^^^^
Expand All @@ -154,7 +164,7 @@ LL | pub struct T19(NonExhaustive, Private);
= note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.

error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
--> $DIR/repr-transparent-non-exhaustive.rs:112:32
--> $DIR/repr-transparent-non-exhaustive.rs:124:32
|
LL | pub struct T19Flipped(Private, NonExhaustive);
| ^^^^^^^^^^^^^
Expand All @@ -163,5 +173,5 @@ LL | pub struct T19Flipped(Private, NonExhaustive);
= note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
= note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.

error: aborting due to 16 previous errors
error: aborting due to 17 previous errors

Loading