Store independent rust name and c++ name for extern functions
diff --git a/syntax/check.rs b/syntax/check.rs
index ff23ec9..2f3c334 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -214,8 +214,8 @@
     if let Some(reason) = cx.types.required_trivial.get(&ety.ident) {
         let what = match reason {
             TrivialReason::StructField(strct) => format!("a field of `{}`", strct.ident),
-            TrivialReason::FunctionArgument(efn) => format!("an argument of `{}`", efn.ident),
-            TrivialReason::FunctionReturn(efn) => format!("a return value of `{}`", efn.ident),
+            TrivialReason::FunctionArgument(efn) => format!("an argument of `{}`", efn.ident.rust),
+            TrivialReason::FunctionReturn(efn) => format!("a return value of `{}`", efn.ident.rust),
         };
         let msg = format!(
             "needs a cxx::ExternType impl in order to be used as {}",
diff --git a/syntax/ident.rs b/syntax/ident.rs
index 74e7799..66f7365 100644
--- a/syntax/ident.rs
+++ b/syntax/ident.rs
@@ -37,7 +37,7 @@
                 check(cx, &ety.ident);
             }
             Api::CxxFunction(efn) | Api::RustFunction(efn) => {
-                check(cx, &efn.ident);
+                check(cx, &efn.ident.rust);
                 for arg in &efn.args {
                     check(cx, &arg.ident);
                 }
diff --git a/syntax/mangle.rs b/syntax/mangle.rs
index 72233b3..e461887 100644
--- a/syntax/mangle.rs
+++ b/syntax/mangle.rs
@@ -13,8 +13,8 @@
 
 pub fn extern_fn(namespace: &Namespace, efn: &ExternFn) -> Symbol {
     match &efn.receiver {
-        Some(receiver) => join!(namespace, CXXBRIDGE, receiver.ty, efn.ident),
-        None => join!(namespace, CXXBRIDGE, efn.ident),
+        Some(receiver) => join!(namespace, CXXBRIDGE, receiver.ty, efn.ident.rust),
+        None => join!(namespace, CXXBRIDGE, efn.ident.rust),
     }
 }
 
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 934f6c6..c8dea67 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -71,10 +71,15 @@
     pub repr: Atom,
 }
 
+pub struct Pair {
+    pub cxx: Ident,
+    pub rust: Ident,
+}
+
 pub struct ExternFn {
     pub lang: Lang,
     pub doc: Doc,
-    pub ident: Ident,
+    pub ident: Pair,
     pub sig: Signature,
     pub semi_token: Token![;],
 }
diff --git a/syntax/parse.rs b/syntax/parse.rs
index c611c8b..142d063 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -3,7 +3,7 @@
 use crate::syntax::report::Errors;
 use crate::syntax::Atom::*;
 use crate::syntax::{
-    attrs, error, Api, Doc, Enum, ExternFn, ExternType, Impl, Lang, Receiver, Ref, Signature,
+    attrs, error, Api, Doc, Enum, ExternFn, ExternType, Impl, Lang, Pair, Receiver, Ref, Signature,
     Slice, Struct, Ty1, Type, TypeAlias, Var, Variant,
 };
 use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
@@ -370,7 +370,10 @@
     Ok(api_function(ExternFn {
         lang,
         doc,
-        ident,
+        ident: Pair {
+            cxx: ident.clone(),
+            rust: ident,
+        },
         sig: Signature {
             unsafety,
             fn_token,
diff --git a/syntax/types.rs b/syntax/types.rs
index 3f8d10c..5ec7d26 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -51,7 +51,8 @@
         }
 
         let mut type_names = UnorderedSet::new();
-        let mut function_names = UnorderedSet::new();
+        let mut cxx_function_names = UnorderedSet::new();
+        let mut rust_function_names = UnorderedSet::new();
         for api in apis {
             // The same identifier is permitted to be declared as both a shared
             // enum and extern C++ type, or shared struct and extern C++ type.
@@ -116,9 +117,15 @@
                     rust.insert(ident);
                 }
                 Api::CxxFunction(efn) | Api::RustFunction(efn) => {
-                    let ident = &efn.ident;
-                    if !function_names.insert((&efn.receiver, ident)) {
-                        duplicate_name(cx, efn, ident);
+                    let cxx_fn = (&efn.receiver, &efn.ident.cxx);
+                    let rust_fn = (&efn.receiver, &efn.ident.rust);
+                    let cxx_duplicate = !cxx_function_names.insert(cxx_fn);
+                    if !rust_function_names.insert(rust_fn) {
+                        duplicate_name(cx, efn, &efn.ident.rust);
+                    } else if cxx_duplicate {
+                        // Insert into cxx_function_names either way, but hide
+                        // error if we're already erroring on the rust name.
+                        duplicate_name(cx, efn, &efn.ident.cxx);
                     }
                     for arg in &efn.args {
                         visit(&mut all, &arg.ty);