Skip to content

Commit 9019390

Browse files
authored
Handle array to pointer decay for libc members (#176)
1 parent f0883dc commit 9019390

5 files changed

Lines changed: 35 additions & 3 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1944,9 +1944,18 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
19441944
Convert(sub_expr);
19451945
break;
19461946
}
1947-
Convert(sub_expr);
19481947
bool dest_pointee_const =
19491948
expr->getType()->getPointeeType().isConstQualified();
1949+
if (const auto *member =
1950+
clang::dyn_cast<clang::MemberExpr>(sub_expr->IgnoreParenImpCasts());
1951+
member && IsCharArrayFieldFromLibc(member->getMemberDecl())) {
1952+
PushParen paren(*this);
1953+
Convert(sub_expr);
1954+
StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()");
1955+
StrCat(keyword::kAs, dest_pointee_const ? "*const u8" : "*mut u8");
1956+
break;
1957+
}
1958+
Convert(sub_expr);
19501959
if (clang::isa<clang::StringLiteral>(sub_expr) ||
19511960
clang::isa<clang::PredefinedExpr>(sub_expr)) {
19521961
StrCat(".as_ptr()");

cpp2rust/converter/converter_lib.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@ bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl) {
139139
field->getParent()->getLocation());
140140
}
141141

142+
bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl) {
143+
auto field = clang::dyn_cast<clang::FieldDecl>(decl);
144+
if (!field || !field->getType()->isArrayType() ||
145+
!field->getType()->getArrayElementTypeNoTypeQual()->isCharType()) {
146+
return false;
147+
}
148+
return field->getASTContext().getSourceManager().isInSystemHeader(
149+
field->getParent()->getLocation());
150+
}
151+
142152
bool IsUserDefinedDecl(const clang::Decl *decl) {
143153
const auto &ctx = decl->getASTContext();
144154
const auto &src_mgr = ctx.getSourceManager();

cpp2rust/converter/converter_lib.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ bool IsInMainFile(const clang::Decl *decl);
4141

4242
bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl);
4343

44+
bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl);
45+
4446
bool IsUserDefinedDecl(const clang::Decl *decl);
4547

4648
bool RefersToUserDefinedDecl(const clang::Expr *expr);

tests/unit/libc_char_ptr_field.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// no-compile: refcount
2+
#include <dirent.h>
23
#include <pwd.h>
34
#include <unistd.h>
45

@@ -8,5 +9,11 @@ int main(void) {
89
return 0;
910
}
1011
char *home = pw->pw_dir;
11-
return home == 0;
12+
13+
struct dirent *d = readdir(opendir("/tmp"));
14+
// d_name is a char array which gets translated as i8. We model chars as u8 in
15+
// Rust.
16+
char *dname = d->d_name;
17+
18+
return 0;
1219
}

tests/unit/out/unsafe/libc_char_ptr_field.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,9 @@ unsafe fn main_0() -> i32 {
1717
return 0;
1818
}
1919
let mut home: *mut u8 = ((*pw).pw_dir as *mut u8);
20-
return (((home).is_null()) as i32);
20+
let mut d: *mut dirent = libc::readdir(libc::opendir(
21+
(b"/tmp\0".as_ptr().cast_mut()).cast_const() as *const i8,
22+
));
23+
let mut dname: *mut u8 = ((*d).d_name.as_mut_ptr() as *mut u8);
24+
return 0;
2125
}

0 commit comments

Comments
 (0)