about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorJubilee Young <workingjubilee@gmail.com>2023-10-16 23:56:22 -0700
committerJubilee Young <workingjubilee@gmail.com>2024-09-19 12:56:31 -0700
commite9cf280ef2ea4550d2305484873a63dfd133abb7 (patch)
treea12d2691113f70c3fb8542e6abd1519e2296a1db /compiler
parent749f80ab051aa0b3724b464130440b0e70a975ac (diff)
downloadrust-e9cf280ef2ea4550d2305484873a63dfd133abb7.tar.gz
rust-e9cf280ef2ea4550d2305484873a63dfd133abb7.zip
warn less about non-exhaustive in ffi
Bindgen allows generating `#[non_exhaustive] #[repr(u32)]` enums.
This results in nonintuitive nonlocal `improper_ctypes` warnings,
even when the types are otherwise perfectly valid in C.

Adjust for actual tooling expectations by avoiding warning on
simple enums with only unit variants.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_lint/src/types.rs27
1 files changed, 18 insertions, 9 deletions
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 900c496e033..eef1f0d133a 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -3,6 +3,7 @@ use std::ops::ControlFlow;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::DiagMessage;
+use rustc_hir::def::CtorKind;
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
@@ -1386,15 +1387,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             // Empty enums are okay... although sort of useless.
                             return FfiSafe;
                         }
-
-                        if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
-                            return FfiUnsafe {
-                                ty,
-                                reason: fluent::lint_improper_ctypes_non_exhaustive,
-                                help: None,
-                            };
-                        }
-
                         // Check for a repr() attribute to specify the size of the
                         // discriminant.
                         if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
@@ -1413,8 +1405,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             };
                         }
 
+                        // non_exhaustive suggests it is possible that someone might break ABI
+                        // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
+                        // so warn on complex enums being used outside their crate
+                        let nonexhaustive_nonlocal_ffi =
+                            def.is_variant_list_non_exhaustive() && !def.did().is_local();
+
                         // Check the contained variants.
                         for variant in def.variants() {
+                            // but only warn about really_tagged_union reprs,
+                            // exempt enums with unit ctors like C's (like rust-bindgen)
+                            if nonexhaustive_nonlocal_ffi
+                                && !matches!(variant.ctor_kind(), Some(CtorKind::Const))
+                            {
+                                return FfiUnsafe {
+                                    ty,
+                                    reason: fluent::lint_improper_ctypes_non_exhaustive,
+                                    help: None,
+                                };
+                            };
                             let is_non_exhaustive = variant.is_field_list_non_exhaustive();
                             if is_non_exhaustive && !variant.def_id.is_local() {
                                 return FfiUnsafe {