Skip to content

Commit 569ed4c

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 d41c712 commit 569ed4c

File tree

4 files changed

+78
-3
lines changed

4 files changed

+78
-3
lines changed

c2rust-ast-exporter/src/AstExporter.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <algorithm>
2+
#include <clang/AST/Type.h>
23
#include <cstdlib>
34
#include <fstream>
45
#include <iostream>
@@ -2225,6 +2226,32 @@ 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 (!macroName.starts_with("__")) {
2251+
return {};
2252+
}
2253+
return std::make_optional(std::string(macroName));
2254+
}();
22282255
if (!D->isCanonicalDecl()) {
22292256
// Emit non-canonical decl so we have a placeholder to attach comments to
22302257
std::vector<void *> childIds = {D->getCanonicalDecl()};
@@ -2235,11 +2262,17 @@ class TranslateASTVisitor final
22352262

22362263
std::vector<void *> childIds;
22372264
encode_entry(D, TagTypedefDecl, childIds, typeForDecl,
2238-
[D](CborEncoder *array) {
2265+
[D, targetDependentMacro](CborEncoder *array) {
22392266
auto name = D->getNameAsString();
22402267
cbor_encode_string(array, name);
22412268

22422269
cbor_encode_boolean(array, D->isImplicit());
2270+
2271+
if (!targetDependentMacro) {
2272+
cbor_encode_null(array);
2273+
} else {
2274+
cbor_encode_string(array, targetDependentMacro->data());
2275+
}
22432276
});
22442277

22452278
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
@@ -1954,9 +1954,9 @@ impl<'c> Translation<'c> {
19541954
&mut self.type_converter.borrow_mut().translate_valist,
19551955
false,
19561956
);
1957+
19571958
let ty = self.convert_type(typ.ctype)?;
19581959
self.type_converter.borrow_mut().translate_valist = translate_valist;
1959-
19601960
Ok(ConvertedDecl::Item(
19611961
mk().span(span).pub_().type_item(new_name, ty),
19621962
))

0 commit comments

Comments
 (0)