Skip to content

Commit 2bf5df6

Browse files
authored
Fix detection of va_list type (#20)
On macOS `va_list` is typedef'ed to `char*`, on Linux is typedefed to `__va_list_tag[1]`. Traverse the TypedefType/AdjustedType in order to check if a type is va_list instead of checking against the Linux specific `__va_list_tag`.
1 parent 9359210 commit 2bf5df6

28 files changed

Lines changed: 70 additions & 49 deletions

cpp2rust/converter/converter.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ bool Converter::VisitRecoveryExpr(clang::RecoveryExpr *expr) {
6363
}
6464

6565
bool Converter::Convert(clang::QualType qual_type) {
66+
// Catch va_list before desugaring
67+
if (IsVaListType(qual_type)) {
68+
StrCat("VaList");
69+
return false;
70+
}
71+
6672
if (Mapper::Contains(qual_type) &&
6773
Mapper::Map(qual_type) != ignore_rule_type_) {
6874
StrCat(Mapper::Map(qual_type));
@@ -243,7 +249,7 @@ bool Converter::VisitPointerType(clang::PointerType *type) {
243249
return false;
244250
}
245251

246-
if (IsVaListType(ctx_, clang::QualType(type, 0))) {
252+
if (IsVaListType(clang::QualType(type, 0))) {
247253
StrCat("VaList");
248254
return false;
249255
}
@@ -371,7 +377,7 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
371377
auto qual_type = decl->getType();
372378
auto name = GetNamedDeclAsString(decl);
373379

374-
if (IsVaListType(ctx_, qual_type) && decl->isLocalVarDecl()) {
380+
if (IsVaListType(qual_type) && decl->isLocalVarDecl()) {
375381
ConvertVaListVarDecl(decl);
376382
return true;
377383
}
@@ -1641,7 +1647,7 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
16411647
return Convert(sub_expr);
16421648
}
16431649
// __va_list_tag [1] decays to __va_list_tag *. Just pass through by value
1644-
if (IsVaListType(ctx_, sub_expr->getType())) {
1650+
if (IsVaListType(sub_expr->getType())) {
16451651
Convert(sub_expr);
16461652
break;
16471653
}
@@ -2650,6 +2656,11 @@ Converter::GetFunctionPointerDefaultAsString(clang::QualType qual_type) {
26502656
}
26512657

26522658
std::string Converter::GetDefaultAsString(clang::QualType qual_type) {
2659+
if (IsVaListType(qual_type)) {
2660+
computed_expr_type_ = ComputedExprType::FreshValue;
2661+
return "VaList::default()";
2662+
}
2663+
26532664
if (qual_type->isPointerType()) {
26542665
if (qual_type->getPointeeType()->isFunctionType()) {
26552666
return GetFunctionPointerDefaultAsString(qual_type);

cpp2rust/converter/converter_lib.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -600,24 +600,24 @@ bool IsRedundantCopyInConversion(clang::ASTContext &ctx,
600600
return parent && parent->getConstructor()->isConvertingConstructor(false);
601601
}
602602

603-
// va_list is implemented as __va_list_tag[1] and decays to __va_list_tag *.
604-
// That's because va_list must have pointer semantics, but still be passed as
605-
// value by user code.
606-
bool IsVaListType(clang::ASTContext &ctx, clang::QualType type) {
607-
auto canonical = type.getCanonicalType();
608-
auto va_list = ctx.getBuiltinVaListType().getCanonicalType();
609-
610-
// Direct match: va_list itself
611-
if (canonical == va_list) {
612-
return true;
613-
}
614-
615-
// Decayed match: __va_list_tag[1] decays to __va_list_tag *
616-
if (auto *arr = clang::dyn_cast<clang::ConstantArrayType>(va_list)) {
617-
return canonical ==
618-
ctx.getPointerType(arr->getElementType()).getCanonicalType();
603+
bool IsVaListType(clang::QualType type) {
604+
for (auto t = type; !t.isNull();) {
605+
if (auto *adjusted = t->getAs<clang::AdjustedType>()) {
606+
// Possibly decayed va_list
607+
t = adjusted->getOriginalType();
608+
continue;
609+
} else if (auto *typedef_type = t->getAs<clang::TypedefType>()) {
610+
// Typedef'ed va_list
611+
if (auto decl = typedef_type->getDecl()) {
612+
if (decl->getName().contains("va_list")) {
613+
return true;
614+
}
615+
t = decl->getUnderlyingType();
616+
continue;
617+
}
618+
}
619+
break;
619620
}
620-
621621
return false;
622622
}
623623

cpp2rust/converter/converter_lib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ std::string GetClassName(clang::QualType type);
142142
bool IsRedundantCopyInConversion(clang::ASTContext &ctx,
143143
const clang::CXXConstructExpr *expr);
144144

145-
bool IsVaListType(clang::ASTContext &ctx, clang::QualType type);
145+
bool IsVaListType(clang::QualType type);
146146

147147
bool IsBuiltinVaStart(const clang::CallExpr *expr);
148148

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ std::string ConverterRefCount::BoxValue(std::string &&str) const {
133133
}
134134

135135
bool ConverterRefCount::Convert(clang::QualType qual_type) {
136+
// Catch va_list before desugaring
137+
if (IsVaListType(qual_type)) {
138+
StrCat(BoxType("VaList"));
139+
return false;
140+
}
141+
136142
if (!Mapper::Contains(qual_type))
137143
qual_type = qual_type.getUnqualifiedType().getDesugaredType(ctx_);
138144

@@ -172,7 +178,7 @@ bool ConverterRefCount::VisitPointerType(clang::PointerType *type) {
172178
return false;
173179
}
174180

175-
if (IsVaListType(ctx_, clang::QualType(type, 0))) {
181+
if (IsVaListType(clang::QualType(type, 0))) {
176182
StrCat("VaList");
177183
return false;
178184
}
@@ -933,7 +939,7 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
933939
}
934940

935941
if (expr->getCastKind() == clang::CastKind::CK_ArrayToPointerDecay) {
936-
if (IsVaListType(ctx_, sub_expr->getType())) {
942+
if (IsVaListType(sub_expr->getType())) {
937943
Convert(sub_expr);
938944
return false;
939945
}
@@ -1408,6 +1414,10 @@ bool ConverterRefCount::VisitCXXDefaultArgExpr(clang::CXXDefaultArgExpr *expr) {
14081414
}
14091415

14101416
std::string ConverterRefCount::GetDefaultAsString(clang::QualType qual_type) {
1417+
if (IsVaListType(qual_type)) {
1418+
return BoxValue("VaList::default()");
1419+
}
1420+
14111421
std::string ret;
14121422
if (qual_type->isPointerType()) {
14131423
auto pointee_type = qual_type->getPointeeType();

tests/unit/out/refcount/va_arg_chain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn middle_layer_1(n: i32, ap: VaList) -> i32 {
2828
}
2929
pub fn top_level_2(n: i32, args: &[VaArg]) -> i32 {
3030
let n: Value<i32> = Rc::new(RefCell::new(n));
31-
let ap: Value<VaList> = <Value<VaList>>::default();
31+
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
3232
(*ap.borrow_mut()) = VaList::new(args);
3333
let result: Value<i32> = Rc::new(RefCell::new(
3434
({

tests/unit/out/refcount/va_arg_concat.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::os::fd::AsFd;
99
use std::rc::{Rc, Weak};
1010
pub fn sum_ints_0(first: i32, args: &[VaArg]) -> i32 {
1111
let first: Value<i32> = Rc::new(RefCell::new(first));
12-
let ap: Value<VaList> = <Value<VaList>>::default();
12+
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
1313
let total: Value<i32> = Rc::new(RefCell::new((*first.borrow())));
1414
(*ap.borrow_mut()) = VaList::new(args);
1515
let val: Value<i32> = <Value<i32>>::default();

tests/unit/out/refcount/va_arg_conditional.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub fn conditional_log_0(verbose: i32, fmt: Ptr<u8>, args: &[VaArg]) -> i32 {
1111
let verbose: Value<i32> = Rc::new(RefCell::new(verbose));
1212
let fmt: Value<Ptr<u8>> = Rc::new(RefCell::new(fmt));
1313
if ((*verbose.borrow()) != 0) {
14-
let ap: Value<VaList> = <Value<VaList>>::default();
14+
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
1515
(*ap.borrow_mut()) = VaList::new(args);
1616
let result: Value<i32> = Rc::new(RefCell::new(((*ap.borrow_mut()).arg::<i32>()).clone()));
1717
return (*result.borrow());

tests/unit/out/refcount/va_arg_copy.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use std::os::fd::AsFd;
99
use std::rc::{Rc, Weak};
1010
pub fn sum_with_copy_0(count: i32, args: &[VaArg]) -> i32 {
1111
let count: Value<i32> = Rc::new(RefCell::new(count));
12-
let ap: Value<VaList> = <Value<VaList>>::default();
13-
let aq: Value<VaList> = <Value<VaList>>::default();
12+
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
13+
let aq: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
1414
(*ap.borrow_mut()) = VaList::new(args);
1515
(*aq.borrow_mut()) = (*ap.borrow_mut()).clone();
1616
let sum1: Value<i32> = Rc::new(RefCell::new(0));

tests/unit/out/refcount/va_arg_forward.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub fn inner_0(count: i32, ap: VaList) -> i32 {
2020
}
2121
pub fn outer_1(count: i32, args: &[VaArg]) -> i32 {
2222
let count: Value<i32> = Rc::new(RefCell::new(count));
23-
let ap: Value<VaList> = <Value<VaList>>::default();
23+
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
2424
(*ap.borrow_mut()) = VaList::new(args);
2525
let result: Value<i32> = Rc::new(RefCell::new(
2626
({

tests/unit/out/refcount/va_arg_mixed_int_ptr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::os::fd::AsFd;
99
use std::rc::{Rc, Weak};
1010
pub fn mixed_args_0(count: i32, args: &[VaArg]) -> i32 {
1111
let count: Value<i32> = Rc::new(RefCell::new(count));
12-
let ap: Value<VaList> = <Value<VaList>>::default();
12+
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
1313
(*ap.borrow_mut()) = VaList::new(args);
1414
let total: Value<i32> = Rc::new(RefCell::new(0));
1515
let i: Value<i32> = Rc::new(RefCell::new(0));

0 commit comments

Comments
 (0)