Skip to content

Commit c58431c

Browse files
author
Nathan Ringo
committed
1 parent d0c2b1e commit c58431c

File tree

3 files changed

+44
-24
lines changed

3 files changed

+44
-24
lines changed

bindgen-tests/tests/expectations/tests/noreturn.rs

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/headers/noreturn.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
_Noreturn void f(void);
33
__attribute__((noreturn)) void g(void);
44
[[noreturn]] void h(void);
5+
void i(__attribute__((noreturn)) void (*arg)(void));

bindgen/ir/function.rs

+39-24
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,8 @@ impl FunctionSig {
435435

436436
// Don't parse operatorxx functions in C++
437437
let is_operator = |spelling: &str| {
438-
spelling.starts_with("operator") &&
439-
!clang::is_valid_identifier(spelling)
438+
spelling.starts_with("operator")
439+
&& !clang::is_valid_identifier(spelling)
440440
};
441441
if is_operator(&spelling) {
442442
return Err(ParseError::Continue);
@@ -445,8 +445,8 @@ impl FunctionSig {
445445
// Constructors of non-type template parameter classes for some reason
446446
// include the template parameter in their name. Just skip them, since
447447
// we don't handle well non-type template parameters anyway.
448-
if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) &&
449-
spelling.contains('<')
448+
if (kind == CXCursor_Constructor || kind == CXCursor_Destructor)
449+
&& spelling.contains('<')
450450
{
451451
return Err(ParseError::Continue);
452452
}
@@ -458,11 +458,11 @@ impl FunctionSig {
458458
};
459459

460460
let mut args = match kind {
461-
CXCursor_FunctionDecl |
462-
CXCursor_Constructor |
463-
CXCursor_CXXMethod |
464-
CXCursor_ObjCInstanceMethodDecl |
465-
CXCursor_ObjCClassMethodDecl => {
461+
CXCursor_FunctionDecl
462+
| CXCursor_Constructor
463+
| CXCursor_CXXMethod
464+
| CXCursor_ObjCInstanceMethodDecl
465+
| CXCursor_ObjCClassMethodDecl => {
466466
args_from_ty_and_cursor(ty, &cursor, ctx)
467467
}
468468
_ => {
@@ -505,16 +505,31 @@ impl FunctionSig {
505505
Default::default()
506506
};
507507

508-
// This looks easy to break but the clang parser keeps the type spelling clean even if
509-
// other attributes are added.
510-
is_divergent =
511-
is_divergent || ty.spelling().contains("__attribute__((noreturn))");
508+
// Check if the type contains __attribute__((noreturn)) outside of parentheses. This is
509+
// somewhat fragile, but it seems to be the only way to get at this information as of
510+
// libclang 9.
511+
let ty_spelling = ty.spelling();
512+
let has_attribute_noreturn = ty_spelling
513+
.find("__attribute__((noreturn))")
514+
.filter(|&i| {
515+
let depth = ty_spelling[..i]
516+
.bytes()
517+
.filter_map(|ch| match ch {
518+
b'(' => Some(1),
519+
b')' => Some(-1),
520+
_ => None,
521+
})
522+
.sum::<isize>();
523+
depth == 0
524+
})
525+
.is_some();
526+
is_divergent = is_divergent || has_attribute_noreturn;
512527

513528
let is_method = kind == CXCursor_CXXMethod;
514529
let is_constructor = kind == CXCursor_Constructor;
515530
let is_destructor = kind == CXCursor_Destructor;
516-
if (is_constructor || is_destructor || is_method) &&
517-
cursor.lexical_parent() != cursor.semantic_parent()
531+
if (is_constructor || is_destructor || is_method)
532+
&& cursor.lexical_parent() != cursor.semantic_parent()
518533
{
519534
// Only parse constructors once.
520535
return Err(ParseError::Continue);
@@ -555,8 +570,8 @@ impl FunctionSig {
555570
}
556571
}
557572

558-
let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl ||
559-
kind == CXCursor_ObjCClassMethodDecl
573+
let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl
574+
|| kind == CXCursor_ObjCClassMethodDecl
560575
{
561576
ty.ret_type()
562577
.or_else(|| cursor.ret_type())
@@ -734,13 +749,13 @@ impl ClangSubItemParser for Function {
734749
_ => return Err(ParseError::Continue),
735750
};
736751

737-
if cursor.is_inlined_function() ||
738-
cursor
752+
if cursor.is_inlined_function()
753+
|| cursor
739754
.definition()
740755
.map_or(false, |x| x.is_inlined_function())
741756
{
742-
if !context.options().generate_inline_functions &&
743-
!context.options().wrap_static_fns
757+
if !context.options().generate_inline_functions
758+
&& !context.options().wrap_static_fns
744759
{
745760
return Err(ParseError::Continue);
746761
}
@@ -750,9 +765,9 @@ impl ClangSubItemParser for Function {
750765
}
751766

752767
// We cannot handle `inline` functions that are not `static`.
753-
if context.options().wrap_static_fns &&
754-
cursor.is_inlined_function() &&
755-
matches!(linkage, Linkage::External)
768+
if context.options().wrap_static_fns
769+
&& cursor.is_inlined_function()
770+
&& matches!(linkage, Linkage::External)
756771
{
757772
return Err(ParseError::Continue);
758773
}

0 commit comments

Comments
 (0)