Add a because to errors derived from fields

This commit is contained in:
Oli Scherer 2022-11-07 10:48:40 +00:00
parent 9b6f8e500c
commit 5446a52b4b
2 changed files with 33 additions and 34 deletions

View File

@ -2410,7 +2410,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
/// Information about why a type cannot be initialized this way.
struct InitError {
message: String,
/// Spans from struct fields and similar can be obtained from just the type.
/// Spans from struct fields and similar that can be obtained from just the type.
span: Option<Span>,
/// Used to report a trace through adts.
nested: Option<Box<InitError>>,
@ -2497,7 +2497,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
descr: &str,
init: InitKind,
) -> Option<InitError> {
let field_err = variant.fields.iter().find_map(|field| {
let mut field_err = variant.fields.iter().find_map(|field| {
ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(|mut err| {
if !field.did.is_local() {
err
@ -2515,28 +2515,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
// Check if this ADT has a constrained layout (like `NonNull` and friends).
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) {
match &layout.abi {
Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) => {
let range = scalar.valid_range(cx);
if !range.contains(0) {
return Some(
InitError::from(format!("`{}` must be non-null", ty))
.nested(field_err),
);
} else if init == InitKind::Uninit && !scalar.is_always_valid(cx) {
// Prefer reporting on the fields over the entire struct for uninit,
// as the information bubbles out and it may be unclear why the type can't
// be null from just its outside signature.
return Some(
InitError::from(format!(
"`{}` must be initialized inside its custom valid range",
ty,
))
.nested(field_err),
);
if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &layout.abi {
let range = scalar.valid_range(cx);
let msg = if !range.contains(0) {
"must be non-null"
} else if init == InitKind::Uninit && !scalar.is_always_valid(cx) {
// Prefer reporting on the fields over the entire struct for uninit,
// as the information bubbles out and it may be unclear why the type can't
// be null from just its outside signature.
"must be initialized inside its custom valid range"
} else {
return field_err;
};
if let Some(field_err) = &mut field_err {
// Most of the time, if the field error is the same as the struct error,
// the struct error only happens because of the field error.
if field_err.message.contains(msg) {
field_err.message = format!("because {}", field_err.message);
}
}
_ => {}
return Some(InitError::from(format!("`{ty}` {msg}")).nested(field_err));
}
}
field_err

View File

@ -35,7 +35,7 @@ LL | let _val: Wrap<&'static T> = mem::zeroed();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `Wrap<&T>` must be non-null
note: references must be non-null (in this struct field)
note: because references must be non-null (in this struct field)
--> $DIR/invalid_value.rs:17:18
|
LL | struct Wrap<T> { wrapped: T }
@ -51,7 +51,7 @@ LL | let _val: Wrap<&'static T> = mem::uninitialized();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `Wrap<&T>` must be non-null
note: references must be non-null (in this struct field)
note: because references must be non-null (in this struct field)
--> $DIR/invalid_value.rs:17:18
|
LL | struct Wrap<T> { wrapped: T }
@ -163,7 +163,7 @@ LL | let _val: Ref = mem::zeroed();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `Ref` must be non-null
note: references must be non-null (in this struct field)
note: because references must be non-null (in this struct field)
--> $DIR/invalid_value.rs:14:12
|
LL | struct Ref(&'static i32);
@ -179,7 +179,7 @@ LL | let _val: Ref = mem::uninitialized();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `Ref` must be non-null
note: references must be non-null (in this struct field)
note: because references must be non-null (in this struct field)
--> $DIR/invalid_value.rs:14:12
|
LL | struct Ref(&'static i32);
@ -217,7 +217,7 @@ LL | let _val: Wrap<fn()> = mem::zeroed();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `Wrap<fn()>` must be non-null
note: function pointers must be non-null (in this struct field)
note: because function pointers must be non-null (in this struct field)
--> $DIR/invalid_value.rs:17:18
|
LL | struct Wrap<T> { wrapped: T }
@ -233,7 +233,7 @@ LL | let _val: Wrap<fn()> = mem::uninitialized();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `Wrap<fn()>` must be non-null
note: function pointers must be non-null (in this struct field)
note: because function pointers must be non-null (in this struct field)
--> $DIR/invalid_value.rs:17:18
|
LL | struct Wrap<T> { wrapped: T }
@ -249,7 +249,7 @@ LL | let _val: WrapEnum<fn()> = mem::zeroed();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `WrapEnum<fn()>` must be non-null
note: function pointers must be non-null (in this field of the only potentially inhabited enum variant)
note: because function pointers must be non-null (in this field of the only potentially inhabited enum variant)
--> $DIR/invalid_value.rs:18:28
|
LL | enum WrapEnum<T> { Wrapped(T) }
@ -265,7 +265,7 @@ LL | let _val: WrapEnum<fn()> = mem::uninitialized();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `WrapEnum<fn()>` must be non-null
note: function pointers must be non-null (in this field of the only potentially inhabited enum variant)
note: because function pointers must be non-null (in this field of the only potentially inhabited enum variant)
--> $DIR/invalid_value.rs:18:28
|
LL | enum WrapEnum<T> { Wrapped(T) }
@ -285,7 +285,7 @@ note: `RefPair` must be non-null (in this struct field)
|
LL | struct Wrap<T> { wrapped: T }
| ^^^^^^^^^^
note: references must be non-null (in this struct field)
note: because references must be non-null (in this struct field)
--> $DIR/invalid_value.rs:15:16
|
LL | struct RefPair((&'static i32, i32));
@ -305,7 +305,7 @@ note: `RefPair` must be non-null (in this struct field)
|
LL | struct Wrap<T> { wrapped: T }
| ^^^^^^^^^^
note: references must be non-null (in this struct field)
note: because references must be non-null (in this struct field)
--> $DIR/invalid_value.rs:15:16
|
LL | struct RefPair((&'static i32, i32));
@ -441,7 +441,7 @@ LL | let _val: OneFruitNonZero = mem::zeroed();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `OneFruitNonZero` must be non-null
note: `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant)
note: because `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant)
--> $DIR/invalid_value.rs:39:12
|
LL | Banana(NonZeroU32),
@ -457,7 +457,7 @@ LL | let _val: OneFruitNonZero = mem::uninitialized();
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `OneFruitNonZero` must be non-null
note: `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant)
note: because `std::num::NonZeroU32` must be non-null (in this field of the only potentially inhabited enum variant)
--> $DIR/invalid_value.rs:39:12
|
LL | Banana(NonZeroU32),