From 8fffbf85e98e75f38e438002d74988b97afde7ee Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Thu, 11 Jan 2024 20:04:13 -0600 Subject: [PATCH] Fixes #2715. --- .../tests/expectations/tests/noreturn.rs | 8 +++++++ bindgen-tests/tests/headers/noreturn.hpp | 2 ++ bindgen/ir/function.rs | 22 +++++++++++++++---- 3 files changed, 28 insertions(+), 4 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..448bcd22ea 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -505,10 +505,24 @@ 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))") + .any(|(i, _)| { + let depth = ty_spelling[..i] + .bytes() + .filter_map(|ch| match ch { + b'(' => Some(1), + b')' => Some(-1), + _ => None, + }) + .sum::(); + depth == 0 + }); + is_divergent = is_divergent || has_attribute_noreturn; let is_method = kind == CXCursor_CXXMethod; let is_constructor = kind == CXCursor_Constructor;