Add ExternType derive for opaque Rust types
diff --git a/syntax/check.rs b/syntax/check.rs
index 725105d..a60332d 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -232,6 +232,13 @@
         }
     }
 
+    for derive in &strct.derives {
+        if derive.what == Trait::ExternType {
+            let msg = format!("derive({}) on shared struct is not supported", derive);
+            cx.error(derive, msg);
+        }
+    }
+
     for field in &strct.fields {
         if let Type::Fn(_) = field.ty {
             cx.error(
@@ -258,11 +265,9 @@
     }
 
     for derive in &enm.derives {
-        if derive.what == Trait::Default {
-            cx.error(
-                derive,
-                "derive(Default) on shared enums is not supported yet",
-            );
+        if derive.what == Trait::Default || derive.what == Trait::ExternType {
+            let msg = format!("derive({}) on shared enum is not supported", derive);
+            cx.error(derive, msg);
         }
     }
 }
@@ -270,6 +275,21 @@
 fn check_api_type(cx: &mut Check, ety: &ExternType) {
     check_reserved_name(cx, &ety.name.rust);
 
+    for derive in &ety.derives {
+        if derive.what == Trait::ExternType && ety.lang == Lang::Rust {
+            continue;
+        }
+        let lang = match ety.lang {
+            Lang::Rust => "Rust",
+            Lang::Cxx => "C++",
+        };
+        let msg = format!(
+            "derive({}) on opaque {} type is not supported yet",
+            derive, lang,
+        );
+        cx.error(derive, msg);
+    }
+
     if let Some(reason) = cx.types.required_trivial.get(&ety.name.rust) {
         let what = match reason {
             TrivialReason::StructField(strct) => format!("a field of `{}`", strct.name.rust),
diff --git a/syntax/derive.rs b/syntax/derive.rs
index 1121211..96b3eea 100644
--- a/syntax/derive.rs
+++ b/syntax/derive.rs
@@ -1,4 +1,5 @@
 use proc_macro2::{Ident, Span};
+use std::fmt::{self, Display};
 
 #[derive(Copy, Clone)]
 pub struct Derive {
@@ -13,6 +14,7 @@
     Debug,
     Default,
     Eq,
+    ExternType,
     Hash,
     Ord,
     PartialEq,
@@ -27,6 +29,7 @@
             "Debug" => Trait::Debug,
             "Default" => Trait::Default,
             "Eq" => Trait::Eq,
+            "ExternType" => Trait::ExternType,
             "Hash" => Trait::Hash,
             "Ord" => Trait::Ord,
             "PartialEq" => Trait::PartialEq,
@@ -52,6 +55,7 @@
             Trait::Debug => "Debug",
             Trait::Default => "Default",
             Trait::Eq => "Eq",
+            Trait::ExternType => "ExternType",
             Trait::Hash => "Hash",
             Trait::Ord => "Ord",
             Trait::PartialEq => "PartialEq",
@@ -60,6 +64,12 @@
     }
 }
 
+impl Display for Derive {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        formatter.write_str(self.what.as_ref())
+    }
+}
+
 pub fn contains(derives: &[Derive], query: Trait) -> bool {
     derives.iter().any(|derive| derive.what == query)
 }
diff --git a/syntax/mod.rs b/syntax/mod.rs
index bd7efc0..e8288a9 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -67,7 +67,9 @@
 }
 
 pub struct ExternType {
+    pub lang: Lang,
     pub doc: Doc,
+    pub derives: Vec<Derive>,
     pub type_token: Token![type],
     pub name: Pair,
     pub semi_token: Token![;],
diff --git a/syntax/parse.rs b/syntax/parse.rs
index a009e19..e46cdb4 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -327,12 +327,14 @@
     namespace: &Namespace,
 ) -> Api {
     let mut doc = Doc::new();
+    let mut derives = Vec::new();
     let mut namespace = namespace.clone();
     attrs::parse(
         cx,
         &foreign_type.attrs,
         attrs::Parser {
             doc: Some(&mut doc),
+            derives: Some(&mut derives),
             namespace: Some(&mut namespace),
             ..Default::default()
         },
@@ -345,7 +347,9 @@
         Lang::Rust => Api::RustType,
     };
     api_type(ExternType {
+        lang,
         doc,
+        derives,
         type_token,
         name: Pair::new(namespace, ident),
         semi_token,