Skip to content

Commit 52d05ca

Browse files
Allow macro definitions to pick up precise C types
Upon activating the `--macro-const-use-ctypes` flag, `bindgen` should generate bindings with precise type resolution to the exact C types. This flag implies `--clang-macro-fallback` as its pre-requisite. Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
1 parent 74a5f30 commit 52d05ca

File tree

12 files changed

+381
-80
lines changed

12 files changed

+381
-80
lines changed

bindgen-tests/tests/expectations/tests/issue-753.rs

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/expectations/tests/issue-923.rs

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/expectations/tests/libclang-9/issue-923.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/expectations/tests/test_macro_fallback_non_system_dir.rs

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/headers/issue-753.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77

88
#define CONST UINT32_C(5)
99
#define OTHER_CONST UINT32_C(6)
10-
#define LARGE_CONST UINT32_C(6 << 8)
10+
#define LARGE_CONST (UINT32_C(6) << 8)
1111

1212
#endif
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// bindgen-flags: --macro-const-use-ctypes
2+
3+
#ifndef ISSUE_923_H
4+
#define ISSUE_923_H
5+
6+
#define ULONG_ZERO 0UL
7+
#define ULONGLONG_ZERO 0ULL
8+
#define CHAR_ZERO ((char)'\0')
9+
#define FLOAT_LIT 0.f
10+
#define DOUBLE_LIT ((double)0.f)
11+
#define UINT_LIT 0x80000000
12+
13+
#endif

