Skip to content

Commit 62e8318

Browse files
committed
Fix implicit cast of string literals
1 parent 5907a12 commit 62e8318

7 files changed

Lines changed: 329 additions & 9 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,8 +2084,7 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
20842084
bool dest_pointee_const =
20852085
expr->getType()->getPointeeType().isConstQualified();
20862086
Convert(sub_expr);
2087-
if (clang::isa<clang::StringLiteral>(sub_expr) ||
2088-
clang::isa<clang::PredefinedExpr>(sub_expr)) {
2087+
if (IsStringLiteralExpr(sub_expr)) {
20892088
StrCat(".as_ptr()");
20902089
if (!dest_pointee_const) {
20912090
StrCat(".cast_mut()");

cpp2rust/converter/converter_lib.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ bool IsUnionArrayMember(const clang::Expr *base) {
140140
return false;
141141
}
142142

143+
bool IsStringLiteralExpr(const clang::Expr *expr) {
144+
const auto *stripped = expr->IgnoreParens()->IgnoreImplicit();
145+
return clang::isa<clang::StringLiteral>(stripped) ||
146+
clang::isa<clang::PredefinedExpr>(stripped);
147+
}
148+
143149
bool IsUserDefinedDecl(const clang::Decl *decl) {
144150
const auto &ctx = decl->getASTContext();
145151
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
@@ -42,6 +42,8 @@ bool IsInMainFile(const clang::Decl *decl);
4242

4343
bool IsUnionArrayMember(const clang::Expr *base);
4444

45+
bool IsStringLiteralExpr(const clang::Expr *expr);
46+
4547
bool IsUserDefinedDecl(const clang::Decl *decl);
4648

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

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,8 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
11701170
->getPointeeType()
11711171
->getAsArrayTypeUnsafe()
11721172
->getElementType())));
1173+
} else if (IsStringLiteralExpr(sub_expr)) {
1174+
StrCat(std::format("{}.to_any()", ConvertFreshPointer(sub_expr)));
11731175
} else {
11741176
StrCat(std::format("({} as {}).to_any()", ConvertFreshPointer(sub_expr),
11751177
ToString(sub_expr->getType())));
@@ -1209,9 +1211,9 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
12091211
Convert(sub_expr);
12101212
return false;
12111213
}
1212-
if (clang::isa<clang::StringLiteral>(sub_expr) ||
1213-
clang::isa<clang::PredefinedExpr>(sub_expr)) {
1214-
StrCat(std::format("Ptr::from_string_literal({})", ToString(sub_expr)));
1214+
if (IsStringLiteralExpr(sub_expr)) {
1215+
StrCat(std::format("Ptr::from_string_literal({})",
1216+
ToString(sub_expr->IgnoreParens())));
12151217
return false;
12161218
} else {
12171219
// we need to write (var.as_pointer as Ptr<T>) because Rust isn't
@@ -2222,10 +2224,16 @@ void ConverterRefCount::ConvertArraySubscript(clang::Expr *base,
22222224

22232225
{
22242226
PushParen paren(*this, is_inner_boxed);
2225-
StrCat(std::format("({} as {}).offset({})",
2226-
ToString(base->IgnoreImplicit()),
2227-
ConvertPtrType(base->IgnoreImplicit()->getType()),
2228-
ConvertRValue(idx)));
2227+
if (IsStringLiteralExpr(base)) {
2228+
StrCat(std::format("Ptr::from_string_literal({}).offset({})",
2229+
ToString(base->IgnoreParens()->IgnoreImplicit()),
2230+
ConvertRValue(idx)));
2231+
} else {
2232+
StrCat(std::format("({} as {}).offset({})",
2233+
ToString(base->IgnoreImplicit()),
2234+
ConvertPtrType(base->IgnoreImplicit()->getType()),
2235+
ConvertRValue(idx)));
2236+
}
22292237

22302238
if (is_inner_boxed) {
22312239
StrCat(GetPointerDerefSuffix(type), ".as_pointer()");
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
#[derive()]
10+
pub struct label {
11+
pub name: Value<Ptr<u8>>,
12+
pub probe: Value<FnPtr<fn() -> i32>>,
13+
pub mask: Value<i32>,
14+
}
15+
impl Clone for label {
16+
fn clone(&self) -> Self {
17+
Self {
18+
name: Rc::new(RefCell::new((*self.name.borrow()).clone())),
19+
probe: Rc::new(RefCell::new((*self.probe.borrow()).clone())),
20+
mask: Rc::new(RefCell::new((*self.mask.borrow()).clone())),
21+
}
22+
}
23+
}
24+
impl Default for label {
25+
fn default() -> Self {
26+
label {
27+
name: Rc::new(RefCell::new(Ptr::<u8>::null())),
28+
probe: Rc::new(RefCell::new(FnPtr::null())),
29+
mask: <Value<i32>>::default(),
30+
}
31+
}
32+
}
33+
impl ByteRepr for label {
34+
fn byte_size() -> usize {
35+
24
36+
}
37+
fn to_bytes(&self, buf: &mut [u8]) {
38+
(*self.name.borrow()).to_bytes(&mut buf[0..8]);
39+
(*self.probe.borrow()).to_bytes(&mut buf[8..16]);
40+
(*self.mask.borrow()).to_bytes(&mut buf[16..20]);
41+
}
42+
fn from_bytes(buf: &[u8]) -> Self {
43+
Self {
44+
name: Rc::new(RefCell::new(<Ptr<u8>>::from_bytes(&buf[0..8]))),
45+
probe: Rc::new(RefCell::new(<FnPtr<fn() -> i32>>::from_bytes(&buf[8..16]))),
46+
mask: Rc::new(RefCell::new(<i32>::from_bytes(&buf[16..20]))),
47+
}
48+
}
49+
}
50+
pub fn probe_two_0() -> i32 {
51+
return 1;
52+
}
53+
thread_local!(
54+
pub static table_1: Value<Box<[label]>> = Rc::new(RefCell::new(Box::new([
55+
label {
56+
name: Rc::new(RefCell::new(Ptr::from_string_literal(b"first"))),
57+
probe: Rc::new(RefCell::new(FnPtr::null())),
58+
mask: Rc::new(RefCell::new((1 << 4))),
59+
},
60+
label {
61+
name: Rc::new(RefCell::new(Ptr::from_string_literal(b"second"))),
62+
probe: Rc::new(RefCell::new((FnPtr::<fn() -> i32>::new(probe_two_0)))),
63+
mask: Rc::new(RefCell::new((1 << 5))),
64+
},
65+
])));
66+
);
67+
pub fn main() {
68+
std::process::exit(main_0());
69+
}
70+
fn main_0() -> i32 {
71+
assert!(
72+
((((((*(*table_1.with(Value::clone).borrow())[(0) as usize]
73+
.name
74+
.borrow())
75+
.offset((0) as isize)
76+
.read()) as i32)
77+
== ('f' as i32)) as i32)
78+
!= 0)
79+
);
80+
assert!(
81+
((((((*(*table_1.with(Value::clone).borrow())[(0) as usize]
82+
.name
83+
.borrow())
84+
.offset((4) as isize)
85+
.read()) as i32)
86+
== ('t' as i32)) as i32)
87+
!= 0)
88+
);
89+
assert!(
90+
((((*(*table_1.with(Value::clone).borrow())[(0) as usize]
91+
.probe
92+
.borrow())
93+
.is_null()) as i32)
94+
!= 0)
95+
);
96+
assert!(
97+
((((*(*table_1.with(Value::clone).borrow())[(0) as usize]
98+
.mask
99+
.borrow())
100+
== 16) as i32)
101+
!= 0)
102+
);
103+
assert!(
104+
((((((*(*table_1.with(Value::clone).borrow())[(1) as usize]
105+
.name
106+
.borrow())
107+
.offset((0) as isize)
108+
.read()) as i32)
109+
== ('s' as i32)) as i32)
110+
!= 0)
111+
);
112+
assert!(
113+
(((({
114+
(*(*(*table_1.with(Value::clone).borrow())[(1) as usize]
115+
.probe
116+
.borrow()))()
117+
}) == 1) as i32)
118+
!= 0)
119+
);
120+
assert!(
121+
((((*(*table_1.with(Value::clone).borrow())[(1) as usize]
122+
.mask
123+
.borrow())
124+
== 32) as i32)
125+
!= 0)
126+
);
127+
let tail: Value<Ptr<u8>> =
128+
Rc::new(RefCell::new((Ptr::from_string_literal(b"ab.cd").offset(2))));
129+
assert!(
130+
((((((*tail.borrow()).offset((0) as isize).read()) as i32) == ('.' as i32)) as i32) != 0)
131+
);
132+
assert!(
133+
((((((*tail.borrow()).offset((1) as isize).read()) as i32) == ('c' as i32)) as i32) != 0)
134+
);
135+
assert!(
136+
((((((*tail.borrow()).offset((2) as isize).read()) as i32) == ('d' as i32)) as i32) != 0)
137+
);
138+
let have: Value<i32> = Rc::new(RefCell::new(0));
139+
let p: Value<AnyPtr> = Rc::new(RefCell::new(if ((*have.borrow()) != 0) {
140+
(*(*table_1.with(Value::clone).borrow())[(0) as usize]
141+
.name
142+
.borrow())
143+
.clone()
144+
.to_any()
145+
} else {
146+
Ptr::from_string_literal(b"").to_any()
147+
}));
148+
assert!(
149+
(((((((*p.borrow()).reinterpret_cast::<u8>())
150+
.offset((0) as isize)
151+
.read()) as i32)
152+
== ('\0' as i32)) as i32)
153+
!= 0)
154+
);
155+
(*have.borrow_mut()) = 1;
156+
(*p.borrow_mut()) = if ((*have.borrow()) != 0) {
157+
(*(*table_1.with(Value::clone).borrow())[(0) as usize]
158+
.name
159+
.borrow())
160+
.clone()
161+
.to_any()
162+
} else {
163+
Ptr::from_string_literal(b"").to_any()
164+
};
165+
assert!(
166+
(((((((*p.borrow()).reinterpret_cast::<u8>())
167+
.offset((0) as isize)
168+
.read()) as i32)
169+
== ('f' as i32)) as i32)
170+
!= 0)
171+
);
172+
return 0;
173+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
#[repr(C)]
10+
#[derive(Copy, Clone)]
11+
pub struct label {
12+
pub name: *const libc::c_char,
13+
pub probe: Option<unsafe fn() -> i32>,
14+
pub mask: i32,
15+
}
16+
impl Default for label {
17+
fn default() -> Self {
18+
label {
19+
name: std::ptr::null(),
20+
probe: None,
21+
mask: 0_i32,
22+
}
23+
}
24+
}
25+
pub unsafe fn probe_two_0() -> i32 {
26+
return 1;
27+
}
28+
pub static mut table_1: [label; 2] = unsafe {
29+
[
30+
label {
31+
name: ((c"first").as_ptr().cast_mut()).cast_const(),
32+
probe: None,
33+
mask: ((1) << (4)),
34+
},
35+
label {
36+
name: ((c"second").as_ptr().cast_mut()).cast_const(),
37+
probe: (Some(probe_two_0)),
38+
mask: ((1) << (5)),
39+
},
40+
]
41+
};
42+
pub fn main() {
43+
unsafe {
44+
std::process::exit(main_0() as i32);
45+
}
46+
}
47+
unsafe fn main_0() -> i32 {
48+
assert!(
49+
(((((*table_1[(0) as usize].name.offset((0) as isize)) as i32) == ('f' as i32)) as i32)
50+
!= 0)
51+
);
52+
assert!(
53+
(((((*table_1[(0) as usize].name.offset((4) as isize)) as i32) == ('t' as i32)) as i32)
54+
!= 0)
55+
);
56+
assert!(((((table_1[(0) as usize].probe).is_none()) as i32) != 0));
57+
assert!(((((table_1[(0) as usize].mask) == (16)) as i32) != 0));
58+
assert!(
59+
(((((*table_1[(1) as usize].name.offset((0) as isize)) as i32) == ('s' as i32)) as i32)
60+
!= 0)
61+
);
62+
assert!(((((unsafe { (table_1[(1) as usize].probe).unwrap()() }) == (1)) as i32) != 0));
63+
assert!(((((table_1[(1) as usize].mask) == (32)) as i32) != 0));
64+
let mut tail: *const libc::c_char = (&mut (*c"ab.cd".as_ptr().cast_mut().offset((2) as isize))
65+
as *mut libc::c_char)
66+
.cast_const();
67+
assert!((((((*tail.offset((0) as isize)) as i32) == ('.' as i32)) as i32) != 0));
68+
assert!((((((*tail.offset((1) as isize)) as i32) == ('c' as i32)) as i32) != 0));
69+
assert!((((((*tail.offset((2) as isize)) as i32) == ('d' as i32)) as i32) != 0));
70+
let mut have: i32 = 0;
71+
let mut p: *mut ::libc::c_void = if (have != 0) {
72+
(table_1[(0) as usize].name as *mut ::libc::c_void)
73+
} else {
74+
(c"".as_ptr().cast_mut() as *mut libc::c_char as *mut ::libc::c_void)
75+
};
76+
assert!(
77+
(((((*(p as *const libc::c_char).offset((0) as isize)) as i32) == ('\0' as i32)) as i32)
78+
!= 0)
79+
);
80+
have = 1;
81+
p = if (have != 0) {
82+
(table_1[(0) as usize].name as *mut ::libc::c_void)
83+
} else {
84+
(c"".as_ptr().cast_mut() as *mut libc::c_char as *mut ::libc::c_void)
85+
};
86+
assert!(
87+
(((((*(p as *const libc::c_char).offset((0) as isize)) as i32) == ('f' as i32)) as i32)
88+
!= 0)
89+
);
90+
return 0;
91+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <assert.h>
2+
3+
#define END_MARK "ab.cd"
4+
5+
struct label {
6+
const char *name;
7+
int (*probe)(void);
8+
int mask;
9+
};
10+
11+
static int probe_two(void) { return 1; }
12+
13+
#define ENTRY(name, probe, mask) {(name), (probe), (mask)}
14+
15+
static const struct label table[] = {
16+
ENTRY("first", 0, 1 << 4),
17+
ENTRY("second", probe_two, 1 << 5),
18+
};
19+
20+
int main() {
21+
assert(table[0].name[0] == 'f');
22+
assert(table[0].name[4] == 't');
23+
assert(table[0].probe == 0);
24+
assert(table[0].mask == 16);
25+
assert(table[1].name[0] == 's');
26+
assert(table[1].probe() == 1);
27+
assert(table[1].mask == 32);
28+
29+
const char *tail = &END_MARK[2];
30+
assert(tail[0] == '.');
31+
assert(tail[1] == 'c');
32+
assert(tail[2] == 'd');
33+
34+
int have = 0;
35+
void *p = have ? (void *)table[0].name : "";
36+
assert(((const char *)p)[0] == '\0');
37+
have = 1;
38+
p = have ? (void *)table[0].name : "";
39+
assert(((const char *)p)[0] == 'f');
40+
return 0;
41+
}

0 commit comments

Comments
 (0)