Skip to content

Commit 91fc4be

Browse files
authored
Distinguish between empty match and non-match (#103)
After 4cb7e30, the matcher inside mapper.cpp broke for the following case: ``` template: "T1 & std::vector<T1>::back()" instantiated: "& std::vector<int> & std::vector<std::vector<int>>::back()" Leading & comes from the call inside VisitUnaryOperator ``` The first T1 is matched to the empty string: ``` T1 & std::vector< T1>::back() & std::vector< int> & std::vector<std::vector<int>>::back() ``` Then, when the second T1 is matched (`int> & std::vector<std::vector<int>`), it goes to the else branch because it believes that the first T1 was never encountered: https://github.com/Cpp2Rust/cpp2rust/blob/1ac73cce3139294d47b421c5d08efa927508bb2d/cpp2rust/converter/mapper.cpp#L253-L260 The fix is to replace the captured `std::vector<std::string>` with `std::vector<std::optional<std::string>>` so that empty matched string can be distinguished from non-matched stirng.
1 parent f120aeb commit 91fc4be

4 files changed

Lines changed: 76 additions & 12 deletions

File tree

cpp2rust/converter/mapper.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <llvm/Support/ThreadPool.h>
1010

1111
#include <format>
12+
#include <optional>
1213
#include <regex>
1314
#include <unordered_map>
1415
#include <utility>
@@ -93,7 +94,7 @@ void AddTypeRule(std::string src, TranslationRule::TypeRule &&rule) {
9394
// template_str = "std::vector<T1>::vector()"
9495
// instantiated = "std::vector<int>::vector()"
9596
// result = { "int" }
96-
std::optional<std::vector<std::string>>
97+
std::optional<std::vector<std::optional<std::string>>>
9798
matchTemplate(const std::string &template_str,
9899
const std::string &instantiated) {
99100
auto matchLiteralAt = [&](const std::string &input_str, size_t pos,
@@ -220,7 +221,7 @@ matchTemplate(const std::string &template_str,
220221
return std::string::npos;
221222
};
222223

223-
std::vector<std::string> captured;
224+
std::vector<std::optional<std::string>> captured;
224225

225226
size_t ti = 0;
226227
size_t si = 0;
@@ -250,9 +251,9 @@ matchTemplate(const std::string &template_str,
250251

251252
captured.resize(std::max(captured.size(), type_idx + 1));
252253
auto &repl = captured[type_idx];
253-
if (!repl.empty()) {
254+
if (repl.has_value()) {
254255
size_t end_pos = 0;
255-
if (!matchLiteralAt(instantiated, si, repl, end_pos)) {
256+
if (!matchLiteralAt(instantiated, si, *repl, end_pos)) {
256257
return std::nullopt;
257258
}
258259
si = end_pos;
@@ -338,7 +339,7 @@ matchTemplate(const std::string &template_str,
338339
// types = { {"i32"} }
339340
// tgt_template = "Vec<T1>"
340341
// result = "Vec<i32>"
341-
std::string instantiateTgt(const std::vector<std::string> &types,
342+
std::string instantiateTgt(const std::vector<std::optional<std::string>> &types,
342343
const std::string &tgt_template) {
343344
assert(types.size() <= 9);
344345
std::string instantiated_template = tgt_template;
@@ -351,20 +352,20 @@ std::string instantiateTgt(const std::vector<std::string> &types,
351352
++pos;
352353
continue;
353354
}
354-
auto &repl = types.at(instantiated_template[pos + 1] - '1');
355+
const auto &repl = types.at(instantiated_template[pos + 1] - '1').value();
355356
instantiated_template.replace(pos, 2, repl);
356357
pos += repl.length();
357358
}
358359
return instantiated_template;
359360
}
360361

361362
template <typename T>
362-
std::pair<T *, std::vector<std::string>>
363+
std::pair<T *, std::vector<std::optional<std::string>>>
363364
search(std::unordered_multimap<std::string, T> &map, const std::string &txt,
364365
const std::string &key) {
365366
auto [it, end] = map.equal_range(key);
366367
T *rule = nullptr;
367-
std::vector<std::string> subs;
368+
std::vector<std::optional<std::string>> subs;
368369

369370
for (; it != end; ++it) {
370371
auto &this_rule = it->second;
@@ -540,7 +541,9 @@ std::string mapTypeStringRecursive(const std::string &cpp_type) {
540541
assert(0 && "Type is not present in types_");
541542
}
542543
for (auto &ty : subs) {
543-
ty = mapTypeStringRecursive(ty);
544+
if (ty) {
545+
ty = mapTypeStringRecursive(*ty);
546+
}
544547
}
545548
return instantiateTgt(subs, rule->type_info.type);
546549
}
@@ -608,7 +611,9 @@ std::string InstantiateTemplate(const clang::Expr *expr, unsigned n) {
608611
return text;
609612
}
610613
for (auto &ty : subs) {
611-
ty = mapTypeStringRecursive(ty);
614+
if (ty) {
615+
ty = mapTypeStringRecursive(*ty);
616+
}
612617
}
613618
return instantiateTgt(subs, text);
614619
}
@@ -618,7 +623,9 @@ std::string Map(clang::QualType qual_type) {
618623
auto [rule, subs] = search(types_, type_str, GetTypeMapKey(type_str));
619624
if (rule) {
620625
for (auto &ty : subs) {
621-
ty = mapTypeStringRecursive(ty);
626+
if (ty) {
627+
ty = mapTypeStringRecursive(*ty);
628+
}
622629
}
623630
return instantiateTgt(subs, rule->type_info.type);
624631
}
@@ -651,7 +658,9 @@ std::string GetParamType(const clang::Expr *expr, unsigned index) {
651658
auto expr_str = ToString(expr);
652659
auto [rule, subs] = search(exprs_, expr_str, GetExprMapKey(expr_str));
653660
for (auto &ty : subs) {
654-
ty = mapTypeStringRecursive(ty);
661+
if (ty) {
662+
ty = mapTypeStringRecursive(*ty);
663+
}
655664
}
656665
return instantiateTgt(subs, rule->params.at(index).type);
657666
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
pub fn main() {
10+
std::process::exit(main_0());
11+
}
12+
fn main_0() -> i32 {
13+
let outer: Value<Vec<Value<Vec<i32>>>> = Rc::new(RefCell::new(Vec::new()));
14+
let inner: Value<Vec<i32>> = Rc::new(RefCell::new(Vec::new()));
15+
(outer.as_pointer() as Ptr<Vec<Value<Vec<i32>>>>).with_mut(|__v: &mut Vec<Value<Vec<i32>>>| {
16+
__v.push(Rc::new(RefCell::new((*inner.borrow()).clone())))
17+
});
18+
let sink: Value<Ptr<Vec<i32>>> = Rc::new(RefCell::new(
19+
((*outer.borrow())[(*outer.borrow()).len() - 1].as_pointer()),
20+
));
21+
assert!(((*(*sink.borrow()).upgrade().deref()).len() as u64 == 0_u64));
22+
return 0;
23+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
pub fn main() {
10+
unsafe {
11+
std::process::exit(main_0() as i32);
12+
}
13+
}
14+
unsafe fn main_0() -> i32 {
15+
let mut outer: Vec<Vec<i32>> = Vec::new();
16+
let mut inner: Vec<i32> = Vec::new();
17+
outer.push(inner.clone());
18+
let mut sink: *mut Vec<i32> = ((outer).last_mut().unwrap());
19+
assert!((((*sink.cast_const()).len() as u64) == (0_u64)));
20+
return 0;
21+
}

tests/unit/vector_addr_of_back.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <assert.h>
2+
#include <vector>
3+
4+
int main() {
5+
std::vector<std::vector<int>> outer;
6+
std::vector<int> inner;
7+
outer.push_back(inner);
8+
auto *sink = &outer.back();
9+
assert(sink->size() == 0);
10+
return 0;
11+
}

0 commit comments

Comments
 (0)