bindgen-tests/tests/tests.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,16 @@ fn create_bindgen_builder(header: &Path) -> Result<BuilderState, Error> {
269269

270270
let source = fs::File::open(header)?;
271271
let reader = BufReader::new(source);
272+
let basename = header.file_name().unwrap();
273+
let per_test_folder = format!(
274+
"./{}",
275+
basename
276+
.to_str()
277+
.unwrap()
278+
.replace('_', "__")
279+
.replace('.', "_")
280+
);
281+
fs::create_dir_all(&per_test_folder)?;
272282

273283
// Scoop up bindgen-flags from test header
274284
let mut flags = Vec::with_capacity(2);
@@ -334,6 +344,8 @@ fn create_bindgen_builder(header: &Path) -> Result<BuilderState, Error> {
334344
"#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
335345
"--raw-line",
336346
"",
347+
"--clang-macro-fallback-build-dir",
348+
&per_test_folder,
337349
];
338350

339351
let args = prepend.iter().map(ToString::to_string).chain(flags);

bindgen/clang.rs

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,10 @@ impl Cursor {
246246
pub(crate) fn is_toplevel(&self) -> bool {
247247
let mut semantic_parent = self.fallible_semantic_parent();
248248

249-
while semantic_parent.is_some() &&
250-
(semantic_parent.unwrap().kind() == CXCursor_Namespace ||
251-
semantic_parent.unwrap().kind() ==
252-
CXCursor_NamespaceAlias ||
253-
semantic_parent.unwrap().kind() == CXCursor_NamespaceRef)
249+
while semantic_parent.is_some()
250+
&& (semantic_parent.unwrap().kind() == CXCursor_Namespace
251+
|| semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias
252+
|| semantic_parent.unwrap().kind() == CXCursor_NamespaceRef)
254253
{
255254
semantic_parent =
256255
semantic_parent.unwrap().fallible_semantic_parent();
@@ -267,9 +266,9 @@ impl Cursor {
267266
pub(crate) fn is_template_like(&self) -> bool {
268267
matches!(
269268
self.kind(),
270-
CXCursor_ClassTemplate |
271-
CXCursor_ClassTemplatePartialSpecialization |
272-
CXCursor_TypeAliasTemplateDecl
269+
CXCursor_ClassTemplate
270+
| CXCursor_ClassTemplatePartialSpecialization
271+
| CXCursor_TypeAliasTemplateDecl
273272
)
274273
}
275274

@@ -296,9 +295,9 @@ impl Cursor {
296295
/// Is the referent a fully specialized template specialization without any
297296
/// remaining free template arguments?
298297
pub(crate) fn is_fully_specialized_template(&self) -> bool {
299-
self.is_template_specialization() &&
300-
self.kind() != CXCursor_ClassTemplatePartialSpecialization &&
301-
self.num_template_args().unwrap_or(0) > 0
298+
self.is_template_specialization()
299+
&& self.kind() != CXCursor_ClassTemplatePartialSpecialization
300+
&& self.num_template_args().unwrap_or(0) > 0
302301
}
303302

304303
/// Is the referent a template specialization that still has remaining free
@@ -324,9 +323,9 @@ impl Cursor {
324323
pub(crate) fn is_template_parameter(&self) -> bool {
325324
matches!(
326325
self.kind(),
327-
CXCursor_TemplateTemplateParameter |
328-
CXCursor_TemplateTypeParameter |
329-
CXCursor_NonTypeTemplateParameter
326+
CXCursor_TemplateTemplateParameter
327+
| CXCursor_TemplateTypeParameter
328+
| CXCursor_NonTypeTemplateParameter
330329
)
331330
}
332331

@@ -664,9 +663,9 @@ impl Cursor {
664663
// inline function without a definition, and it's not a defaulted
665664
// function, we can reasonably safely conclude that it's a deleted
666665
// function.
667-
self.is_inlined_function() &&
668-
self.definition().is_none() &&
669-
!self.is_defaulted_function()
666+
self.is_inlined_function()
667+
&& self.definition().is_none()
668+
&& !self.is_defaulted_function()
670669
}
671670

672671
/// Is the referent a bit field declaration?
@@ -788,11 +787,11 @@ impl Cursor {
788787
let found_attr = &mut found_attrs[idx];
789788
if !*found_attr {
790789
// `attr.name` and` attr.token_kind` are checked against unexposed attributes only.
791-
if attr.kind == Some(kind) ||
792-
(kind == CXCursor_UnexposedAttr &&
793-
cur.tokens().iter().any(|t| {
794-
t.kind == attr.token_kind &&
795-
t.spelling() == attr.name
790+
if attr.kind == Some(kind)
791+
|| (kind == CXCursor_UnexposedAttr
792+
&& cur.tokens().iter().any(|t| {
793+
t.kind == attr.token_kind
794+
&& t.spelling() == attr.name
796795
}))
797796
{
798797
*found_attr = true;
@@ -1408,12 +1407,12 @@ impl Type {
14081407
/// to.
14091408
pub(crate) fn pointee_type(&self) -> Option<Type> {
14101409
match self.kind() {
1411-
CXType_Pointer |
1412-
CXType_RValueReference |
1413-
CXType_LValueReference |
1414-
CXType_MemberPointer |
1415-
CXType_BlockPointer |
1416-
CXType_ObjCObjectPointer => {
1410+
CXType_Pointer
1411+
| CXType_RValueReference
1412+
| CXType_LValueReference
1413+
| CXType_MemberPointer
1414+
| CXType_BlockPointer
1415+
| CXType_ObjCObjectPointer => {
14171416
let ret = Type {
14181417
x: unsafe { clang_getPointeeType(self.x) },
14191418
};
@@ -1516,12 +1515,12 @@ impl Type {
15161515
// Yep, the spelling of this containing type-parameter is extremely
15171516
// nasty... But can happen in <type_traits>. Unfortunately I couldn't
15181517
// reduce it enough :(
1519-
self.template_args().is_some_and(|args| args.len() > 0) &&
1520-
!matches!(
1518+
self.template_args().is_some_and(|args| args.len() > 0)
1519+
&& !matches!(
15211520
self.declaration().kind(),
1522-
CXCursor_ClassTemplatePartialSpecialization |
1523-
CXCursor_TypeAliasTemplateDecl |
1524-
CXCursor_TemplateTemplateParameter
1521+
CXCursor_ClassTemplatePartialSpecialization
1522+
| CXCursor_TypeAliasTemplateDecl
1523+
| CXCursor_TemplateTemplateParameter
15251524
)
15261525
}
15271526

@@ -1546,9 +1545,9 @@ impl Type {
15461545
.is_match(spelling.as_ref())
15471546
}
15481547

1549-
self.kind() == CXType_Unexposed &&
1550-
(hacky_parse_associated_type(self.spelling()) ||
1551-
hacky_parse_associated_type(
1548+
self.kind() == CXType_Unexposed
1549+
&& (hacky_parse_associated_type(self.spelling())
1550+
|| hacky_parse_associated_type(
15521551
self.canonical_type().spelling(),
15531552
))
15541553
}
@@ -2309,8 +2308,8 @@ impl EvalResult {
23092308
{
23102309
let mut found_cant_eval = false;
23112310
cursor.visit(|c| {
2312-
if c.kind() == CXCursor_TypeRef &&
2313-
c.cur_type().canonical_type().kind() == CXType_Unexposed
2311+
if c.kind() == CXCursor_TypeRef
2312+
&& c.cur_type().canonical_type().kind() == CXType_Unexposed
23142313
{
23152314
found_cant_eval = true;
23162315
return CXChildVisit_Break;
@@ -2329,7 +2328,8 @@ impl EvalResult {
23292328
})
23302329
}
23312330

2332-
fn kind(&self) -> CXEvalResultKind {
2331+
/// Return the kind of the evaluation result.
2332+
pub(crate) fn kind(&self) -> CXEvalResultKind {
23332333
unsafe { clang_EvalResult_getKind(self.x) }
23342334
}
23352335

@@ -2370,6 +2370,30 @@ impl EvalResult {
23702370
Some(value as i64)
23712371
}
23722372

2373+
/// Try to resolve the result into a string literal.
2374+
/// This returns `None` if the result is not immediately a string literal.
2375+
pub(crate) fn as_str_literal(&self) -> Option<Vec<u8>> {
2376+
if !matches!(
2377+
self.kind(),
2378+
CXEval_StrLiteral | CXEval_CFStr | CXEval_ObjCStrLiteral,
2379+
) {
2380+
return None;
2381+
}
2382+
// Safety: we are only copying the content, not assuming a borrow.
2383+
// TODO(@dingxiangfei2009): LLVM Libclang does not return the true size
2384+
// of a string literal, which could be truncated due to a null character
2385+
// '\0' in the middle.
2386+
// Tracking issue: https://github.com/llvm/llvm-project/issues/69749
2387+
let value =
2388+
unsafe { CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) };
2389+
Some(value.to_bytes().into())
2390+
}
2391+
2392+
/// Return the type of the value.
2393+
pub(crate) fn value_type(&self) -> Type {
2394+
self.ty
2395+
}
2396+
23732397
/// Evaluates the expression as a literal string, that may or may not be
23742398
/// valid utf-8.
23752399
pub(crate) fn as_literal_string(&self) -> Option<Vec<u8>> {

bindgen/ir/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ pub(crate) struct BindgenContext {
353353
/// hard errors while parsing duplicated macros, as well to allow macro
354354
/// expression parsing.
355355
///
356-
/// This needs to be an `std::HashMap` because the `cexpr` API requires it.
356+
/// This needs to be an `std::HashMap` because the [`cexpr`] API requires it.
357357
parsed_macros: StdHashMap<Vec<u8>, cexpr::expr::EvalResult>,
358358

359359
/// A map with all include locations.
@@ -2131,6 +2131,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
21312131
}
21322132

21332133
/// Get the currently parsed macros.
2134+
/// This map only contains macros accepted by [`cexpr`]
21342135
pub(crate) fn parsed_macros(
21352136
&self,
21362137
) -> &StdHashMap<Vec<u8>, cexpr::expr::EvalResult> {

0 commit comments

Comments
 (0)