Skip to content

Commit cf2f0b5

Browse files
committed
transpile: convert typedefs of target-dependent macros to their synthetic CTypeKinds
e.g., `typedef __SIZE_TYPE__ size_t;` -> `typedef <CTypeKind::Size> size_t`
1 parent 2fb013d commit cf2f0b5

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

c2rust-ast-exporter/src/AstExporter.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include <algorithm>
2+
#include <clang/AST/Type.h>
23
#include <cstdlib>
34
#include <fstream>
45
#include <iostream>
56
#include <iterator>
7+
#include <optional>
68
#include <set>
79
#include <unordered_map>
810
#include <unordered_set>
@@ -98,7 +100,6 @@ Optional<APSInt> getIntegerConstantExpr(const Expr &E, const ASTContext &Ctx) {
98100
#endif // CLANG_VERSION_MAJOR
99101
}
100102
#else
101-
#include <optional>
102103
std::optional<APSInt> getIntegerConstantExpr(const Expr &E,
103104
const ASTContext &Ctx) {
104105
return E.getIntegerConstantExpr(Ctx);
@@ -2225,6 +2226,36 @@ class TranslateASTVisitor final
22252226

22262227
bool VisitTypedefNameDecl(TypedefNameDecl *D) {
22272228
auto typeForDecl = D->getUnderlyingType();
2229+
// If this typedef is to a compiler-builtin macro with target-dependent definition, note the
2230+
// macro's name so we can map to the appropriate target-independent name (e.g. `size_t`).
2231+
auto targetDependentMacro = [&]() -> std::optional<std::string> {
2232+
TypeSourceInfo *TSI = D->getTypeSourceInfo();
2233+
if (!TSI)
2234+
return {};
2235+
2236+
TypeLoc typeLoc = TSI->getTypeLoc();
2237+
SourceLocation loc = typeLoc.getBeginLoc();
2238+
2239+
if (loc.isInvalid())
2240+
return {};
2241+
2242+
// Check if the location is from a macro expansion
2243+
if (!loc.isMacroID()) {
2244+
return {};
2245+
}
2246+
2247+
auto macroName = Lexer::getImmediateMacroName(loc, Context->getSourceManager(), Context->getLangOpts());
2248+
// Double-underscore indicates that name is reserved for the implementation,
2249+
// so this should not interfere with user code.
2250+
#if CLANG_VERSION_MAJOR >= 18
2251+
if (!macroName.starts_with("__")) {
2252+
#else
2253+
if (!macroName.startswith("__")) {
2254+
#endif // CLANG_VERSION_MAJOR
2255+
return {};
2256+
}
2257+
return std::make_optional(std::string(macroName));
2258+
}();
22282259
if (!D->isCanonicalDecl()) {
22292260
// Emit non-canonical decl so we have a placeholder to attach comments to
22302261
std::vector<void *> childIds = {D->getCanonicalDecl()};
@@ -2235,11 +2266,17 @@ class TranslateASTVisitor final
22352266

22362267
std::vector<void *> childIds;
22372268
encode_entry(D, TagTypedefDecl, childIds, typeForDecl,
2238-
[D](CborEncoder *array) {
2269+
[D, targetDependentMacro](CborEncoder *array) {
22392270
auto name = D->getNameAsString();
22402271
cbor_encode_string(array, name);
22412272

22422273
cbor_encode_boolean(array, D->isImplicit());
2274+
2275+
if (!targetDependentMacro) {
2276+
cbor_encode_null(array);
2277+
} else {
2278+
cbor_encode_string(array, targetDependentMacro->data());
2279+
}
22432280
});
22442281

22452282
typeEncoder.VisitQualType(typeForDecl);

c2rust-transpile/src/c_ast/conversion.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1884,12 +1884,53 @@ impl ConversionContext {
18841884
let typ_old = node
18851885
.type_id
18861886
.expect("Expected to find type on typedef declaration");
1887-
let typ = self.visit_qualified_type(typ_old);
1887+
let mut typ = self.visit_qualified_type(typ_old);
1888+
1889+
// Clang injects definitions of the form `#define SOME_MACRO unsigned int` into
1890+
// compilation units based on the target. (See lib/Frontend/InitPreprocessor.cpp
1891+
// in Clang).
1892+
//
1893+
// Later, headers contain defns like: `typedef SOME_MACRO standard_t;`
1894+
//
1895+
// We detect these typedefs and replace the type referred to by `SOME_MACRO`
1896+
// with a synthetic, portable `CTypeKind` chosen based on the macro's name.
1897+
//
1898+
// This allows us to generate platform-independent Rust types like u64 or usize
1899+
// despite the C side internally working with a target-specific type.
1900+
let target_dependent_macro: Option<String> = from_value(node.extras[2].clone())
1901+
.expect("Expected to find optional target-dependent macro name");
1902+
1903+
typ = target_dependent_macro
1904+
.as_deref()
1905+
.and_then(|macro_name| {
1906+
let kind = match macro_name {
1907+
// Match names in the order Clang defines them.
1908+
"__INTMAX_TYPE__" => CTypeKind::IntMax,
1909+
"__UINTMAX_TYPE__" => CTypeKind::UIntMax,
1910+
"__PTRDIFF_TYPE__" => CTypeKind::PtrDiff,
1911+
"__INTPTR_TYPE__" => CTypeKind::IntPtr,
1912+
"__SIZE_TYPE__" => CTypeKind::Size,
1913+
"__WCHAR_TYPE__" => CTypeKind::WChar,
1914+
// __WINT_TYPE__ is defined by Clang but has no obvious translation
1915+
// __CHARn_TYPE__ for n ∈ {8, 16, 32} also lack obvious translation
1916+
"__UINTPTR_TYPE__" => CTypeKind::UIntPtr,
1917+
_ => {
1918+
log::debug!("Unknown target-dependent macro {macro_name}!");
1919+
return None;
1920+
}
1921+
};
1922+
log::trace!("Selected kind {kind} for typedef {name}");
1923+
Some(CQualTypeId::new(
1924+
self.typed_context.type_for_kind(kind).unwrap(),
1925+
))
1926+
})
1927+
.unwrap_or(typ);
18881928

18891929
let typdef_decl = CDeclKind::Typedef {
18901930
name,
18911931
typ,
18921932
is_implicit,
1933+
target_dependent_macro,
18931934
};
18941935

18951936
self.add_decl(new_id, located(node, typdef_decl));

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,7 @@ pub enum CDeclKind {
951951
name: String,
952952
typ: CQualTypeId,
953953
is_implicit: bool,
954+
target_dependent_macro: Option<String>,
954955
},
955956

956957
// Struct

c2rust-transpile/src/translator/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1955,9 +1955,9 @@ impl<'c> Translation<'c> {
19551955
&mut self.type_converter.borrow_mut().translate_valist,
19561956
false,
19571957
);
1958+
19581959
let ty = self.convert_type(typ.ctype)?;
19591960
self.type_converter.borrow_mut().translate_valist = translate_valist;
1960-
19611961
Ok(ConvertedDecl::Item(
19621962
mk().span(span).pub_().type_item(new_name, ty),
19631963
))

0 commit comments

Comments
 (0)