From fb72abf3f822dbf3cddcb9b2e006cf4cb7b61fcb Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Thu, 11 Jan 2024 19:46:19 -0600 Subject: [PATCH] Fixes #2715. --- .../tests/expectations/tests/noreturn.rs | 8 +++ bindgen-tests/tests/headers/noreturn.hpp | 2 + bindgen/ir/function.rs | 64 ++++++++++++------- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/noreturn.rs b/bindgen-tests/tests/expectations/tests/noreturn.rs index 2b9b316b5d..2081d3d44b 100644 --- a/bindgen-tests/tests/expectations/tests/noreturn.rs +++ b/bindgen-tests/tests/expectations/tests/noreturn.rs @@ -11,3 +11,11 @@ extern "C" { #[link_name = "\u{1}_Z1hv"] pub fn h() -> !; } +extern "C" { + #[link_name = "\u{1}_Z1iPFvvE"] + pub fn i(arg: ::std::option::Option !>); +} +extern "C" { + #[link_name = "\u{1}_Z1jPFvvE"] + pub fn j(arg: ::std::option::Option !>) -> !; +} diff --git a/bindgen-tests/tests/headers/noreturn.hpp b/bindgen-tests/tests/headers/noreturn.hpp index 4ce1e11e3f..bf9d58c7fa 100644 --- a/bindgen-tests/tests/headers/noreturn.hpp +++ b/bindgen-tests/tests/headers/noreturn.hpp @@ -2,3 +2,5 @@ _Noreturn void f(void); __attribute__((noreturn)) void g(void); [[noreturn]] void h(void); +void i(__attribute__((noreturn)) void (*arg)(void)); +__attribute__((noreturn)) void j(__attribute__((noreturn)) void (*arg)(void)); diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 6679a3d509..6c78aa34bf 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -435,8 +435,8 @@ impl FunctionSig { // Don't parse operatorxx functions in C++ let is_operator = |spelling: &str| { - spelling.starts_with("operator") && - !clang::is_valid_identifier(spelling) + spelling.starts_with("operator") + && !clang::is_valid_identifier(spelling) }; if is_operator(&spelling) { return Err(ParseError::Continue); @@ -445,8 +445,8 @@ impl FunctionSig { // Constructors of non-type template parameter classes for some reason // include the template parameter in their name. Just skip them, since // we don't handle well non-type template parameters anyway. - if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) && - spelling.contains('<') + if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) + && spelling.contains('<') { return Err(ParseError::Continue); } @@ -458,11 +458,11 @@ impl FunctionSig { }; let mut args = match kind { - CXCursor_FunctionDecl | - CXCursor_Constructor | - CXCursor_CXXMethod | - CXCursor_ObjCInstanceMethodDecl | - CXCursor_ObjCClassMethodDecl => { + CXCursor_FunctionDecl + | CXCursor_Constructor + | CXCursor_CXXMethod + | CXCursor_ObjCInstanceMethodDecl + | CXCursor_ObjCClassMethodDecl => { args_from_ty_and_cursor(ty, &cursor, ctx) } _ => { @@ -505,16 +505,32 @@ impl FunctionSig { Default::default() }; - // This looks easy to break but the clang parser keeps the type spelling clean even if - // other attributes are added. - is_divergent = - is_divergent || ty.spelling().contains("__attribute__((noreturn))"); + // Check if the type contains __attribute__((noreturn)) outside of parentheses. This is + // somewhat fragile, but it seems to be the only way to get at this information as of + // libclang 9. + let ty_spelling = ty.spelling(); + let has_attribute_noreturn = ty_spelling + .match_indices("__attribute__((noreturn))") + .filter(|&(i, _)| { + let depth = ty_spelling[..i] + .bytes() + .filter_map(|ch| match ch { + b'(' => Some(1), + b')' => Some(-1), + _ => None, + }) + .sum::(); + depth == 0 + }) + .next() + .is_some(); + is_divergent = is_divergent || has_attribute_noreturn; let is_method = kind == CXCursor_CXXMethod; let is_constructor = kind == CXCursor_Constructor; let is_destructor = kind == CXCursor_Destructor; - if (is_constructor || is_destructor || is_method) && - cursor.lexical_parent() != cursor.semantic_parent() + if (is_constructor || is_destructor || is_method) + && cursor.lexical_parent() != cursor.semantic_parent() { // Only parse constructors once. return Err(ParseError::Continue); @@ -555,8 +571,8 @@ impl FunctionSig { } } - let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl || - kind == CXCursor_ObjCClassMethodDecl + let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl + || kind == CXCursor_ObjCClassMethodDecl { ty.ret_type() .or_else(|| cursor.ret_type()) @@ -734,13 +750,13 @@ impl ClangSubItemParser for Function { _ => return Err(ParseError::Continue), }; - if cursor.is_inlined_function() || - cursor + if cursor.is_inlined_function() + || cursor .definition() .map_or(false, |x| x.is_inlined_function()) { - if !context.options().generate_inline_functions && - !context.options().wrap_static_fns + if !context.options().generate_inline_functions + && !context.options().wrap_static_fns { return Err(ParseError::Continue); } @@ -750,9 +766,9 @@ impl ClangSubItemParser for Function { } // We cannot handle `inline` functions that are not `static`. - if context.options().wrap_static_fns && - cursor.is_inlined_function() && - matches!(linkage, Linkage::External) + if context.options().wrap_static_fns + && cursor.is_inlined_function() + && matches!(linkage, Linkage::External) { return Err(ParseError::Continue); }