Skip to content

Commit fb72abf

Browse files
author
Nathan Ringo
committed
1 parent d0c2b1e commit fb72abf

File tree

3 files changed

+50
-24
lines changed

3 files changed

+50
-24
lines changed

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

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

bindgen-tests/tests/headers/noreturn.hpp

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

bindgen/ir/function.rs

+40-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,32 @@ 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+
.match_indices("__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+
.next()
526+
.is_some();
527+
is_divergent = is_divergent || has_attribute_noreturn;
512528

513529
let is_method = kind == CXCursor_CXXMethod;
514530
let is_constructor = kind == CXCursor_Constructor;
515531
let is_destructor = kind == CXCursor_Destructor;
516-
if (is_constructor || is_destructor || is_method) &&
517-
cursor.lexical_parent() != cursor.semantic_parent()
532+
if (is_constructor || is_destructor || is_method)
533+
&& cursor.lexical_parent() != cursor.semantic_parent()
518534
{
519535
// Only parse constructors once.
520536
return Err(ParseError::Continue);
@@ -555,8 +571,8 @@ impl FunctionSig {
555571
}
556572
}
557573

558-
let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl ||
559-
kind == CXCursor_ObjCClassMethodDecl
574+
let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl
575+
|| kind == CXCursor_ObjCClassMethodDecl
560576
{
561577
ty.ret_type()
562578
.or_else(|| cursor.ret_type())
@@ -734,13 +750,13 @@ impl ClangSubItemParser for Function {
734750
_ => return Err(ParseError::Continue),
735751
};
736752

737-
if cursor.is_inlined_function() ||
738-
cursor
753+
if cursor.is_inlined_function()
754+
|| cursor
739755
.definition()
740756
.map_or(false, |x| x.is_inlined_function())
741757
{
742-
if !context.options().generate_inline_functions &&
743-
!context.options().wrap_static_fns
758+
if !context.options().generate_inline_functions
759+
&& !context.options().wrap_static_fns
744760
{
745761
return Err(ParseError::Continue);
746762
}
@@ -750,9 +766,9 @@ impl ClangSubItemParser for Function {
750766
}
751767

752768
// 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)
769+
if context.options().wrap_static_fns
770+
&& cursor.is_inlined_function()
771+
&& matches!(linkage, Linkage::External)
756772
{
757773
return Err(ParseError::Continue);
758774
}

0 commit comments

Comments
 (0)