Enforce unsafe surrounding block on safe-to-call functions
diff --git a/README.md b/README.md
index a962b52..28f9ef1 100644
--- a/README.md
+++ b/README.md
@@ -90,7 +90,7 @@
fn next_chunk(buf: &mut MultiBuf) -> &[u8];
}
- extern "C++" {
+ unsafe extern "C++" {
// One or more headers with the matching C++ declarations. Our code
// generators don't read it but it gets #include'd and used in static
// assertions to ensure our picture of the FFI boundary is accurate.
diff --git a/demo/src/main.rs b/demo/src/main.rs
index 10f57e5..dca596a 100644
--- a/demo/src/main.rs
+++ b/demo/src/main.rs
@@ -14,7 +14,7 @@
}
// C++ types and signatures exposed to Rust.
- extern "C++" {
+ unsafe extern "C++" {
include!("demo/include/blobstore.h");
type BlobstoreClient;
diff --git a/gen/lib/tests/test.rs b/gen/lib/tests/test.rs
index ebb69a8..d035b52 100644
--- a/gen/lib/tests/test.rs
+++ b/gen/lib/tests/test.rs
@@ -6,7 +6,7 @@
let rs = quote! {
#[cxx::bridge]
mod ffi {
- extern "C++" {
+ unsafe extern "C++" {
fn in_C();
}
extern "Rust" {
diff --git a/src/extern_type.rs b/src/extern_type.rs
index 008fdc1..d7634c4 100644
--- a/src/extern_type.rs
+++ b/src/extern_type.rs
@@ -30,7 +30,7 @@
/// # mod file1 {
/// #[cxx::bridge(namespace = "example")]
/// pub mod ffi {
-/// extern "C++" {
+/// unsafe extern "C++" {
/// type Demo;
///
/// fn create_demo() -> UniquePtr<Demo>;
@@ -41,7 +41,7 @@
/// // file2.rs
/// #[cxx::bridge(namespace = "example")]
/// pub mod ffi {
-/// extern "C++" {
+/// unsafe extern "C++" {
/// type Demo = crate::file1::ffi::Demo;
///
/// fn take_ref_demo(demo: &Demo);
@@ -80,7 +80,7 @@
///
/// #[cxx::bridge(namespace = "folly")]
/// pub mod ffi {
-/// extern "C++" {
+/// unsafe extern "C++" {
/// include!("rust_cxx_bindings.h");
///
/// type StringPiece = crate::folly_sys::StringPiece;
diff --git a/src/lib.rs b/src/lib.rs
index c72e362..091c7cc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -86,7 +86,7 @@
//! fn next_chunk(buf: &mut MultiBuf) -> &[u8];
//! }
//!
-//! extern "C++" {
+//! unsafe extern "C++" {
//! // One or more headers with the matching C++ declarations. Our code
//! // generators don't read it but it gets #include'd and used in static
//! // assertions to ensure our picture of the FFI boundary is accurate.
diff --git a/syntax/parse.rs b/syntax/parse.rs
index b557584..9509bd8 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -204,7 +204,7 @@
Lang::Rust => {
if foreign_mod.unsafety.is_some() {
let unsafety = foreign_mod.unsafety;
- let abi = foreign_mod.abi;
+ let abi = &foreign_mod.abi;
let span = quote!(#unsafety #abi);
cx.error(span, "extern \"Rust\" block does not need to be unsafe");
}
@@ -253,6 +253,18 @@
}
}
+ if !trusted
+ && items.iter().any(|api| match api {
+ Api::CxxFunction(efn) => efn.unsafety.is_none(),
+ _ => false,
+ })
+ {
+ cx.error(
+ foreign_mod.abi,
+ "block must be declared `unsafe extern \"C++\"` if it contains any safe-to-call C++ functions",
+ );
+ }
+
let mut types = items.iter().filter_map(|item| match item {
Api::CxxType(ety) | Api::RustType(ety) => Some(&ety.name),
Api::TypeAlias(alias) => Some(&alias.name),
diff --git a/tests/cxx_gen.rs b/tests/cxx_gen.rs
index 340e2d7..a0c9ff4 100644
--- a/tests/cxx_gen.rs
+++ b/tests/cxx_gen.rs
@@ -6,7 +6,7 @@
const BRIDGE0: &str = r#"
#[cxx::bridge]
mod ffi {
- extern "C++" {
+ unsafe extern "C++" {
pub fn do_cpp_thing(foo: &str);
}
}
diff --git a/tests/ffi/extra.rs b/tests/ffi/extra.rs
index b5ed579..8ca5e57 100644
--- a/tests/ffi/extra.rs
+++ b/tests/ffi/extra.rs
@@ -15,7 +15,7 @@
impl UniquePtr<F> {}
impl UniquePtr<G> {}
- extern "C++" {
+ unsafe extern "C++" {
include!("tests/ffi/tests.h");
type D = crate::other::D;
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index 6ece294..ed6740d 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -116,7 +116,7 @@
i: i32,
}
- extern "C++" {
+ unsafe extern "C++" {
include!("tests/ffi/tests.h");
type C;
diff --git a/tests/ffi/module.rs b/tests/ffi/module.rs
index cf53cde..aff1b1c 100644
--- a/tests/ffi/module.rs
+++ b/tests/ffi/module.rs
@@ -3,7 +3,7 @@
#[rustfmt::skip]
#[cxx::bridge(namespace = "tests")]
pub mod ffi {
- extern "C++" {
+ unsafe extern "C++" {
include!("tests/ffi/tests.h");
type C = crate::ffi::C;
diff --git a/tests/ui/disallow_lifetime.rs b/tests/ui/disallow_lifetime.rs
index b07697a..a4a7b51 100644
--- a/tests/ui/disallow_lifetime.rs
+++ b/tests/ui/disallow_lifetime.rs
@@ -1,6 +1,6 @@
#[cxx::bridge]
mod ffi {
- extern "C++" {
+ unsafe extern "C++" {
type C;
fn f(&'static self);
}
diff --git a/tests/ui/reference_to_reference.rs b/tests/ui/reference_to_reference.rs
index 2318533..91fe160 100644
--- a/tests/ui/reference_to_reference.rs
+++ b/tests/ui/reference_to_reference.rs
@@ -1,6 +1,6 @@
#[cxx::bridge]
mod ffi {
- extern "C++" {
+ unsafe extern "C++" {
type ThingC;
fn repro_c(t: &&ThingC);
}
diff --git a/tests/ui/unnamed_receiver.rs b/tests/ui/unnamed_receiver.rs
index 13c23ae..5f53a0a 100644
--- a/tests/ui/unnamed_receiver.rs
+++ b/tests/ui/unnamed_receiver.rs
@@ -1,6 +1,6 @@
#[cxx::bridge]
mod ffi {
- extern "C++" {
+ unsafe extern "C++" {
type One;
type Two;
fn f(&mut self);
diff --git a/tests/ui/unrecognized_receiver.rs b/tests/ui/unrecognized_receiver.rs
index 5b09c56..eee8259 100644
--- a/tests/ui/unrecognized_receiver.rs
+++ b/tests/ui/unrecognized_receiver.rs
@@ -1,6 +1,6 @@
#[cxx::bridge]
mod ffi {
- extern "C++" {
+ unsafe extern "C++" {
fn f(self: &Unrecognized);
}
}