From fbc2237b7d7b8ab250ec184c709bc5d4129fceab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 30 Nov 2020 19:27:51 +0100 Subject: [PATCH] parser: Fix resolution of #[path] dependencies from certain modules. We need the current mod dir to resolve #[path], not the one we get for rust 2018. Fixes #599 --- src/bindgen/parser.rs | 37 +++++++++++++++-------- tests/expectations/mod_2018.both.c | 6 ++++ tests/expectations/mod_2018.both.compat.c | 6 ++++ tests/expectations/mod_2018.c | 6 ++++ tests/expectations/mod_2018.compat.c | 6 ++++ tests/expectations/mod_2018.cpp | 6 ++++ tests/expectations/mod_2018.pyx | 5 +++ tests/expectations/mod_2018.tag.c | 6 ++++ tests/expectations/mod_2018.tag.compat.c | 6 ++++ tests/expectations/mod_2018.tag.pyx | 5 +++ tests/rust/mod_2018/src/nested.rs | 3 ++ tests/rust/mod_2018/src/other2.rs | 7 +++++ 12 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 tests/rust/mod_2018/src/other2.rs diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index e43645c..b8d84c5 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -205,7 +205,7 @@ impl<'a> Parser<'a> { self.cache_expanded_crate.get(&pkg.name).unwrap().clone() }; - self.process_mod(pkg, None, &mod_items, 0) + self.process_mod(pkg, None, None, &mod_items, 0) } fn parse_mod( @@ -240,30 +240,37 @@ impl<'a> Parser<'a> { }; // Compute module directory according to Rust 2018 rules - let mod_dir_2018; + let submod_dir_2018; - let mod_dir = if depth == 0 || mod_path.ends_with("mod.rs") { - mod_path.parent().unwrap() + let mod_dir = mod_path.parent().unwrap(); + + let submod_dir = if depth == 0 || mod_path.ends_with("mod.rs") { + mod_dir } else { - mod_dir_2018 = mod_path + submod_dir_2018 = mod_path .parent() .unwrap() .join(mod_path.file_stem().unwrap()); - &mod_dir_2018 + &submod_dir_2018 }; - self.process_mod(pkg, Some(&mod_dir), &mod_items, depth) + self.process_mod(pkg, Some(mod_dir), Some(submod_dir), &mod_items, depth) } /// `mod_dir` is the path to the current directory of the module. It may be /// `None` for pre-expanded modules. + /// + /// `submod_dir` is the path to search submodules in by default, which might + /// be different for rust 2018 for example. fn process_mod( &mut self, pkg: &PackageRef, mod_dir: Option<&FilePath>, + submod_dir: Option<&FilePath>, items: &[syn::Item], depth: usize, ) -> Result<(), Error> { + debug_assert_eq!(mod_dir.is_some(), submod_dir.is_some()); // We process the items first then the nested modules. let nested_modules = self.out.load_syn_crate_mod( &self.config, @@ -275,18 +282,24 @@ impl<'a> Parser<'a> { for item in nested_modules { let next_mod_name = item.ident.to_string(); - let cfg = Cfg::load(&item.attrs); if let Some(ref cfg) = cfg { self.cfg_stack.push(cfg.clone()); } if let Some((_, ref inline_items)) = item.content { - let next_mod_dir = mod_dir.map(|dir| dir.join(&next_mod_name)); - self.process_mod(pkg, next_mod_dir.as_deref(), inline_items, depth)?; + let next_submod_dir = submod_dir.map(|dir| dir.join(&next_mod_name)); + self.process_mod( + pkg, + mod_dir, + next_submod_dir.as_deref(), + inline_items, + depth, + )?; } else if let Some(mod_dir) = mod_dir { - let next_mod_path1 = mod_dir.join(next_mod_name.clone() + ".rs"); - let next_mod_path2 = mod_dir.join(next_mod_name.clone()).join("mod.rs"); + let submod_dir = submod_dir.unwrap(); + let next_mod_path1 = submod_dir.join(next_mod_name.clone() + ".rs"); + let next_mod_path2 = submod_dir.join(next_mod_name.clone()).join("mod.rs"); if next_mod_path1.exists() { self.parse_mod(pkg, next_mod_path1.as_path(), depth + 1)?; diff --git a/tests/expectations/mod_2018.both.c b/tests/expectations/mod_2018.both.c index 387edf8..8f0c126 100644 --- a/tests/expectations/mod_2018.both.c +++ b/tests/expectations/mod_2018.both.c @@ -9,4 +9,10 @@ typedef struct ExportMe { uint64_t val; } ExportMe; +typedef struct ExportMe2 { + uint64_t val; +} ExportMe2; + void export_me(struct ExportMe *val); + +void export_me_2(struct ExportMe2*); diff --git a/tests/expectations/mod_2018.both.compat.c b/tests/expectations/mod_2018.both.compat.c index 3d090e5..3a64d75 100644 --- a/tests/expectations/mod_2018.both.compat.c +++ b/tests/expectations/mod_2018.both.compat.c @@ -9,12 +9,18 @@ typedef struct ExportMe { uint64_t val; } ExportMe; +typedef struct ExportMe2 { + uint64_t val; +} ExportMe2; + #ifdef __cplusplus extern "C" { #endif // __cplusplus void export_me(struct ExportMe *val); +void export_me_2(struct ExportMe2*); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2018.c b/tests/expectations/mod_2018.c index 7ffa5ee..c653e5f 100644 --- a/tests/expectations/mod_2018.c +++ b/tests/expectations/mod_2018.c @@ -9,4 +9,10 @@ typedef struct { uint64_t val; } ExportMe; +typedef struct { + uint64_t val; +} ExportMe2; + void export_me(ExportMe *val); + +void export_me_2(ExportMe2*); diff --git a/tests/expectations/mod_2018.compat.c b/tests/expectations/mod_2018.compat.c index 1527af6..64e0e54 100644 --- a/tests/expectations/mod_2018.compat.c +++ b/tests/expectations/mod_2018.compat.c @@ -9,12 +9,18 @@ typedef struct { uint64_t val; } ExportMe; +typedef struct { + uint64_t val; +} ExportMe2; + #ifdef __cplusplus extern "C" { #endif // __cplusplus void export_me(ExportMe *val); +void export_me_2(ExportMe2*); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2018.cpp b/tests/expectations/mod_2018.cpp index 22b3f70..0c2d0b0 100644 --- a/tests/expectations/mod_2018.cpp +++ b/tests/expectations/mod_2018.cpp @@ -10,8 +10,14 @@ struct ExportMe { uint64_t val; }; +struct ExportMe2 { + uint64_t val; +}; + extern "C" { void export_me(ExportMe *val); +void export_me_2(ExportMe2*); + } // extern "C" diff --git a/tests/expectations/mod_2018.pyx b/tests/expectations/mod_2018.pyx index 4398e5d..377db9f 100644 --- a/tests/expectations/mod_2018.pyx +++ b/tests/expectations/mod_2018.pyx @@ -11,4 +11,9 @@ cdef extern from *: ctypedef struct ExportMe: uint64_t val; + ctypedef struct ExportMe2: + uint64_t val; + void export_me(ExportMe *val); + + void export_me_2(ExportMe2*); diff --git a/tests/expectations/mod_2018.tag.c b/tests/expectations/mod_2018.tag.c index 01a8d59..a6df41f 100644 --- a/tests/expectations/mod_2018.tag.c +++ b/tests/expectations/mod_2018.tag.c @@ -9,4 +9,10 @@ struct ExportMe { uint64_t val; }; +struct ExportMe2 { + uint64_t val; +}; + void export_me(struct ExportMe *val); + +void export_me_2(struct ExportMe2*); diff --git a/tests/expectations/mod_2018.tag.compat.c b/tests/expectations/mod_2018.tag.compat.c index 097697e..edbd8a1 100644 --- a/tests/expectations/mod_2018.tag.compat.c +++ b/tests/expectations/mod_2018.tag.compat.c @@ -9,12 +9,18 @@ struct ExportMe { uint64_t val; }; +struct ExportMe2 { + uint64_t val; +}; + #ifdef __cplusplus extern "C" { #endif // __cplusplus void export_me(struct ExportMe *val); +void export_me_2(struct ExportMe2*); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2018.tag.pyx b/tests/expectations/mod_2018.tag.pyx index 4838320..4f0e6c1 100644 --- a/tests/expectations/mod_2018.tag.pyx +++ b/tests/expectations/mod_2018.tag.pyx @@ -11,4 +11,9 @@ cdef extern from *: cdef struct ExportMe: uint64_t val; + cdef struct ExportMe2: + uint64_t val; + void export_me(ExportMe *val); + + void export_me_2(ExportMe2*); diff --git a/tests/rust/mod_2018/src/nested.rs b/tests/rust/mod_2018/src/nested.rs index 5347ee6..e551180 100644 --- a/tests/rust/mod_2018/src/nested.rs +++ b/tests/rust/mod_2018/src/nested.rs @@ -1 +1,4 @@ pub mod other; + +#[path = "other2.rs"] +pub mod other2; diff --git a/tests/rust/mod_2018/src/other2.rs b/tests/rust/mod_2018/src/other2.rs new file mode 100644 index 0000000..31186ae --- /dev/null +++ b/tests/rust/mod_2018/src/other2.rs @@ -0,0 +1,7 @@ +#[repr(C)] +pub struct ExportMe2 { + val: u64 +} + +#[no_mangle] +pub unsafe extern "C" fn export_me_2(_: *mut ExportMe2) { }