Repository: dtolnay/cxx (language: rust)

Issue:
Not accepting C++ namespace containing Rust keyword
We need to support C++ namespaces whose name is a reserved keyword in Rust. Currently the macro fails to parse these.

```console
error[cxxbridge]: expected path segment
  ┌─ src/main.rs:1:32
  │
1 │ #[cxx::bridge(namespace = org::trait)]
  │                                ^^^^^ expected path segment
```


Discussion / hints:

Fix patch:
diff --git a/syntax/mod.rs b/syntax/mod.rs
index e2356e1bd..d6db7cb2e 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -13,6 +13,7 @@ mod impls;
 pub mod mangle;
 pub mod namespace;
 mod parse;
+mod qualified;
 pub mod report;
 pub mod set;
 pub mod symbol;
diff --git a/syntax/namespace.rs b/syntax/namespace.rs
index e2dce1831..bdfb84530 100644
--- a/syntax/namespace.rs
+++ b/syntax/namespace.rs
@@ -1,8 +1,9 @@
+use crate::syntax::qualified::QualifiedName;
 use quote::IdentFragment;
 use std::fmt::{self, Display};
 use std::slice::Iter;
 use syn::parse::{Parse, ParseStream, Result};
-use syn::{Ident, Path, Token};
+use syn::{Ident, Token};
 
 mod kw {
     syn::custom_keyword!(namespace);
@@ -31,10 +32,7 @@ impl Parse for Namespace {
         if !input.is_empty() {
             input.parse::<kw::namespace>()?;
             input.parse::<Token![=]>()?;
-            let path = input.call(Path::parse_mod_style)?;
-            for segment in path.segments {
-                segments.push(segment.ident);
-            }
+            segments = input.call(QualifiedName::parse_unquoted)?.segments;
             input.parse::<Option<Token![,]>>()?;
         }
         Ok(Namespace { segments })
diff --git a/syntax/qualified.rs b/syntax/qualified.rs
new file mode 100644
index 000000000..a34009310
--- /dev/null
+++ b/syntax/qualified.rs
@@ -0,0 +1,26 @@
+use syn::ext::IdentExt;
+use syn::parse::{ParseStream, Result};
+use syn::{Ident, Token};
+
+pub struct QualifiedName {
+    pub segments: Vec<Ident>,
+}
+
+impl QualifiedName {
+    pub fn parse_unquoted(input: ParseStream) -> Result<Self> {
+        let mut segments = Vec::new();
+        let mut trailing_punct = true;
+        while trailing_punct && input.peek(Ident::peek_any) {
+            let ident = Ident::parse_any(input)?;
+            segments.push(ident);
+            let colons: Option<Token![::]> = input.parse()?;
+            trailing_punct = colons.is_some();
+        }
+        if segments.is_empty() {
+            return Err(input.error("expected path"));
+        } else if trailing_punct {
+            return Err(input.error("expected path segment"));
+        }
+        Ok(QualifiedName { segments })
+    }
+}


Test patch: