Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit be0e608

Browse files
committedMay 5, 2024
Auto merge of rust-lang#124769 - fmease:rollup-gwdj5yz, r=fmease
Rollup of 6 pull requests Successful merges: - rust-lang#124146 (Triagebot: Rename `macos` ping group to `apple`) - rust-lang#124742 (Add `rustfmt` cfg to well known cfgs list) - rust-lang#124745 (Implement lldb formattter for "clang encoded" enums (LLDB 18.1+) (v2)) - rust-lang#124747 (Support Result<T, E> across FFI when niche optimization can be used (v2)) - rust-lang#124765 ([rustdoc] Fix bad color for setting cog in ayu theme) - rust-lang#124768 ([resubmission] Meta: Enable the brand new triagebot transfer command) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 9c9b568 + 31e2302 commit be0e608

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1102
-140
lines changed
 

‎compiler/rustc_feature/src/unstable.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ declare_features! (
579579
(incomplete, repr128, "1.16.0", Some(56071)),
580580
/// Allows `repr(simd)` and importing the various simd intrinsics.
581581
(unstable, repr_simd, "1.4.0", Some(27731)),
582+
/// Allows enums like Result<T, E> to be used across FFI, if T's niche value can
583+
/// be used to describe E or vise-versa.
584+
(unstable, result_ffi_guarantees, "CURRENT_RUSTC_VERSION", Some(110503)),
582585
/// Allows bounding the return type of AFIT/RPITIT.
583586
(incomplete, return_type_notation, "1.70.0", Some(109417)),
584587
/// Allows `extern "rust-cold"`.

‎compiler/rustc_lint/src/types.rs

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,32 @@ fn get_nullable_type<'tcx>(
11011101
})
11021102
}
11031103

1104+
/// A type is niche-optimization candidate iff:
1105+
/// - Is a zero-sized type with alignment 1 (a “1-ZST”).
1106+
/// - Has no fields.
1107+
/// - Does not have the `#[non_exhaustive]` attribute.
1108+
fn is_niche_optimization_candidate<'tcx>(
1109+
tcx: TyCtxt<'tcx>,
1110+
param_env: ty::ParamEnv<'tcx>,
1111+
ty: Ty<'tcx>,
1112+
) -> bool {
1113+
if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) {
1114+
return false;
1115+
}
1116+
1117+
match ty.kind() {
1118+
ty::Adt(ty_def, _) => {
1119+
let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
1120+
let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
1121+
|| (ty_def.is_enum() && ty_def.variants().is_empty());
1122+
1123+
!non_exhaustive && empty
1124+
}
1125+
ty::Tuple(tys) => tys.is_empty(),
1126+
_ => false,
1127+
}
1128+
}
1129+
11041130
/// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
11051131
/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
11061132
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
@@ -1117,6 +1143,22 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
11171143
let field_ty = match &ty_def.variants().raw[..] {
11181144
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
11191145
([], [field]) | ([field], []) => field.ty(tcx, args),
1146+
([field1], [field2]) => {
1147+
if !tcx.features().result_ffi_guarantees {
1148+
return None;
1149+
}
1150+
1151+
let ty1 = field1.ty(tcx, args);
1152+
let ty2 = field2.ty(tcx, args);
1153+
1154+
if is_niche_optimization_candidate(tcx, param_env, ty1) {
1155+
ty2
1156+
} else if is_niche_optimization_candidate(tcx, param_env, ty2) {
1157+
ty1
1158+
} else {
1159+
return None;
1160+
}
1161+
}
11201162
_ => return None,
11211163
},
11221164
_ => return None,
@@ -1202,7 +1244,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12021244
args: GenericArgsRef<'tcx>,
12031245
) -> FfiResult<'tcx> {
12041246
use FfiResult::*;
1205-
12061247
let transparent_with_all_zst_fields = if def.repr().transparent() {
12071248
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
12081249
// Transparent newtypes have at most one non-ZST field which needs to be checked..
@@ -1329,27 +1370,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13291370
return FfiSafe;
13301371
}
13311372

1373+
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
1374+
return FfiUnsafe {
1375+
ty,
1376+
reason: fluent::lint_improper_ctypes_non_exhaustive,
1377+
help: None,
1378+
};
1379+
}
1380+
13321381
// Check for a repr() attribute to specify the size of the
13331382
// discriminant.
13341383
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
13351384
{
1336-
// Special-case types like `Option<extern fn()>`.
1337-
if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
1338-
.is_none()
1385+
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
1386+
if let Some(ty) =
1387+
repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
13391388
{
1340-
return FfiUnsafe {
1341-
ty,
1342-
reason: fluent::lint_improper_ctypes_enum_repr_reason,
1343-
help: Some(fluent::lint_improper_ctypes_enum_repr_help),
1344-
};
1389+
return self.check_type_for_ffi(cache, ty);
13451390
}
1346-
}
13471391

1348-
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
13491392
return FfiUnsafe {
13501393
ty,
1351-
reason: fluent::lint_improper_ctypes_non_exhaustive,
1352-
help: None,
1394+
reason: fluent::lint_improper_ctypes_enum_repr_reason,
1395+
help: Some(fluent::lint_improper_ctypes_enum_repr_help),
13531396
};
13541397
}
13551398

0 commit comments

Comments
 (0)