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);
     }
 }