diff --git a/bindgen-tests/tests/expectations/tests/inline_namespace_nested.rs b/bindgen-tests/tests/expectations/tests/inline_namespace_nested.rs new file mode 100644 index 0000000000..29b5b35ffa --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/inline_namespace_nested.rs @@ -0,0 +1,21 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod ranges { + #[allow(unused_imports)] + use self::super::super::root; + pub mod bar { + #[allow(unused_imports)] + use self::super::super::super::root; + pub const bar: ::std::os::raw::c_int = 0; + } + } +} diff --git a/bindgen-tests/tests/expectations/tests/libclang-5/inline_namespace_nested.rs b/bindgen-tests/tests/expectations/tests/libclang-5/inline_namespace_nested.rs new file mode 100644 index 0000000000..996b877e50 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/libclang-5/inline_namespace_nested.rs @@ -0,0 +1 @@ +/* error generating bindings */ diff --git a/bindgen-tests/tests/headers/inline_namespace_nested.hpp b/bindgen-tests/tests/headers/inline_namespace_nested.hpp new file mode 100644 index 0000000000..5c542e195c --- /dev/null +++ b/bindgen-tests/tests/headers/inline_namespace_nested.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: --enable-cxx-namespaces -- -std=c++2a + +namespace ranges::inline foo::bar { + static int bar = 0; +} diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index ca081e2683..25c073cc84 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -252,7 +252,7 @@ fn compare_generated_header( let actual = bindings.to_string(); rustfmt(actual) } - Err(_) => ("".to_string(), "".to_string()), + Err(_) => ("/* error generating bindings */\n".into(), "".to_string()), }; println!("{}", rustfmt_stderr); diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index 12373952ff..e2a13b8d17 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -2107,13 +2107,18 @@ If you encounter an error missing from this list, please file an issue or a PR!" } let mut kind = ModuleKind::Normal; - let mut found_namespace_keyword = false; + let mut looking_for_name = false; for token in cursor.tokens().iter() { match token.spelling() { b"inline" => { - assert!(!found_namespace_keyword); - assert!(kind != ModuleKind::Inline); + debug_assert!( + kind != ModuleKind::Inline, + "Multiple inline keywords?" + ); kind = ModuleKind::Inline; + // When hitting a nested inline namespace we get a spelling + // that looks like ["inline", "foo"]. Deal with it properly. + looking_for_name = true; } // The double colon allows us to handle nested namespaces like // namespace foo::bar { } @@ -2122,45 +2127,39 @@ If you encounter an error missing from this list, please file an issue or a PR!" // but the tokenization of the second begins with the double // colon. That's ok, so we only need to handle the weird // tokenization here. - // - // Fortunately enough, inline nested namespace specifiers aren't - // a thing, and are invalid C++ :) b"namespace" | b"::" => { - found_namespace_keyword = true; + looking_for_name = true; } b"{" => { - assert!(found_namespace_keyword); + // This should be an anonymous namespace. + assert!(looking_for_name); break; } - name if found_namespace_keyword => { - if module_name.is_none() { - module_name = - Some(String::from_utf8_lossy(name).into_owned()); + name => { + if looking_for_name { + if module_name.is_none() { + module_name = Some( + String::from_utf8_lossy(name).into_owned(), + ); + } + break; + } else { + // This is _likely_, but not certainly, a macro that's + // been placed just before the namespace keyword. + // Unfortunately, clang tokens don't let us easily see + // through the ifdef tokens, so we don't know what this + // token should really be. Instead of panicking though, + // we warn the user that we assumed the token was blank, + // and then move on. + // + // See also https://github.com/rust-lang/rust-bindgen/issues/1676. + warn!( + "Ignored unknown namespace prefix '{}' at {:?} in {:?}", + String::from_utf8_lossy(name), + token, + cursor + ); } - break; - } - spelling if !found_namespace_keyword => { - // This is _likely_, but not certainly, a macro that's been placed just before - // the namespace keyword. Unfortunately, clang tokens don't let us easily see - // through the ifdef tokens, so we don't know what this token should really be. - // Instead of panicking though, we warn the user that we assumed the token was - // blank, and then move on. - // - // See also https://github.com/rust-lang/rust-bindgen/issues/1676. - warn!( - "Ignored unknown namespace prefix '{}' at {:?} in {:?}", - String::from_utf8_lossy(spelling), - token, - cursor - ); - } - spelling => { - panic!( - "Unknown token '{}' while processing namespace at {:?} in {:?}", - String::from_utf8_lossy(spelling), - token, - cursor - ); } } }