11//! Intermediate representation of variables.
22
33use super :: super :: codegen:: MacroTypeVariation ;
4- use super :: context:: { BindgenContext , TypeId } ;
4+ use super :: annotations:: Annotations ;
5+ use super :: context:: { BindgenContext , ItemId , TypeId } ;
56use super :: dot:: DotAttributes ;
67use super :: function:: cursor_mangling;
78use super :: int:: IntKind ;
89use super :: item:: Item ;
10+ use super :: item_kind:: ItemKind as IrItemKind ;
911use super :: ty:: { FloatKind , TypeKind } ;
1012use crate :: callbacks:: { ItemInfo , ItemKind , MacroParsingBehavior } ;
1113use crate :: clang;
@@ -28,6 +30,27 @@ pub(crate) enum VarType {
2830 Char ( u8 ) ,
2931 /// A string, not necessarily well-formed utf-8.
3032 String ( Vec < u8 > ) ,
33+ /// A pointer represented as an integer constant.
34+ Pointer ( u64 ) ,
35+ }
36+
37+ /// The value obtained when parsing a macro.
38+ enum MacroValue {
39+ /// A value parsed using `cexpr` or evaluated by Clang as an integer.
40+ Expr ( cexpr:: expr:: EvalResult ) ,
41+ /// A data pointer value recognized by Clang.
42+ Pointer ,
43+ }
44+
45+ /// A pointer-valued macro waiting to have its type materialized.
46+ #[ derive( Debug ) ]
47+ pub ( crate ) struct PendingPointerMacro {
48+ /// The item ID reserved at the macro's source position.
49+ id : ItemId ,
50+ /// The macro name.
51+ name : String ,
52+ /// The original macro cursor in the primary translation unit.
53+ cursor : clang:: Cursor ,
3154}
3255
3356/// A `Var` is our intermediate representation of a variable.
@@ -207,10 +230,13 @@ impl ClangSubItemParser for Var {
207230
208231 let previously_defined = ctx. parsed_macro ( & id) ;
209232
210- // NB: It's important to "note" the macro even if the result is
211- // not an integer, otherwise we might loose other kind of
212- // derived macros.
213- ctx. note_parsed_macro ( id. clone ( ) , value. clone ( ) ) ;
233+ // Keep pointer macros unknown to `cexpr`: derived expressions
234+ // must still be eligible for Clang fallback evaluation.
235+ let cexpr_value = match & value {
236+ MacroValue :: Expr ( value) => Some ( value. clone ( ) ) ,
237+ MacroValue :: Pointer => None ,
238+ } ;
239+ ctx. note_parsed_macro ( id. clone ( ) , cexpr_value) ;
214240
215241 if previously_defined {
216242 let name = String :: from_utf8 ( id) . unwrap ( ) ;
@@ -223,6 +249,18 @@ impl ClangSubItemParser for Var {
223249 // enforce utf8 there, so we should have already panicked at
224250 // this point.
225251 let name = String :: from_utf8 ( id) . unwrap ( ) ;
252+ let value =
253+ match value {
254+ MacroValue :: Expr ( value) => value,
255+ MacroValue :: Pointer => {
256+ let id = ctx. next_item_id ( ) ;
257+ ctx. note_pending_pointer_macro (
258+ PendingPointerMacro { id, name, cursor } ,
259+ ) ;
260+ return Err ( ParseError :: Continue ) ;
261+ }
262+ } ;
263+
226264 let ( type_kind, val) = match value {
227265 EvalResult :: Invalid => return Err ( ParseError :: Continue ) ,
228266 EvalResult :: Float ( f) => {
@@ -390,13 +428,18 @@ impl ClangSubItemParser for Var {
390428fn parse_macro_clang_fallback (
391429 ctx : & mut BindgenContext ,
392430 cursor : & clang:: Cursor ,
393- ) -> Option < ( Vec < u8 > , cexpr:: expr:: EvalResult ) > {
431+ ) -> Option < ( Vec < u8 > , MacroValue ) > {
432+ use clang_sys:: {
433+ CXType_FunctionNoProto , CXType_FunctionProto , CXType_Pointer ,
434+ } ;
435+
394436 if !ctx. options ( ) . clang_macro_fallback {
395437 return None ;
396438 }
397439
398440 let ftu = ctx. try_ensure_fallback_translation_unit ( ) ?;
399- let contents = format ! ( "int main() {{ {}; }}" , cursor. spelling( ) ) ;
441+ let name = cursor. spelling ( ) ;
442+ let contents = format ! ( "int main() {{ {name}; }}" ) ;
400443 ftu. reparse ( & contents) . ok ( ) ?;
401444 // Children of root node of AST
402445 let root_children = ftu. translation_unit ( ) . cursor ( ) . collect_children ( ) ;
@@ -413,18 +456,33 @@ fn parse_macro_clang_fallback(
413456 // First child in all_exprs is the expression utilizing the given macro to be evaluated
414457 // Should be ParenExpr
415458 let paren = paren_exprs. first ( ) ?;
459+ let canonical_ty = paren. cur_type ( ) . canonical_type ( ) ;
460+
461+ if canonical_ty. kind ( ) != CXType_Pointer {
462+ return Some ( (
463+ name. into_bytes ( ) ,
464+ MacroValue :: Expr ( cexpr:: expr:: EvalResult :: Int ( Wrapping (
465+ paren. evaluate ( ) ?. as_int ( ) ?,
466+ ) ) ) ,
467+ ) ) ;
468+ }
469+
470+ let pointee = canonical_ty. pointee_type ( ) ?;
471+ if matches ! (
472+ pointee. kind( ) ,
473+ CXType_FunctionNoProto | CXType_FunctionProto
474+ ) {
475+ return None ;
476+ }
416477
417- Some ( (
418- cursor. spelling ( ) . into_bytes ( ) ,
419- cexpr:: expr:: EvalResult :: Int ( Wrapping ( paren. evaluate ( ) ?. as_int ( ) ?) ) ,
420- ) )
478+ Some ( ( name. into_bytes ( ) , MacroValue :: Pointer ) )
421479}
422480
423481/// Try and parse a macro using all the macros parsed until now.
424482fn parse_macro (
425483 ctx : & mut BindgenContext ,
426484 cursor : & clang:: Cursor ,
427- ) -> Option < ( Vec < u8 > , cexpr :: expr :: EvalResult ) > {
485+ ) -> Option < ( Vec < u8 > , MacroValue ) > {
428486 use cexpr:: expr;
429487
430488 let mut cexpr_tokens = cursor. cexpr_tokens ( ) ;
@@ -436,8 +494,102 @@ fn parse_macro(
436494 let parser = expr:: IdentifierParser :: new ( ctx. parsed_macros ( ) ) ;
437495
438496 match parser. macro_definition ( & cexpr_tokens) {
439- Ok ( ( _, ( id, val) ) ) => Some ( ( id. into ( ) , val) ) ,
440- _ => parse_macro_clang_fallback ( ctx, cursor) ,
497+ Ok ( ( _, ( id, value) ) ) => Some ( ( id. into ( ) , MacroValue :: Expr ( value) ) ) ,
498+ Err ( _) => parse_macro_clang_fallback ( ctx, cursor) ,
499+ }
500+ }
501+
502+ /// Materialize all pointer macro types from one final fallback translation
503+ /// unit, which remains valid throughout deferred type resolution.
504+ pub ( crate ) fn finish_pending_pointer_macros ( ctx : & mut BindgenContext ) {
505+ use clang_sys:: { CXChildVisit_Break , CXChildVisit_Recurse , CXType_Pointer } ;
506+
507+ let pending = ctx. take_pending_pointer_macros ( ) ;
508+ if pending. is_empty ( ) {
509+ return ;
510+ }
511+
512+ let statements = pending
513+ . iter ( )
514+ . map ( |pointer_macro| {
515+ format ! ( "{{ (unsigned long long)({}); }}" , pointer_macro. name)
516+ } )
517+ . collect :: < Vec < _ > > ( )
518+ . join ( " " ) ;
519+ let contents = format ! ( "int main() {{ {statements} }}" ) ;
520+ let expressions = {
521+ let Some ( ftu) = ctx. try_ensure_fallback_translation_unit ( ) else {
522+ return ;
523+ } ;
524+ if ftu. reparse ( & contents) . is_err ( ) {
525+ return ;
526+ }
527+ let root_children = ftu. translation_unit ( ) . cursor ( ) . collect_children ( ) ;
528+ let Some ( main_func) = root_children. last ( ) else {
529+ return ;
530+ } ;
531+ let all_stmts = main_func. collect_children ( ) ;
532+ let Some ( macro_stmt) = all_stmts. first ( ) else {
533+ return ;
534+ } ;
535+ macro_stmt
536+ . collect_children ( )
537+ . into_iter ( )
538+ . map ( |statement| {
539+ let value_expression = * statement. collect_children ( ) . first ( ) ?;
540+ let value = value_expression. evaluate ( ) ?. as_int ( ) ? as u64 ;
541+ let mut pointer_expression = None ;
542+ value_expression. visit ( |child| {
543+ if child. cur_type ( ) . canonical_type ( ) . kind ( ) ==
544+ CXType_Pointer
545+ {
546+ pointer_expression = Some ( child) ;
547+ CXChildVisit_Break
548+ } else {
549+ CXChildVisit_Recurse
550+ }
551+ } ) ;
552+ Some ( ( pointer_expression?, value) )
553+ } )
554+ . collect :: < Vec < _ > > ( )
555+ } ;
556+ if expressions. len ( ) != pending. len ( ) {
557+ return ;
558+ }
559+
560+ for ( pointer_macro, expression) in pending. into_iter ( ) . zip ( expressions) {
561+ let Some ( ( expression, value) ) = expression else {
562+ continue ;
563+ } ;
564+ let Ok ( ty) = Item :: from_ty (
565+ & expression. cur_type ( ) . canonical_type ( ) ,
566+ expression,
567+ None ,
568+ ctx,
569+ ) else {
570+ continue ;
571+ } ;
572+ let cursor = pointer_macro. cursor ;
573+ let var = Var :: new (
574+ pointer_macro. name ,
575+ None ,
576+ None ,
577+ ty,
578+ Some ( VarType :: Pointer ( value) ) ,
579+ true ,
580+ ) ;
581+ ctx. add_item (
582+ Item :: new (
583+ pointer_macro. id ,
584+ cursor. raw_comment ( ) ,
585+ Annotations :: new ( & cursor) ,
586+ ctx. root_module ( ) . into ( ) ,
587+ IrItemKind :: Var ( var) ,
588+ Some ( cursor. location ( ) ) ,
589+ ) ,
590+ Some ( cursor) ,
591+ Some ( cursor) ,
592+ ) ;
441593 }
442594}
443595
0 commit comments