diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 239bc8e7accfc..d805890de5bc4 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -927,7 +927,11 @@ fn create_and_seed_worklist(
                     match tcx.def_kind(id) {
                         DefKind::Impl { .. } => false,
                         DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
-                        DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(),
+                        DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some() || {
+                            let def = tcx.adt_def(id);
+                            // often declared in Rust but constructed by FFI, so ignore
+                            def.repr().c() || def.repr().transparent()
+                        },
                         _ => true
                     })
                 .map(|id| (id, ComesFromAllowExpect::No))
diff --git a/tests/ui/lint/dead-code/not-lint-structs-constructed-externally.rs b/tests/ui/lint/dead-code/not-lint-structs-constructed-externally.rs
new file mode 100644
index 0000000000000..06ff750f2903e
--- /dev/null
+++ b/tests/ui/lint/dead-code/not-lint-structs-constructed-externally.rs
@@ -0,0 +1,39 @@
+//@ check-pass
+#![deny(dead_code)]
+
+#[repr(C)]
+pub struct Foo {
+    pub i: i16,
+    align: i16
+}
+
+mod ffi {
+    use super::*;
+
+    extern "C" {
+        pub fn DomPromise_AddRef(promise: *const Promise);
+        pub fn DomPromise_Release(promise: *const Promise);
+    }
+}
+
+#[repr(C)]
+pub struct Promise {
+    private: [u8; 0],
+    __nosync: ::std::marker::PhantomData<::std::rc::Rc<u8>>,
+}
+
+pub unsafe trait RefCounted {
+    unsafe fn addref(&self);
+    unsafe fn release(&self);
+}
+
+unsafe impl RefCounted for Promise {
+    unsafe fn addref(&self) {
+        ffi::DomPromise_AddRef(self)
+    }
+    unsafe fn release(&self) {
+        ffi::DomPromise_Release(self)
+    }
+}
+
+fn main() {}