From 79fa1fc6c5acfdda2a44ea11fe68d9adfb895e1e Mon Sep 17 00:00:00 2001 From: Rua Date: Mon, 11 May 2026 19:31:35 +0200 Subject: [PATCH 01/10] ast-exporter: Cleanup `VisitExpr`, remove old Clang support --- c2rust-ast-exporter/src/AstExporter.cpp | 34 ++++++++----------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index 3d48d24574..7f9dcc67ba 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -1431,49 +1431,37 @@ class TranslateASTVisitor final // Check that we are only expanding a single macro call. if (!Begin.isMacroID() || !End.isMacroID() || - Mgr.getImmediateMacroCallerLoc(Begin) != Mgr.getImmediateMacroCallerLoc(End)) + Mgr.getImmediateMacroCallerLoc(Begin) != Mgr.getImmediateMacroCallerLoc(End)) { return true; - - if (Begin.isMacroID()) { -#if CLANG_VERSION_MAJOR < 7 - // getImmediateExpansionRange in LLVM<7 returns a - // std::pair, which we need to - // translate to a CharSourceRange for Lexer::getSourceText - auto LocPair = Mgr.getImmediateExpansionRange(Begin); - auto ExpansionRange = CharSourceRange::getCharRange(LocPair.first, LocPair.second); -#else // CLANG_VERSION_MAJOR >= 7 - auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin); -#endif - curMacroExpansionSource = - Lexer::getSourceText(ExpansionRange, Mgr, Context->getLangOpts()); } + auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin); + curMacroExpansionSource = + Lexer::getSourceText(ExpansionRange, Mgr, Context->getLangOpts()); + // The macro stack unwound by getImmediateMacroCallerLoc and friends // starts with literal replacement and works it's way to the macro call // that was replaced. while (Begin.isMacroID()) { -#if CLANG_VERSION_MAJOR < 7 - auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin); - auto ExpansionBegin = ExpansionRange.first; - auto ExpansionEnd = ExpansionRange.second; -#else // CLANG_VERSION_MAJOR >= 7 auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin).getAsRange(); auto ExpansionBegin = ExpansionRange.getBegin(); auto ExpansionEnd = ExpansionRange.getEnd(); -#endif StringRef name; MacroInfo *mac = getMacroInfo(ExpansionBegin, name); - if (!mac || mac->getNumTokens() == 0) + if (!mac || mac->getNumTokens() == 0) { return true; + } + auto ReplacementBegin = mac->getReplacementToken(0).getLocation(); auto ReplacementEnd = mac->getDefinitionEndLoc(); // Verify that this expansion covers the entire macro replacement // definition, i.e. E is not a subexpression of the macro // replacement. if (Mgr.getSpellingLoc(Begin) != ReplacementBegin || - Mgr.getSpellingLoc(End) != ReplacementEnd) + Mgr.getSpellingLoc(End) != ReplacementEnd) { return true; + } Begin = ExpansionBegin; End = ExpansionEnd; @@ -1482,10 +1470,10 @@ class TranslateASTVisitor final curMacroExpansionStack.push_back(mac); } } + return true; } - bool VisitVAArgExpr(VAArgExpr *E) { std::vector childIds{E->getSubExpr()}; encode_entry(E, TagVAArgExpr, childIds); From 74ab1d8eb266317e12d2ad1225576a9a9e2d6ca2 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 12 May 2026 18:12:39 +0200 Subject: [PATCH 02/10] ast-exporter: In `VisitExpr`, pre-compute the macro expansion stack --- c2rust-ast-exporter/src/AstExporter.cpp | 58 +++++++++++++++---------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index 7f9dcc67ba..ad21fa3e8a 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -1426,28 +1426,27 @@ class TranslateASTVisitor final LLVM_DEBUG(Range.getBegin().dump(Mgr)); LLVM_DEBUG(Range.getEnd().dump(Mgr)); - auto Begin = Range.getBegin(); - auto End = Range.getEnd(); - // Check that we are only expanding a single macro call. - if (!Begin.isMacroID() || !End.isMacroID() || - Mgr.getImmediateMacroCallerLoc(Begin) != Mgr.getImmediateMacroCallerLoc(End)) { + if (!Range.getBegin().isMacroID() || !Range.getEnd().isMacroID() + || Mgr.getImmediateMacroCallerLoc(Range.getBegin()) + != Mgr.getImmediateMacroCallerLoc(Range.getEnd())) { + return true; + } + + // Holds the stack of ranges of macro expansions that expand to this expression. + // The last element is the top-level macro call. + auto ExpansionStack = getMacroExpansionStack(Range); + + if (ExpansionStack.empty()) { return true; } - auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin); curMacroExpansionSource = - Lexer::getSourceText(ExpansionRange, Mgr, Context->getLangOpts()); - - // The macro stack unwound by getImmediateMacroCallerLoc and friends - // starts with literal replacement and works it's way to the macro call - // that was replaced. - while (Begin.isMacroID()) { - auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin).getAsRange(); - auto ExpansionBegin = ExpansionRange.getBegin(); - auto ExpansionEnd = ExpansionRange.getEnd(); + Lexer::getSourceText(ExpansionStack[0], Mgr, Context->getLangOpts()); + + for (auto &ExpansionRange : ExpansionStack) { StringRef name; - MacroInfo *mac = getMacroInfo(ExpansionBegin, name); + MacroInfo *mac = getMacroInfo(ExpansionRange.getBegin(), name); if (!mac || mac->getNumTokens() == 0) { return true; @@ -1458,22 +1457,37 @@ class TranslateASTVisitor final // Verify that this expansion covers the entire macro replacement // definition, i.e. E is not a subexpression of the macro // replacement. - if (Mgr.getSpellingLoc(Begin) != ReplacementBegin || - Mgr.getSpellingLoc(End) != ReplacementEnd) { + if (Mgr.getSpellingLoc(Range.getBegin()) != ReplacementBegin || + Mgr.getSpellingLoc(Range.getEnd()) != ReplacementEnd) { return true; } - Begin = ExpansionBegin; - End = ExpansionEnd; - - if (VisitMacro(name, Begin, mac, E)) { + if (VisitMacro(name, ExpansionRange.getBegin(), mac, E)) { curMacroExpansionStack.push_back(mac); } + + Range = ExpansionRange.getAsRange(); } return true; } + std::vector getMacroExpansionStack(SourceRange Range) const { + auto &Mgr = Context->getSourceManager(); + auto Begin = Range.getBegin(); + auto End = Range.getEnd(); + + std::vector ExpansionStack; + + do { + auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin); + ExpansionStack.push_back(ExpansionRange); + Begin = ExpansionRange.getBegin(); + } while (Begin.isMacroID()); + + return ExpansionStack; + } + bool VisitVAArgExpr(VAArgExpr *E) { std::vector childIds{E->getSubExpr()}; encode_entry(E, TagVAArgExpr, childIds); From ec5d465aa09b110a112674b7b2230d646d8c0af9 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 12 May 2026 20:14:59 +0200 Subject: [PATCH 03/10] ast-exporter: In `VisitExpr`, handle when Begin and End start off in different macros --- c2rust-ast-exporter/src/AstExporter.cpp | 73 ++++++-- ...hots__transpile@macros.c.2021.clang15.snap | 175 +++++++----------- ...hots__transpile@macros.c.2024.clang15.snap | 175 +++++++----------- 3 files changed, 196 insertions(+), 227 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index ad21fa3e8a..a4a1d7ba5f 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -1426,10 +1426,7 @@ class TranslateASTVisitor final LLVM_DEBUG(Range.getBegin().dump(Mgr)); LLVM_DEBUG(Range.getEnd().dump(Mgr)); - // Check that we are only expanding a single macro call. - if (!Range.getBegin().isMacroID() || !Range.getEnd().isMacroID() - || Mgr.getImmediateMacroCallerLoc(Range.getBegin()) - != Mgr.getImmediateMacroCallerLoc(Range.getEnd())) { + if (!Range.getBegin().isMacroID() || !Range.getEnd().isMacroID()) { return true; } @@ -1452,21 +1449,9 @@ class TranslateASTVisitor final return true; } - auto ReplacementBegin = mac->getReplacementToken(0).getLocation(); - auto ReplacementEnd = mac->getDefinitionEndLoc(); - // Verify that this expansion covers the entire macro replacement - // definition, i.e. E is not a subexpression of the macro - // replacement. - if (Mgr.getSpellingLoc(Range.getBegin()) != ReplacementBegin || - Mgr.getSpellingLoc(Range.getEnd()) != ReplacementEnd) { - return true; - } - if (VisitMacro(name, ExpansionRange.getBegin(), mac, E)) { curMacroExpansionStack.push_back(mac); } - - Range = ExpansionRange.getAsRange(); } return true; @@ -1476,18 +1461,72 @@ class TranslateASTVisitor final auto &Mgr = Context->getSourceManager(); auto Begin = Range.getBegin(); auto End = Range.getEnd(); - std::vector ExpansionStack; do { + if (!isAtStartOfImmediateMacroExpansion(Begin)) { + break; + } + auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin); ExpansionStack.push_back(ExpansionRange); Begin = ExpansionRange.getBegin(); } while (Begin.isMacroID()); + // Find the point at which `Begin` and `End` converge on the same expansion range. + // This is where the expression in `Range` first corresponds to a single macro call. + auto ConvergencePoint = ExpansionStack.end(); + + do { + if (!isAtEndOfImmediateMacroExpansion(End)) { + break; + } + + auto ExpansionRange = Mgr.getImmediateExpansionRange(End); + ConvergencePoint = std::find_if( + ExpansionStack.begin(), + ExpansionStack.end(), + [ExpansionRange](auto &R) { + return R.getAsRange() == ExpansionRange.getAsRange() && + R.isTokenRange() == ExpansionRange.isTokenRange(); + } + ); + End = ExpansionRange.getEnd(); + } while (End.isMacroID() && ConvergencePoint == ExpansionStack.end()); + + // Remove all elements before the convergence point. + ExpansionStack.erase(ExpansionStack.begin(), ConvergencePoint); + + // Ensure the remaining ranges still correspond to the input `Range`. + auto EraseAfter = std::find_if( + ExpansionStack.begin(), + ExpansionStack.end(), + [this](auto &R) { + auto End = R.getEnd(); + return End.isMacroID() && !isAtEndOfImmediateMacroExpansion(End); + } + ); + auto EraseFrom = EraseAfter + 1; + + if (EraseFrom < ExpansionStack.end()) { + ExpansionStack.erase(EraseFrom, ExpansionStack.end()); + } + return ExpansionStack; } + bool isAtStartOfImmediateMacroExpansion(SourceLocation loc) const { + auto &Mgr = Context->getSourceManager(); + return Mgr.isAtStartOfImmediateMacroExpansion(loc); + } + + bool isAtEndOfImmediateMacroExpansion(SourceLocation loc) const { + auto &Mgr = Context->getSourceManager(); + auto spellingLoc = Mgr.getSpellingLoc(loc); + auto len = Lexer::MeasureTokenLength(spellingLoc, Mgr, Context->getLangOpts()); + return Mgr.isAtEndOfImmediateMacroExpansion(loc.getLocWithOffset(len)); + } + bool VisitVAArgExpr(VAArgExpr *E) { std::vector childIds{E->getSubExpr()}; encode_entry(E, TagVAArgExpr, childIds); diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.clang15.snap index b059b1a47f..3f8ff8ab44 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.clang15.snap @@ -58,6 +58,11 @@ pub const NESTED_CHAR: ::core::ffi::c_int = LITERAL_CHAR; pub const NESTED_STR: [::core::ffi::c_char; 6] = LITERAL_STR; pub const NESTED_ARRAY: [::core::ffi::c_int; 3] = LITERAL_ARRAY; pub const NESTED_STRUCT: S = LITERAL_STRUCT; +pub const NEGATIVE_INT: ::core::ffi::c_int = -LITERAL_INT; +pub const INT_ARITHMETIC: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; +pub const MIXED_ARITHMETIC: ::core::ffi::c_double = LITERAL_INT as ::core::ffi::c_double + + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + - true_0 as ::core::ffi::c_double; pub const PARENS: ::core::ffi::c_int = NESTED_INT * (LITERAL_CHAR + true_0); pub const PTR_ARITHMETIC: *const ::core::ffi::c_char = unsafe { LITERAL_STR @@ -66,7 +71,24 @@ pub const PTR_ARITHMETIC: *const ::core::ffi::c_char = unsafe { .offset(-(3 as ::core::ffi::c_int as isize)) }; pub const WIDENING_CAST: ::core::ffi::c_ulonglong = LITERAL_INT as ::core::ffi::c_ulonglong; +pub const NARROWING_CAST: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; pub const CONVERSION_CAST: ::core::ffi::c_double = LITERAL_INT as ::core::ffi::c_double; +pub const INDEXING: ::core::ffi::c_char = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; +pub const STR_CONCATENATION: [::core::ffi::c_char; 18] = unsafe { + ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0") +}; +pub const REF_MACRO: *const ::core::ffi::c_char = unsafe { + NESTED_STR + .as_ptr() + .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char +}; +pub const REF_LITERAL: *mut S = &LITERAL_STRUCT as *const S as *mut S; +pub const TERNARY: ::core::ffi::c_int = if LITERAL_BOOL != 0 { + 1 as ::core::ffi::c_int +} else { + 2 as ::core::ffi::c_int +}; +pub const MEMBER: ::core::ffi::c_int = LITERAL_STRUCT.i; #[no_mangle] pub unsafe extern "C" fn local_muts() { let mut literal_int: ::core::ffi::c_int = LITERAL_INT; @@ -85,45 +107,28 @@ pub unsafe extern "C" fn local_muts() { let mut nested_str: [::core::ffi::c_char; 6] = NESTED_STR; let mut nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY; let mut nested_struct: S = NESTED_STRUCT; - let mut negative_int: ::core::ffi::c_int = -LITERAL_INT; - let mut int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; - let mut mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let mut negative_int: ::core::ffi::c_int = NEGATIVE_INT; + let mut int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; + let mut mixed_arithmetic: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let mut parens: ::core::ffi::c_int = PARENS; let mut ptr_arithmetic: *const ::core::ffi::c_char = PTR_ARITHMETIC; let mut widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; - let mut narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; + let mut narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; let mut conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; - let mut indexing: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let mut str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; - let mut str_concatenation: [::core::ffi::c_char; 18] = - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0"); + let mut indexing: ::core::ffi::c_char = INDEXING; + let mut str_concatenation_ptr: *const ::core::ffi::c_char = STR_CONCATENATION.as_ptr(); + let mut str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; let mut builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let mut ref_indexing: *const ::core::ffi::c_char = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - let mut ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; - let mut ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - let mut member: ::core::ffi::c_int = LITERAL_STRUCT.i; + let mut ref_indexing: *const ::core::ffi::c_char = REF_MACRO; + let mut ref_struct: *const S = REF_LITERAL; + let mut ternary: ::core::ffi::c_int = TERNARY; + let mut member: ::core::ffi::c_int = MEMBER; let mut stmt_expr: ::core::ffi::c_float = ({ let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let mut indexing_0: ::core::ffi::c_char = INDEXING; + let mut mixed: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; while i < builtin_0 { mixed += indexing_0 as ::core::ffi::c_float; @@ -150,43 +155,27 @@ pub unsafe extern "C" fn local_consts() { let nested_str: [::core::ffi::c_char; 6] = NESTED_STR; let nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY; let nested_struct: S = NESTED_STRUCT; - let negative_int: ::core::ffi::c_int = -LITERAL_INT; - let int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; - let mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let negative_int: ::core::ffi::c_int = NEGATIVE_INT; + let int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; + let mixed_arithmetic: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let parens: ::core::ffi::c_int = PARENS; let ptr_arithmetic: *const ::core::ffi::c_char = PTR_ARITHMETIC; let widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; - let narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; + let narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; let conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; - let indexing: ::core::ffi::c_char = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; - let str_concatenation: [::core::ffi::c_char; 18] = - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0"); + let indexing: ::core::ffi::c_char = INDEXING; + let str_concatenation_ptr: *const ::core::ffi::c_char = STR_CONCATENATION.as_ptr(); + let str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; let builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let ref_indexing: *const ::core::ffi::c_char = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - let ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; - let ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - let member: ::core::ffi::c_int = LITERAL_STRUCT.i; + let ref_indexing: *const ::core::ffi::c_char = REF_MACRO; + let ref_struct: *const S = REF_LITERAL; + let ternary: ::core::ffi::c_int = TERNARY; + let member: ::core::ffi::c_int = MEMBER; let stmt_expr: ::core::ffi::c_float = ({ let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let mut indexing_0: ::core::ffi::c_char = INDEXING; + let mut mixed: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; while i < builtin_0 { mixed += indexing_0 as ::core::ffi::c_float; @@ -215,30 +204,25 @@ static mut global_static_const_nested_str_ptr: *const ::core::ffi::c_char = NEST static mut global_static_const_nested_str: [::core::ffi::c_char; 6] = NESTED_STR; static mut global_static_const_nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY; static mut global_static_const_nested_struct: S = NESTED_STRUCT; -static mut global_static_const_negative_int: ::core::ffi::c_int = -LITERAL_INT; -static mut global_static_const_int_arithmetic: ::core::ffi::c_int = - NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; +static mut global_static_const_negative_int: ::core::ffi::c_int = NEGATIVE_INT; +static mut global_static_const_int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; static mut global_static_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; + MIXED_ARITHMETIC as ::core::ffi::c_float; static mut global_static_const_parens: ::core::ffi::c_int = PARENS; static mut global_static_const_ptr_arithmetic: *const ::core::ffi::c_char = ::core::ptr::null::<::core::ffi::c_char>(); static mut global_static_const_widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; -static mut global_static_const_narrowing_cast: ::core::ffi::c_char = - LITERAL_INT as ::core::ffi::c_char; +static mut global_static_const_narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; static mut global_static_const_conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; static mut global_static_const_indexing: ::core::ffi::c_char = 0; static mut global_static_const_str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; -static mut global_static_const_str_concatenation: [::core::ffi::c_char; 18] = unsafe { - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0") -}; + STR_CONCATENATION.as_ptr(); +static mut global_static_const_str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; static mut global_static_const_builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; static mut global_static_const_ref_indexing: *const ::core::ffi::c_char = ::core::ptr::null::<::core::ffi::c_char>(); -static mut global_static_const_ref_struct: *const S = &LITERAL_STRUCT as *const S as *mut S; +static mut global_static_const_ref_struct: *const S = REF_LITERAL; static mut global_static_const_ternary: ::core::ffi::c_int = 0; static mut global_static_const_member: ::core::ffi::c_int = 0; #[no_mangle] @@ -278,14 +262,12 @@ pub static mut global_const_nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY #[no_mangle] pub static mut global_const_nested_struct: S = NESTED_STRUCT; #[no_mangle] -pub static mut global_const_negative_int: ::core::ffi::c_int = -LITERAL_INT; +pub static mut global_const_negative_int: ::core::ffi::c_int = NEGATIVE_INT; #[no_mangle] -pub static mut global_const_int_arithmetic: ::core::ffi::c_int = - NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; +pub static mut global_const_int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; #[no_mangle] pub static mut global_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; + MIXED_ARITHMETIC as ::core::ffi::c_float; #[no_mangle] pub static mut global_const_parens: ::core::ffi::c_int = PARENS; #[no_mangle] @@ -294,19 +276,16 @@ pub static mut global_const_ptr_arithmetic: *const ::core::ffi::c_char = #[no_mangle] pub static mut global_const_widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; #[no_mangle] -pub static mut global_const_narrowing_cast: ::core::ffi::c_char = - LITERAL_INT as ::core::ffi::c_char; +pub static mut global_const_narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; #[no_mangle] pub static mut global_const_conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; #[no_mangle] pub static mut global_const_indexing: ::core::ffi::c_char = 0; #[no_mangle] pub static mut global_const_str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; + STR_CONCATENATION.as_ptr(); #[no_mangle] -pub static mut global_const_str_concatenation: [::core::ffi::c_char; 18] = unsafe { - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0") -}; +pub static mut global_const_str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; #[no_mangle] pub static mut global_const_builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; @@ -314,7 +293,7 @@ pub static mut global_const_builtin: ::core::ffi::c_int = pub static mut global_const_ref_indexing: *const ::core::ffi::c_char = ::core::ptr::null::<::core::ffi::c_char>(); #[no_mangle] -pub static mut global_const_ref_struct: *const S = &LITERAL_STRUCT as *const S as *mut S; +pub static mut global_const_ref_struct: *const S = REF_LITERAL; #[no_mangle] pub static mut global_const_ternary: ::core::ffi::c_int = 0; #[no_mangle] @@ -420,29 +399,15 @@ pub unsafe extern "C" fn late_init_var() -> ::core::ffi::c_int { } unsafe extern "C" fn c2rust_run_static_initializers() { global_static_const_ptr_arithmetic = PTR_ARITHMETIC; - global_static_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - global_static_const_ref_indexing = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - global_static_const_ternary = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - global_static_const_member = LITERAL_STRUCT.i; + global_static_const_indexing = INDEXING; + global_static_const_ref_indexing = REF_MACRO; + global_static_const_ternary = TERNARY; + global_static_const_member = MEMBER; global_const_ptr_arithmetic = PTR_ARITHMETIC; - global_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - global_const_ref_indexing = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - global_const_ternary = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - global_const_member = LITERAL_STRUCT.i; + global_const_indexing = INDEXING; + global_const_ref_indexing = REF_MACRO; + global_const_ternary = TERNARY; + global_const_member = MEMBER; } #[used] #[cfg_attr(target_os = "linux", link_section = ".init_array")] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.clang15.snap index 1541727a10..2cb96b462c 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.clang15.snap @@ -58,6 +58,11 @@ pub const NESTED_CHAR: ::core::ffi::c_int = LITERAL_CHAR; pub const NESTED_STR: [::core::ffi::c_char; 6] = LITERAL_STR; pub const NESTED_ARRAY: [::core::ffi::c_int; 3] = LITERAL_ARRAY; pub const NESTED_STRUCT: S = LITERAL_STRUCT; +pub const NEGATIVE_INT: ::core::ffi::c_int = -LITERAL_INT; +pub const INT_ARITHMETIC: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; +pub const MIXED_ARITHMETIC: ::core::ffi::c_double = LITERAL_INT as ::core::ffi::c_double + + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + - true_0 as ::core::ffi::c_double; pub const PARENS: ::core::ffi::c_int = NESTED_INT * (LITERAL_CHAR + true_0); pub const PTR_ARITHMETIC: *const ::core::ffi::c_char = unsafe { LITERAL_STR @@ -66,7 +71,24 @@ pub const PTR_ARITHMETIC: *const ::core::ffi::c_char = unsafe { .offset(-(3 as ::core::ffi::c_int as isize)) }; pub const WIDENING_CAST: ::core::ffi::c_ulonglong = LITERAL_INT as ::core::ffi::c_ulonglong; +pub const NARROWING_CAST: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; pub const CONVERSION_CAST: ::core::ffi::c_double = LITERAL_INT as ::core::ffi::c_double; +pub const INDEXING: ::core::ffi::c_char = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; +pub const STR_CONCATENATION: [::core::ffi::c_char; 18] = unsafe { + ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0") +}; +pub const REF_MACRO: *const ::core::ffi::c_char = unsafe { + NESTED_STR + .as_ptr() + .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char +}; +pub const REF_LITERAL: *mut S = &LITERAL_STRUCT as *const S as *mut S; +pub const TERNARY: ::core::ffi::c_int = if LITERAL_BOOL != 0 { + 1 as ::core::ffi::c_int +} else { + 2 as ::core::ffi::c_int +}; +pub const MEMBER: ::core::ffi::c_int = LITERAL_STRUCT.i; #[unsafe(no_mangle)] pub unsafe extern "C" fn local_muts() { let mut literal_int: ::core::ffi::c_int = LITERAL_INT; @@ -85,45 +107,28 @@ pub unsafe extern "C" fn local_muts() { let mut nested_str: [::core::ffi::c_char; 6] = NESTED_STR; let mut nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY; let mut nested_struct: S = NESTED_STRUCT; - let mut negative_int: ::core::ffi::c_int = -LITERAL_INT; - let mut int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; - let mut mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let mut negative_int: ::core::ffi::c_int = NEGATIVE_INT; + let mut int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; + let mut mixed_arithmetic: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let mut parens: ::core::ffi::c_int = PARENS; let mut ptr_arithmetic: *const ::core::ffi::c_char = PTR_ARITHMETIC; let mut widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; - let mut narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; + let mut narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; let mut conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; - let mut indexing: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let mut str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; - let mut str_concatenation: [::core::ffi::c_char; 18] = - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0"); + let mut indexing: ::core::ffi::c_char = INDEXING; + let mut str_concatenation_ptr: *const ::core::ffi::c_char = STR_CONCATENATION.as_ptr(); + let mut str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; let mut builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let mut ref_indexing: *const ::core::ffi::c_char = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - let mut ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; - let mut ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - let mut member: ::core::ffi::c_int = LITERAL_STRUCT.i; + let mut ref_indexing: *const ::core::ffi::c_char = REF_MACRO; + let mut ref_struct: *const S = REF_LITERAL; + let mut ternary: ::core::ffi::c_int = TERNARY; + let mut member: ::core::ffi::c_int = MEMBER; let mut stmt_expr: ::core::ffi::c_float = ({ let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let mut indexing_0: ::core::ffi::c_char = INDEXING; + let mut mixed: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; while i < builtin_0 { mixed += indexing_0 as ::core::ffi::c_float; @@ -150,43 +155,27 @@ pub unsafe extern "C" fn local_consts() { let nested_str: [::core::ffi::c_char; 6] = NESTED_STR; let nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY; let nested_struct: S = NESTED_STRUCT; - let negative_int: ::core::ffi::c_int = -LITERAL_INT; - let int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; - let mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let negative_int: ::core::ffi::c_int = NEGATIVE_INT; + let int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; + let mixed_arithmetic: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let parens: ::core::ffi::c_int = PARENS; let ptr_arithmetic: *const ::core::ffi::c_char = PTR_ARITHMETIC; let widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; - let narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; + let narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; let conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; - let indexing: ::core::ffi::c_char = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; - let str_concatenation: [::core::ffi::c_char; 18] = - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0"); + let indexing: ::core::ffi::c_char = INDEXING; + let str_concatenation_ptr: *const ::core::ffi::c_char = STR_CONCATENATION.as_ptr(); + let str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; let builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let ref_indexing: *const ::core::ffi::c_char = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - let ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; - let ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - let member: ::core::ffi::c_int = LITERAL_STRUCT.i; + let ref_indexing: *const ::core::ffi::c_char = REF_MACRO; + let ref_struct: *const S = REF_LITERAL; + let ternary: ::core::ffi::c_int = TERNARY; + let member: ::core::ffi::c_int = MEMBER; let stmt_expr: ::core::ffi::c_float = ({ let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; - let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) - as ::core::ffi::c_float; + let mut indexing_0: ::core::ffi::c_char = INDEXING; + let mut mixed: ::core::ffi::c_float = MIXED_ARITHMETIC as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; while i < builtin_0 { mixed += indexing_0 as ::core::ffi::c_float; @@ -215,30 +204,25 @@ static mut global_static_const_nested_str_ptr: *const ::core::ffi::c_char = NEST static mut global_static_const_nested_str: [::core::ffi::c_char; 6] = NESTED_STR; static mut global_static_const_nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY; static mut global_static_const_nested_struct: S = NESTED_STRUCT; -static mut global_static_const_negative_int: ::core::ffi::c_int = -LITERAL_INT; -static mut global_static_const_int_arithmetic: ::core::ffi::c_int = - NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; +static mut global_static_const_negative_int: ::core::ffi::c_int = NEGATIVE_INT; +static mut global_static_const_int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; static mut global_static_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; + MIXED_ARITHMETIC as ::core::ffi::c_float; static mut global_static_const_parens: ::core::ffi::c_int = PARENS; static mut global_static_const_ptr_arithmetic: *const ::core::ffi::c_char = ::core::ptr::null::<::core::ffi::c_char>(); static mut global_static_const_widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; -static mut global_static_const_narrowing_cast: ::core::ffi::c_char = - LITERAL_INT as ::core::ffi::c_char; +static mut global_static_const_narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; static mut global_static_const_conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; static mut global_static_const_indexing: ::core::ffi::c_char = 0; static mut global_static_const_str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; -static mut global_static_const_str_concatenation: [::core::ffi::c_char; 18] = unsafe { - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0") -}; + STR_CONCATENATION.as_ptr(); +static mut global_static_const_str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; static mut global_static_const_builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; static mut global_static_const_ref_indexing: *const ::core::ffi::c_char = ::core::ptr::null::<::core::ffi::c_char>(); -static mut global_static_const_ref_struct: *const S = &LITERAL_STRUCT as *const S as *mut S; +static mut global_static_const_ref_struct: *const S = REF_LITERAL; static mut global_static_const_ternary: ::core::ffi::c_int = 0; static mut global_static_const_member: ::core::ffi::c_int = 0; #[unsafe(no_mangle)] @@ -278,14 +262,12 @@ pub static mut global_const_nested_array: [::core::ffi::c_int; 3] = NESTED_ARRAY #[unsafe(no_mangle)] pub static mut global_const_nested_struct: S = NESTED_STRUCT; #[unsafe(no_mangle)] -pub static mut global_const_negative_int: ::core::ffi::c_int = -LITERAL_INT; +pub static mut global_const_negative_int: ::core::ffi::c_int = NEGATIVE_INT; #[unsafe(no_mangle)] -pub static mut global_const_int_arithmetic: ::core::ffi::c_int = - NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; +pub static mut global_const_int_arithmetic: ::core::ffi::c_int = INT_ARITHMETIC; #[unsafe(no_mangle)] pub static mut global_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double - - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; + MIXED_ARITHMETIC as ::core::ffi::c_float; #[unsafe(no_mangle)] pub static mut global_const_parens: ::core::ffi::c_int = PARENS; #[unsafe(no_mangle)] @@ -294,19 +276,16 @@ pub static mut global_const_ptr_arithmetic: *const ::core::ffi::c_char = #[unsafe(no_mangle)] pub static mut global_const_widening_cast: ::core::ffi::c_ulonglong = WIDENING_CAST; #[unsafe(no_mangle)] -pub static mut global_const_narrowing_cast: ::core::ffi::c_char = - LITERAL_INT as ::core::ffi::c_char; +pub static mut global_const_narrowing_cast: ::core::ffi::c_char = NARROWING_CAST; #[unsafe(no_mangle)] pub static mut global_const_conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; #[unsafe(no_mangle)] pub static mut global_const_indexing: ::core::ffi::c_char = 0; #[unsafe(no_mangle)] pub static mut global_const_str_concatenation_ptr: *const ::core::ffi::c_char = - b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; + STR_CONCATENATION.as_ptr(); #[unsafe(no_mangle)] -pub static mut global_const_str_concatenation: [::core::ffi::c_char; 18] = unsafe { - ::core::mem::transmute::<[u8; 18], [::core::ffi::c_char; 18]>(*b"hello hello world\0") -}; +pub static mut global_const_str_concatenation: [::core::ffi::c_char; 18] = STR_CONCATENATION; #[unsafe(no_mangle)] pub static mut global_const_builtin: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; @@ -314,7 +293,7 @@ pub static mut global_const_builtin: ::core::ffi::c_int = pub static mut global_const_ref_indexing: *const ::core::ffi::c_char = ::core::ptr::null::<::core::ffi::c_char>(); #[unsafe(no_mangle)] -pub static mut global_const_ref_struct: *const S = &LITERAL_STRUCT as *const S as *mut S; +pub static mut global_const_ref_struct: *const S = REF_LITERAL; #[unsafe(no_mangle)] pub static mut global_const_ternary: ::core::ffi::c_int = 0; #[unsafe(no_mangle)] @@ -420,29 +399,15 @@ pub unsafe extern "C" fn late_init_var() -> ::core::ffi::c_int { } unsafe extern "C" fn c2rust_run_static_initializers() { global_static_const_ptr_arithmetic = PTR_ARITHMETIC; - global_static_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - global_static_const_ref_indexing = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - global_static_const_ternary = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - global_static_const_member = LITERAL_STRUCT.i; + global_static_const_indexing = INDEXING; + global_static_const_ref_indexing = REF_MACRO; + global_static_const_ternary = TERNARY; + global_static_const_member = MEMBER; global_const_ptr_arithmetic = PTR_ARITHMETIC; - global_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; - global_const_ref_indexing = NESTED_STR - .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) - as *const ::core::ffi::c_char; - global_const_ternary = if LITERAL_BOOL != 0 { - 1 as ::core::ffi::c_int - } else { - 2 as ::core::ffi::c_int - }; - global_const_member = LITERAL_STRUCT.i; + global_const_indexing = INDEXING; + global_const_ref_indexing = REF_MACRO; + global_const_ternary = TERNARY; + global_const_member = MEMBER; } #[used] #[cfg_attr(target_os = "linux", unsafe(link_section = ".init_array"))] From 72c96f61ce0532fbc73732c2b7792d2e6e9258fb Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 11:45:37 +0200 Subject: [PATCH 04/10] ast-exporter: Add `macro_fns.c` snapshot test --- c2rust-transpile/tests/snapshots.rs | 5 +++ c2rust-transpile/tests/snapshots/macro_fns.c | 27 ++++++++++++++++ ...s__transpile@macro_fns.c.2021.clang15.snap | 30 ++++++++++++++++++ ...s__transpile@macro_fns.c.2024.clang15.snap | 31 +++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 c2rust-transpile/tests/snapshots/macro_fns.c create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap diff --git a/c2rust-transpile/tests/snapshots.rs b/c2rust-transpile/tests/snapshots.rs index 4f10e330ea..a2185a094c 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -405,6 +405,11 @@ fn test_lift_const() { transpile("lift_const.c").run(); } +#[test] +fn test_macro_fns() { + transpile("macro_fns.c").run(); +} + #[test] fn test_macrocase() { transpile("macrocase.c").run(); diff --git a/c2rust-transpile/tests/snapshots/macro_fns.c b/c2rust-transpile/tests/snapshots/macro_fns.c new file mode 100644 index 0000000000..e6a2a55284 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/macro_fns.c @@ -0,0 +1,27 @@ +#define CONST 42 + +#define ID(x) x +#define PAREN(x) (x) +#define LIT_ID ID(42) +#define LIT_PAREN PAREN(42) +#define CONST_ID ID(CONST) +#define CONST_PAREN PAREN(CONST) +#define NESTED_ID(x) ID(x) +#define NESTED_PAREN(x) PAREN(x) + +void basic(void) { + int lit_id = LIT_ID; + int lit_paren = LIT_PAREN; + int const_id = CONST_ID; + int const_paren = CONST_PAREN; + + int id_with_lit = ID(42); + int paren_with_lit = PAREN(42); + int id_with_const = ID(CONST); + int paren_with_const = PAREN(CONST); + + int nested_id_with_lit = NESTED_ID(42); + int nested_paren_with_lit = NESTED_PAREN(42); + int nested_id_with_const = NESTED_ID(CONST); + int nested_paren_with_const = NESTED_PAREN(CONST); +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap new file mode 100644 index 0000000000..98e356dd6b --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap @@ -0,0 +1,30 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/macro_fns.2021.clang15.rs +--- +#![allow( + clippy::missing_safety_doc, + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] +pub const LIT_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +pub const CONST_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +#[no_mangle] +pub unsafe extern "C" fn basic() { + let mut lit_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut lit_paren: ::core::ffi::c_int = LIT_PAREN; + let mut const_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut const_paren: ::core::ffi::c_int = CONST_PAREN; + let mut id_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut paren_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut id_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut paren_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_id_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_paren_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_id_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_paren_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap new file mode 100644 index 0000000000..49b6ec07b2 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap @@ -0,0 +1,31 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/macro_fns.2024.clang15.rs +--- +#![allow( + clippy::missing_safety_doc, + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unsafe_op_in_unsafe_fn, + unused_assignments, + unused_mut +)] +pub const LIT_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +pub const CONST_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +#[unsafe(no_mangle)] +pub unsafe extern "C" fn basic() { + let mut lit_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut lit_paren: ::core::ffi::c_int = LIT_PAREN; + let mut const_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut const_paren: ::core::ffi::c_int = CONST_PAREN; + let mut id_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut paren_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut id_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut paren_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_id_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_paren_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_id_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut nested_paren_with_const: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +} From 1df9391e9318b40c0dfb1e916c3df83c7a5fa46c Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 13 May 2026 20:33:08 +0200 Subject: [PATCH 05/10] ast-exporter: Skip over parameter expansions in `VisitExpr` --- c2rust-ast-exporter/src/AstExporter.cpp | 56 ++++++++++++------- ...s__transpile@macro_fns.c.2021.clang15.snap | 6 +- ...s__transpile@macro_fns.c.2024.clang15.snap | 6 +- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index a4a1d7ba5f..0aa54ba63c 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -1439,17 +1439,21 @@ class TranslateASTVisitor final } curMacroExpansionSource = - Lexer::getSourceText(ExpansionStack[0], Mgr, Context->getLangOpts()); + Lexer::getSourceText(ExpansionStack[0].range, Mgr, Context->getLangOpts()); + + for (auto &elem : ExpansionStack) { + if (elem.isParameter) { + continue; + } - for (auto &ExpansionRange : ExpansionStack) { StringRef name; - MacroInfo *mac = getMacroInfo(ExpansionRange.getBegin(), name); + MacroInfo *mac = getMacroInfo(elem.range.getBegin(), name); if (!mac || mac->getNumTokens() == 0) { return true; } - if (VisitMacro(name, ExpansionRange.getBegin(), mac, E)) { + if (VisitMacro(name, elem.range.getBegin(), mac, E)) { curMacroExpansionStack.push_back(mac); } } @@ -1457,20 +1461,34 @@ class TranslateASTVisitor final return true; } - std::vector getMacroExpansionStack(SourceRange Range) const { + struct ExpansionRange { + CharSourceRange range; + bool isParameter; + + bool operator== (const ExpansionRange &rhs) const { + return this->range.getAsRange() == rhs.range.getAsRange() + && this->range.isTokenRange() == rhs.range.isTokenRange() + && this->isParameter == rhs.isParameter; + } + }; + + std::vector getMacroExpansionStack(SourceRange Range) const { auto &Mgr = Context->getSourceManager(); auto Begin = Range.getBegin(); auto End = Range.getEnd(); - std::vector ExpansionStack; + std::vector ExpansionStack; do { if (!isAtStartOfImmediateMacroExpansion(Begin)) { break; } - auto ExpansionRange = Mgr.getImmediateExpansionRange(Begin); - ExpansionStack.push_back(ExpansionRange); - Begin = ExpansionRange.getBegin(); + ExpansionRange elem = { + Mgr.getImmediateExpansionRange(Begin), + Mgr.isMacroArgExpansion(Begin) + }; + Begin = elem.range.getBegin(); + ExpansionStack.push_back(elem); } while (Begin.isMacroID()); // Find the point at which `Begin` and `End` converge on the same expansion range. @@ -1482,16 +1500,12 @@ class TranslateASTVisitor final break; } - auto ExpansionRange = Mgr.getImmediateExpansionRange(End); - ConvergencePoint = std::find_if( - ExpansionStack.begin(), - ExpansionStack.end(), - [ExpansionRange](auto &R) { - return R.getAsRange() == ExpansionRange.getAsRange() && - R.isTokenRange() == ExpansionRange.isTokenRange(); - } - ); - End = ExpansionRange.getEnd(); + ExpansionRange elem = { + Mgr.getImmediateExpansionRange(End), + Mgr.isMacroArgExpansion(End) + }; + End = elem.range.getEnd(); + ConvergencePoint = std::find(ExpansionStack.begin(), ExpansionStack.end(), elem); } while (End.isMacroID() && ConvergencePoint == ExpansionStack.end()); // Remove all elements before the convergence point. @@ -1501,8 +1515,8 @@ class TranslateASTVisitor final auto EraseAfter = std::find_if( ExpansionStack.begin(), ExpansionStack.end(), - [this](auto &R) { - auto End = R.getEnd(); + [this](auto &elem) { + auto End = elem.range.getEnd(); return End.isMacroID() && !isAtEndOfImmediateMacroExpansion(End); } ); diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap index 98e356dd6b..b4120ee024 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2021.clang15.snap @@ -11,13 +11,15 @@ expression: cat tests/snapshots/macro_fns.2021.clang15.rs unused_assignments, unused_mut )] +pub const LIT_ID: ::core::ffi::c_int = 42 as ::core::ffi::c_int; pub const LIT_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +pub const CONST_ID: ::core::ffi::c_int = 42 as ::core::ffi::c_int; pub const CONST_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; #[no_mangle] pub unsafe extern "C" fn basic() { - let mut lit_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut lit_id: ::core::ffi::c_int = LIT_ID; let mut lit_paren: ::core::ffi::c_int = LIT_PAREN; - let mut const_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut const_id: ::core::ffi::c_int = CONST_ID; let mut const_paren: ::core::ffi::c_int = CONST_PAREN; let mut id_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; let mut paren_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap index 49b6ec07b2..e1ed38afc8 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macro_fns.c.2024.clang15.snap @@ -12,13 +12,15 @@ expression: cat tests/snapshots/macro_fns.2024.clang15.rs unused_assignments, unused_mut )] +pub const LIT_ID: ::core::ffi::c_int = 42 as ::core::ffi::c_int; pub const LIT_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; +pub const CONST_ID: ::core::ffi::c_int = 42 as ::core::ffi::c_int; pub const CONST_PAREN: ::core::ffi::c_int = 42 as ::core::ffi::c_int; #[unsafe(no_mangle)] pub unsafe extern "C" fn basic() { - let mut lit_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut lit_id: ::core::ffi::c_int = LIT_ID; let mut lit_paren: ::core::ffi::c_int = LIT_PAREN; - let mut const_id: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + let mut const_id: ::core::ffi::c_int = CONST_ID; let mut const_paren: ::core::ffi::c_int = CONST_PAREN; let mut id_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; let mut paren_with_lit: ::core::ffi::c_int = 42 as ::core::ffi::c_int; From 0f10dc58b13fda86a9caee2ab32627af51b81168 Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 11:20:06 +0200 Subject: [PATCH 06/10] ast-exporter: Move `getMacroInfo` closer to the code that calls it --- c2rust-ast-exporter/src/AstExporter.cpp | 68 ++++++++++++------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index 0aa54ba63c..49f402f9a3 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -903,40 +903,6 @@ class TranslateASTVisitor final isVaList(ast, T), encodeMacroExpansions, childIds, extra); } - MacroInfo* getMacroInfo(SourceLocation loc, StringRef &name) const { - auto &Mgr = Context->getSourceManager(); - Token Result; - if (!Lexer::getRawToken(Mgr.getSpellingLoc(loc), Result, - Mgr, Context->getLangOpts(), false)) { - if (Result.is(tok::raw_identifier)) { - PP.LookUpIdentifierInfo(Result); - } - IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo(); - if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) { - std::pair DecLoc = - Mgr.getDecomposedExpansionLoc(loc); - // Get the definition just before the searched location - // so that a macro referenced in a '#undef MACRO' can - // still be found. - SourceLocation BeforeSearchedLocation = - Mgr.getMacroArgExpandedLocation( - Mgr.getLocForStartOfFile(DecLoc.first) - .getLocWithOffset(DecLoc.second - 1)); - MacroDefinition MacroDef = PP.getMacroDefinitionAtLoc( - IdentifierInfo, BeforeSearchedLocation); - MacroInfo *MacroInf = MacroDef.getMacroInfo(); - if (MacroInf) { - LLVM_DEBUG(dbgs() << IdentifierInfo->getName() << "\n"); - LLVM_DEBUG(MacroInf->dump()); - LLVM_DEBUG(dbgs() << "\n"); - name = IdentifierInfo->getName(); - return MacroInf; - } - } - } - return nullptr; - } - bool VisitMacro(StringRef name, SourceLocation loc, MacroInfo *mac, Expr *E) { // TODO: handle builtin macros if (mac->isBuiltinMacro()) @@ -1541,6 +1507,40 @@ class TranslateASTVisitor final return Mgr.isAtEndOfImmediateMacroExpansion(loc.getLocWithOffset(len)); } + MacroInfo* getMacroInfo(SourceLocation loc, StringRef &name) const { + auto &Mgr = Context->getSourceManager(); + Token Result; + if (!Lexer::getRawToken(Mgr.getSpellingLoc(loc), Result, + Mgr, Context->getLangOpts(), false)) { + if (Result.is(tok::raw_identifier)) { + PP.LookUpIdentifierInfo(Result); + } + IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo(); + if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) { + std::pair DecLoc = + Mgr.getDecomposedExpansionLoc(loc); + // Get the definition just before the searched location + // so that a macro referenced in a '#undef MACRO' can + // still be found. + SourceLocation BeforeSearchedLocation = + Mgr.getMacroArgExpandedLocation( + Mgr.getLocForStartOfFile(DecLoc.first) + .getLocWithOffset(DecLoc.second - 1)); + MacroDefinition MacroDef = PP.getMacroDefinitionAtLoc( + IdentifierInfo, BeforeSearchedLocation); + MacroInfo *MacroInf = MacroDef.getMacroInfo(); + if (MacroInf) { + LLVM_DEBUG(dbgs() << IdentifierInfo->getName() << "\n"); + LLVM_DEBUG(MacroInf->dump()); + LLVM_DEBUG(dbgs() << "\n"); + name = IdentifierInfo->getName(); + return MacroInf; + } + } + } + return nullptr; + } + bool VisitVAArgExpr(VAArgExpr *E) { std::vector childIds{E->getSubExpr()}; encode_entry(E, TagVAArgExpr, childIds); From 5a1cd2c296c40b591dffc40f8877c935ed422e46 Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 11:20:20 +0200 Subject: [PATCH 07/10] ast-exporter: Split off `getIdentifierInfo` --- c2rust-ast-exporter/src/AstExporter.cpp | 80 +++++++++++++++---------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index 49f402f9a3..bd73085493 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -1412,15 +1412,21 @@ class TranslateASTVisitor final continue; } - StringRef name; - MacroInfo *mac = getMacroInfo(elem.range.getBegin(), name); + auto loc = elem.range.getBegin(); + auto IdentifierInfo = getIdentifierInfo(loc); - if (!mac || mac->getNumTokens() == 0) { + if (!IdentifierInfo) { return true; } - if (VisitMacro(name, elem.range.getBegin(), mac, E)) { - curMacroExpansionStack.push_back(mac); + auto MacroInfo = getMacroInfo(loc, IdentifierInfo); + + if (!MacroInfo || MacroInfo->getNumTokens() == 0) { + return true; + } + + if (VisitMacro(IdentifierInfo->getName(), loc, MacroInfo, E)) { + curMacroExpansionStack.push_back(MacroInfo); } } @@ -1507,40 +1513,54 @@ class TranslateASTVisitor final return Mgr.isAtEndOfImmediateMacroExpansion(loc.getLocWithOffset(len)); } - MacroInfo* getMacroInfo(SourceLocation loc, StringRef &name) const { + IdentifierInfo *getIdentifierInfo(SourceLocation loc) const { auto &Mgr = Context->getSourceManager(); Token Result; - if (!Lexer::getRawToken(Mgr.getSpellingLoc(loc), Result, - Mgr, Context->getLangOpts(), false)) { + + if (!Lexer::getRawToken( + Mgr.getSpellingLoc(loc), + Result, + Mgr, + Context->getLangOpts(), + false + )) { if (Result.is(tok::raw_identifier)) { PP.LookUpIdentifierInfo(Result); } - IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo(); - if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) { - std::pair DecLoc = - Mgr.getDecomposedExpansionLoc(loc); - // Get the definition just before the searched location - // so that a macro referenced in a '#undef MACRO' can - // still be found. - SourceLocation BeforeSearchedLocation = - Mgr.getMacroArgExpandedLocation( - Mgr.getLocForStartOfFile(DecLoc.first) - .getLocWithOffset(DecLoc.second - 1)); - MacroDefinition MacroDef = PP.getMacroDefinitionAtLoc( - IdentifierInfo, BeforeSearchedLocation); - MacroInfo *MacroInf = MacroDef.getMacroInfo(); - if (MacroInf) { - LLVM_DEBUG(dbgs() << IdentifierInfo->getName() << "\n"); - LLVM_DEBUG(MacroInf->dump()); - LLVM_DEBUG(dbgs() << "\n"); - name = IdentifierInfo->getName(); - return MacroInf; - } - } + + return Result.getIdentifierInfo(); } + return nullptr; } + MacroInfo* getMacroInfo(SourceLocation loc, IdentifierInfo *IdentifierInfo) const { + if (!IdentifierInfo->hadMacroDefinition()) { + return nullptr; + } + + auto &Mgr = Context->getSourceManager(); + std::pair DecLoc = Mgr.getDecomposedExpansionLoc(loc); + // Get the definition just before the searched location + // so that a macro referenced in a '#undef MACRO' can + // still be found. + SourceLocation BeforeSearchedLocation = Mgr.getMacroArgExpandedLocation( + Mgr.getLocForStartOfFile(DecLoc.first).getLocWithOffset(DecLoc.second - 1)); + MacroDefinition MacroDef = PP.getMacroDefinitionAtLoc( + IdentifierInfo, BeforeSearchedLocation); + MacroInfo *MacroInf = MacroDef.getMacroInfo(); + + if (!MacroInf) { + return nullptr; + } + + LLVM_DEBUG(dbgs() << IdentifierInfo->getName() << "\n"); + LLVM_DEBUG(MacroInf->dump()); + LLVM_DEBUG(dbgs() << "\n"); + + return MacroInf; + } + bool VisitVAArgExpr(VAArgExpr *E) { std::vector childIds{E->getSubExpr()}; encode_entry(E, TagVAArgExpr, childIds); From 78afd7f14471e6ab669214f35bd6fdb5b695d31f Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 11:21:35 +0200 Subject: [PATCH 08/10] ast-exporter: Rename "expansion" to "invocation" --- c2rust-ast-exporter/src/AstExporter.cpp | 54 ++++++++++++------------ c2rust-ast-exporter/src/clang_ast.rs | 12 +++--- c2rust-transpile/src/c_ast/conversion.rs | 4 +- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index bd73085493..1d3f1b4508 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -711,7 +711,7 @@ class TypeEncoder final : public TypeVisitor { class TranslateASTVisitor final : public RecursiveASTVisitor { - struct MacroExpansionInfo { + struct MacroDeclInfo { StringRef Name; }; @@ -723,13 +723,13 @@ class TranslateASTVisitor final // Mapping from SourceManager FileID to index in files DenseMap file_id_mapping; std::set> exportedTags; - std::unordered_map macros; + std::unordered_map macros; // This stores a raw encoding of the macro call site SourceLocation, since // SourceLocation isn't hashable. std::unordered_set macroCallSites; - SmallVector curMacroExpansionStack; - StringRef curMacroExpansionSource; + SmallVector curMacroInvocationStack; + StringRef curMacroInvocationSource; // Returns true when a new entry is added to exportedTags bool markForExport(void *ptr, ASTEntryTag tag) { @@ -769,7 +769,7 @@ class TranslateASTVisitor final // Template required because Decl and Stmt don't share a common base class void encode_entry_raw(void *ast, ASTEntryTag tag, SourceRange loc, const QualType ty, bool rvalue, - bool isVaList, bool encodeMacroExpansions, + bool isVaList, bool encodeMacroInvocations, const std::vector &childIds, std::function extra) { if (!markForExport(ast, tag)) @@ -808,21 +808,21 @@ class TranslateASTVisitor final // 9 - Is Rvalue (only for expressions) cbor_encode_boolean(&local, rvalue); - // 10 - Macro expansion stack, starting with initial macro call and ending + // 10 - Macro invocation stack, starting with initial macro call and ending // with the innermost replacement. cbor_encoder_create_array(&local, &childEnc, - encodeMacroExpansions ? curMacroExpansionStack.size() : 0); - if (encodeMacroExpansions) { - for (auto I = curMacroExpansionStack.rbegin(), E = curMacroExpansionStack.rend(); + encodeMacroInvocations ? curMacroInvocationStack.size() : 0); + if (encodeMacroInvocations) { + for (auto I = curMacroInvocationStack.rbegin(), E = curMacroInvocationStack.rend(); I != E; ++I) { cbor_encode_uint(&childEnc, uintptr_t(*I)); } } cbor_encoder_close_container(&local, &childEnc); - // 11 - Macro expansion source string, if applicable. - if (!curMacroExpansionSource.empty()) { - cbor_encode_string(&local, curMacroExpansionSource.str()); + // 11 - Macro invocation source string, if applicable. + if (!curMacroInvocationSource.empty()) { + cbor_encode_string(&local, curMacroInvocationSource.str()); } else { cbor_encode_null(&local); } @@ -846,7 +846,7 @@ class TranslateASTVisitor final std::function extra = [](CborEncoder *) {}) { auto ty = ast->getType(); auto isVaList = false; - auto encodeMacroExpansions = true; + auto encodeMacroInvocations = true; #if CLANG_VERSION_MAJOR < 13 bool isRValue = ast->isRValue(); #else @@ -860,7 +860,7 @@ class TranslateASTVisitor final auto span = ast->getSourceRange(); expandSpanToFinalChar(span, Context); encode_entry_raw(ast, tag, span, ty, isRValue, isVaList, - encodeMacroExpansions, childIds, extra); + encodeMacroInvocations, childIds, extra); typeEncoder.VisitQualTypeOf(ty, ast); } @@ -870,11 +870,11 @@ class TranslateASTVisitor final QualType s = QualType(static_cast(nullptr), 0); auto rvalue = false; auto isVaList = false; - auto encodeMacroExpansions = false; + auto encodeMacroInvocations = false; auto span = ast->getSourceRange(); expandSpanToFinalChar(span, Context); encode_entry_raw(ast, tag, span, s, rvalue, isVaList, - encodeMacroExpansions, childIds, extra); + encodeMacroInvocations, childIds, extra); } void encode_entry( @@ -882,11 +882,11 @@ class TranslateASTVisitor final const QualType T, std::function extra = [](CborEncoder *) {}) { auto rvalue = false; - auto encodeMacroExpansions = false; + auto encodeMacroInvocations = false; auto span = ast->getSourceRange(); expandSpanToFinalChar(span, Context); encode_entry_raw(ast, tag, span, T, rvalue, - isVaList(ast, T), encodeMacroExpansions, childIds, extra); + isVaList(ast, T), encodeMacroInvocations, childIds, extra); } /// Explicitly override the source location of this decl for cases where the @@ -897,10 +897,10 @@ class TranslateASTVisitor final const std::vector &childIds, const QualType T, std::function extra = [](CborEncoder *) {}) { auto rvalue = false; - auto encodeMacroExpansions = false; + auto encodeMacroInvocations = false; expandSpanToFinalChar(loc, Context); encode_entry_raw(ast, tag, loc, T, rvalue, - isVaList(ast, T), encodeMacroExpansions, childIds, extra); + isVaList(ast, T), encodeMacroInvocations, childIds, extra); } bool VisitMacro(StringRef name, SourceLocation loc, MacroInfo *mac, Expr *E) { @@ -973,11 +973,11 @@ class TranslateASTVisitor final void encodeMacros() { // Sort macros by source location - std::vector> macro_vec( + std::vector> macro_vec( macros.begin(), macros.end()); std::sort(macro_vec.begin(), macro_vec.end(), - [](const std::pair &a, - const std::pair &b) { + [](const std::pair &a, + const std::pair &b) { return a.first->getDefinitionLoc() < b.first->getDefinitionLoc(); }); @@ -1369,8 +1369,8 @@ class TranslateASTVisitor final // bool VisitExpr(Expr *E) { - curMacroExpansionStack.clear(); - curMacroExpansionSource = StringRef(); + curMacroInvocationStack.clear(); + curMacroInvocationSource = StringRef(); // We only translate constant macro objects to Rust consts, so this // expression must be constant. @@ -1404,7 +1404,7 @@ class TranslateASTVisitor final return true; } - curMacroExpansionSource = + curMacroInvocationSource = Lexer::getSourceText(ExpansionStack[0].range, Mgr, Context->getLangOpts()); for (auto &elem : ExpansionStack) { @@ -1426,7 +1426,7 @@ class TranslateASTVisitor final } if (VisitMacro(IdentifierInfo->getName(), loc, MacroInfo, E)) { - curMacroExpansionStack.push_back(MacroInfo); + curMacroInvocationStack.push_back(MacroInfo); } } diff --git a/c2rust-ast-exporter/src/clang_ast.rs b/c2rust-ast-exporter/src/clang_ast.rs index bac54c9302..4d44e74baf 100644 --- a/c2rust-ast-exporter/src/clang_ast.rs +++ b/c2rust-ast-exporter/src/clang_ast.rs @@ -108,8 +108,8 @@ pub struct AstNode { // Stack of macros this node was expanded from, beginning with the initial // macro call and ending with the leaf. This needs to be a stack for nested // macro definitions. - pub macro_expansions: Vec, - pub macro_expansion_text: Option, + pub macro_invocations: Vec, + pub macro_invocation_text: Option, pub extras: Vec, } @@ -260,9 +260,9 @@ pub fn process(items: Value) -> error::Result { }; // entry[10] - let macro_expansions = from_value::>(entry.pop_front().unwrap()).unwrap(); + let macro_invocations = from_value::>(entry.pop_front().unwrap()).unwrap(); - let macro_expansion_text = expect_opt_str(&entry.pop_front().unwrap()) + let macro_invocation_text = expect_opt_str(&entry.pop_front().unwrap()) .unwrap() .map(|s| s.to_string()); @@ -278,8 +278,8 @@ pub fn process(items: Value) -> error::Result { }, type_id, rvalue, - macro_expansions, - macro_expansion_text, + macro_invocations, + macro_invocation_text, extras: entry.into_iter().collect(), }; diff --git a/c2rust-transpile/src/c_ast/conversion.rs b/c2rust-transpile/src/c_ast/conversion.rs index 4da3d7e750..0f894003cd 100644 --- a/c2rust-transpile/src/c_ast/conversion.rs +++ b/c2rust-transpile/src/c_ast/conversion.rs @@ -1047,7 +1047,7 @@ impl ConversionContext { }; if expected_ty & EXPR != 0 { - for mac_id in &node.macro_expansions { + for mac_id in &node.macro_invocations { let mac = CDeclId(self.visit_node_type(*mac_id, MACRO_DECL)); self.typed_context .macro_invocations @@ -1057,7 +1057,7 @@ impl ConversionContext { } } - if let Some(text) = &node.macro_expansion_text { + if let Some(text) = &node.macro_invocation_text { self.typed_context .macro_expansion_text .insert(CExprId(new_id), text.clone()); From f6e254bd083f1b4f6d229a47915e8c717d3b85c8 Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 11:28:09 +0200 Subject: [PATCH 09/10] ast-exporter: Add parameter information to macro invocations --- c2rust-ast-exporter/src/AstExporter.cpp | 36 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index 1d3f1b4508..c57ea50805 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -725,10 +725,17 @@ class TranslateASTVisitor final std::set> exportedTags; std::unordered_map macros; + struct MacroInvocationInfo { + uint32_t key; + MacroInfo* macro; + StringRef parameter; + }; + // This stores a raw encoding of the macro call site SourceLocation, since // SourceLocation isn't hashable. - std::unordered_set macroCallSites; - SmallVector curMacroInvocationStack; + // TODO: Can this be made to use `unordered_set` for speed? + std::set> macroCallSites; + SmallVector curMacroInvocationStack; StringRef curMacroInvocationSource; // Returns true when a new entry is added to exportedTags @@ -815,7 +822,7 @@ class TranslateASTVisitor final if (encodeMacroInvocations) { for (auto I = curMacroInvocationStack.rbegin(), E = curMacroInvocationStack.rend(); I != E; ++I) { - cbor_encode_uint(&childEnc, uintptr_t(*I)); + cbor_encode_uint(&childEnc, uintptr_t(I->macro)); } } cbor_encoder_close_container(&local, &childEnc); @@ -903,14 +910,15 @@ class TranslateASTVisitor final isVaList(ast, T), encodeMacroInvocations, childIds, extra); } - bool VisitMacro(StringRef name, SourceLocation loc, MacroInfo *mac, Expr *E) { + bool VisitMacro(StringRef name, StringRef parameter, SourceLocation loc, MacroInfo *mac, Expr *E) { // TODO: handle builtin macros if (mac->isBuiltinMacro()) return false; // If this isn't the first time we've seen this macro call site, we // shouldn't associate this expression with the macro as it is a subexpr // of a previously seen expression. - if (!macroCallSites.insert(loc.getRawEncoding()).second) + std::pair key { loc.getRawEncoding(), parameter }; + if (!macroCallSites.insert(key).second) return false; auto &info = macros[mac]; if (info.Name.empty()) @@ -1408,11 +1416,20 @@ class TranslateASTVisitor final Lexer::getSourceText(ExpansionStack[0].range, Mgr, Context->getLangOpts()); for (auto &elem : ExpansionStack) { + auto loc = elem.range.getBegin(); + StringRef parameter; + if (elem.isParameter) { - continue; + auto IdentifierInfo = getIdentifierInfo(loc); + + if (!IdentifierInfo) { + return true; + } + + parameter = IdentifierInfo->getName(); + loc = Mgr.getImmediateExpansionRange(loc).getBegin(); } - auto loc = elem.range.getBegin(); auto IdentifierInfo = getIdentifierInfo(loc); if (!IdentifierInfo) { @@ -1425,8 +1442,9 @@ class TranslateASTVisitor final return true; } - if (VisitMacro(IdentifierInfo->getName(), loc, MacroInfo, E)) { - curMacroInvocationStack.push_back(MacroInfo); + if (VisitMacro(IdentifierInfo->getName(), parameter, loc, MacroInfo, E)) { + MacroInvocationInfo info = { loc.getRawEncoding(), MacroInfo, parameter }; + curMacroInvocationStack.push_back(info); } } From 0481fbc3a78f6875b2546c936379ad4a7064ac2e Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 14 May 2026 11:36:54 +0200 Subject: [PATCH 10/10] ast-exporter: Export macro parameter information to Rust --- c2rust-ast-exporter/src/AstExporter.cpp | 14 +++++++++++++- c2rust-ast-exporter/src/clang_ast.rs | 13 +++++++++++-- c2rust-transpile/src/c_ast/conversion.rs | 4 ++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index c57ea50805..f8981c12a5 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -822,7 +822,19 @@ class TranslateASTVisitor final if (encodeMacroInvocations) { for (auto I = curMacroInvocationStack.rbegin(), E = curMacroInvocationStack.rend(); I != E; ++I) { - cbor_encode_uint(&childEnc, uintptr_t(I->macro)); + CborEncoder expansionEnc; + cbor_encoder_create_array(&childEnc, &expansionEnc, 3); + + cbor_encode_uint(&expansionEnc, I->key); + cbor_encode_uint(&expansionEnc, uintptr_t(I->macro)); + + if (!I->parameter.empty()) { + cbor_encode_string(&expansionEnc, I->parameter.str()); + } else { + cbor_encode_null(&expansionEnc); + } + + cbor_encoder_close_container(&childEnc, &expansionEnc); } } cbor_encoder_close_container(&local, &childEnc); diff --git a/c2rust-ast-exporter/src/clang_ast.rs b/c2rust-ast-exporter/src/clang_ast.rs index 4d44e74baf..a96ee1c5cc 100644 --- a/c2rust-ast-exporter/src/clang_ast.rs +++ b/c2rust-ast-exporter/src/clang_ast.rs @@ -1,3 +1,4 @@ +use serde::Deserialize; use serde_bytes::ByteBuf; use serde_cbor::error; use std::collections::{HashMap, VecDeque}; @@ -108,11 +109,18 @@ pub struct AstNode { // Stack of macros this node was expanded from, beginning with the initial // macro call and ending with the leaf. This needs to be a stack for nested // macro definitions. - pub macro_invocations: Vec, + pub macro_invocations: Vec, pub macro_invocation_text: Option, pub extras: Vec, } +#[derive(Debug, Clone, Deserialize)] +pub struct MacroInvocationInfoRaw { + pub key: u32, + pub macro_id: u64, + pub parameter: Option, +} + #[derive(Debug, Clone)] pub struct TypeNode { pub tag: TypeTag, @@ -260,7 +268,8 @@ pub fn process(items: Value) -> error::Result { }; // entry[10] - let macro_invocations = from_value::>(entry.pop_front().unwrap()).unwrap(); + let macro_invocations = + from_value::>(entry.pop_front().unwrap()).unwrap(); let macro_invocation_text = expect_opt_str(&entry.pop_front().unwrap()) .unwrap() diff --git a/c2rust-transpile/src/c_ast/conversion.rs b/c2rust-transpile/src/c_ast/conversion.rs index 0f894003cd..89f8f723c5 100644 --- a/c2rust-transpile/src/c_ast/conversion.rs +++ b/c2rust-transpile/src/c_ast/conversion.rs @@ -1047,8 +1047,8 @@ impl ConversionContext { }; if expected_ty & EXPR != 0 { - for mac_id in &node.macro_invocations { - let mac = CDeclId(self.visit_node_type(*mac_id, MACRO_DECL)); + for info in &node.macro_invocations { + let mac = CDeclId(self.visit_node_type(info.macro_id, MACRO_DECL)); self.typed_context .macro_invocations .entry(CExprId(new_id))