Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,12 @@ bool Converter::RecordDerivesDefault(const clang::RecordDecl *decl) {
}

bool Converter::RecordDerivesCopy(const clang::RecordDecl *decl) {
auto *derives = Mapper::MappedDerives(ctx_.getCanonicalTagType(decl));
return derives &&
std::find(derives->begin(), derives->end(), "Copy") != derives->end();
}

bool Converter::RecordHasCopyableFields(const clang::RecordDecl *decl) {
for (auto f : decl->fields()) {
// Records that contain std::vector, std::array, std::string or anything
// that is translated to Vec<>, do not derive Copy
Expand Down Expand Up @@ -751,8 +757,11 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
if (EmitsReprCForRecords()) {
StrCat("#[repr(C)]");
}
auto attrs = GetStructAttributes(decl);
Mapper::SetDerives(ctx_.getCanonicalTagType(decl),
std::vector<std::string>(attrs.begin(), attrs.end()));
StrCat("#[derive(");
for (auto *attr : GetStructAttributes(decl)) {
for (auto *attr : attrs) {
StrCat(attr, ',');
}
StrCat(")]");
Expand Down Expand Up @@ -3107,6 +3116,8 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) {
return false;
}
Mapper::AddRuleForUserDefinedType(decl);
Mapper::SetDerives(ctx_.getCanonicalTagType(decl),
{"Clone", "Copy", "PartialEq", "Debug", "Default"});
StrCat("#[derive(Clone, Copy, PartialEq, Debug, Default)]");
StrCat(std::format("enum {}", GetRecordName(decl)));
StrCat('{');
Expand Down Expand Up @@ -3324,6 +3335,12 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
auto size_as_string = GetNumAsString(array_type->getSize());
auto element_type = array_type->getElementType();
auto element_type_as_string = GetDefaultAsString(element_type);
if (auto *rec = element_type->getAsRecordDecl()) {
if (!RecordDerivesCopy(rec)) {
return std::format("std::array::from_fn::<_, {}, _>(|_| {})",
size_as_string.c_str(), element_type_as_string);
}
}
return std::format("[{}; {}]", element_type_as_string,
size_as_string.c_str());
}
Expand Down Expand Up @@ -3487,7 +3504,7 @@ Converter::GetStructAttributes(const clang::RecordDecl *decl) {

std::vector<const char *> struct_attrs;

if (RecordDerivesCopy(decl)) {
if (RecordHasCopyableFields(decl)) {
struct_attrs.emplace_back("Copy");
}

Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

bool RecordDerivesCopy(const clang::RecordDecl *decl);

bool RecordHasCopyableFields(const clang::RecordDecl *decl);

bool ShouldReplaceWithMappedBody(clang::DeclRefExpr *expr) const;

std::string *rs_code_;
Expand Down
16 changes: 16 additions & 0 deletions cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,12 @@ void addBuiltinTypes(Model model) {
const std::string &initializer = {}) {
auto plain = TranslationRule::TypeRule::Plain(rust);
plain.initializer = initializer;
std::vector<std::string> derives = {"Copy", "Clone", "Default",
"Debug", "PartialEq", "PartialOrd"};
if (!(rust == "f32" || rust == "f64")) {
derives.insert(derives.end(), {"Eq", "Ord", "Hash"});
}
plain.type_info.derives = std::move(derives);
AddTypeRule(cxx, TranslationRule::TypeRule(plain));
AddTypeRule("const " + cxx, std::move(plain));

Expand Down Expand Up @@ -696,6 +702,16 @@ bool MapsToRefcountPointer(clang::QualType qual_type) {
return rule && rule->type_info.is_refcount_pointer;
}

const std::vector<std::string> *MappedDerives(clang::QualType qual_type) {
auto rule = search(qual_type).first;
return rule ? &rule->type_info.derives : nullptr;
}

void SetDerives(clang::QualType qual_type, std::vector<std::string> derives) {
if (auto *rule = search(qual_type).first) {
rule->type_info.derives = std::move(derives);
}
}
bool ReturnsPointer(const clang::Expr *expr) {
auto rule = search(expr);
return rule && rule->return_type.is_pointer();
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ std::string GetParamType(const clang::Expr *expr, unsigned index);
bool ParamIsPointer(const clang::Expr *expr, unsigned index);
bool MapsToPointer(clang::QualType qual_type);
bool MapsToRefcountPointer(clang::QualType qual_type);
const std::vector<std::string> *MappedDerives(clang::QualType qual_type);
void SetDerives(clang::QualType qual_type, std::vector<std::string> derives);

enum class ScalarSugar {
kDesugar,
Expand Down
8 changes: 8 additions & 0 deletions cpp2rust/converter/translation_rule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ TypeInfo ParseTypeInfoJSON(const llvm::json::Object &obj) {
if (auto v = obj.getBoolean("is_unsafe_pointer"))
info.is_unsafe_pointer = *v;
assert(!(info.is_refcount_pointer && info.is_unsafe_pointer));
if (auto *arr = obj.getArray("derives")) {
for (const auto &elem : *arr) {
if (auto s = elem.getAsString())
info.derives.emplace_back(s->str());
}
}
return info;
}

Expand Down Expand Up @@ -329,6 +335,8 @@ void TypeInfo::dump() const {
log() << " [rc_ptr]";
if (is_unsafe_pointer)
log() << " [unsafe_ptr]";
for (const auto &d : derives)
log() << " +" << d;
}

void TypeRule::dump() const {
Expand Down
7 changes: 4 additions & 3 deletions cpp2rust/converter/translation_rule.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct MethodCallFragment {
};

struct TypeInfo {
std::vector<std::string> derives;
std::string type;
bool is_refcount_pointer = false;
bool is_unsafe_pointer = false;
Expand Down Expand Up @@ -83,13 +84,13 @@ struct TypeRule {
void dump() const;

static TypeRule Plain(std::string type) {
return {{}, {}, {std::move(type), false, false}};
return {{}, {}, {{}, std::move(type), false, false}};
}
static TypeRule RefcountPtr(std::string type) {
return {{}, {}, {std::move(type), true, false}};
return {{}, {}, {{}, std::move(type), true, false}};
}
static TypeRule UnsafePtr(std::string type) {
return {{}, {}, {std::move(type), false, true}};
return {{}, {}, {{}, std::move(type), false, true}};
}
};

Expand Down
2 changes: 2 additions & 0 deletions rule-preprocessor/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub struct TypeInfo {
pub is_refcount_pointer: bool,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub is_unsafe_pointer: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub derives: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
2 changes: 2 additions & 0 deletions rule-preprocessor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@

extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_infer;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_span;
extern crate rustc_trait_selection;

mod ir;
mod semantic;
Expand Down
58 changes: 52 additions & 6 deletions rule-preprocessor/src/semantic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ fn find_rlib(deps_dir: &Path, crate_name: &str) -> Option<PathBuf> {
struct FnDecl<'tcx> {
source_file: String,
name: String,
def_id: rustc_span::def_id::DefId,
body: &'tcx rustc_hir::Body<'tcx>,
}

Expand Down Expand Up @@ -124,11 +125,17 @@ struct MethodResolver {
}

impl MethodResolver {
fn resolve_fn_decl<'tcx>(&mut self, tcx: rustc_middle::ty::TyCtxt<'tcx>, f: &FnDecl<'tcx>) {
if let Some(file_ir) = self.ir.all_ir.get_mut(&f.source_file)
&& let Some(RuleIr::Fn(fn_ir)) = file_ir.get_mut(&f.name)
{
f.resolve_unknowns(tcx, fn_ir);
fn resolve_rule<'tcx>(&mut self, tcx: rustc_middle::ty::TyCtxt<'tcx>, f: &FnDecl<'tcx>) {
let Some(file_ir) = self.ir.all_ir.get_mut(&f.source_file) else {
return;
};
match file_ir.get_mut(&f.name) {
Some(RuleIr::Fn(fn_ir)) => f.resolve_unknowns(tcx, fn_ir),
Some(RuleIr::Type(type_ir)) => {
let ret_ty = tcx.fn_sig(f.def_id).skip_binder().output().skip_binder();
type_ir.type_info.derives = type_derives(tcx, ret_ty);
}
None => {}
}
}

Expand All @@ -154,7 +161,7 @@ impl rustc_driver::Callbacks for MethodResolver {
tcx: rustc_middle::ty::TyCtxt<'_>,
) -> rustc_driver::Compilation {
for f in iter_fn_decls(tcx) {
self.resolve_fn_decl(tcx, &f);
self.resolve_rule(tcx, &f);
}

rustc_driver::Compilation::Stop
Expand All @@ -181,6 +188,7 @@ fn iter_fn_decls<'tcx>(tcx: rustc_middle::ty::TyCtxt<'tcx>) -> Vec<FnDecl<'tcx>>
result.push(FnDecl {
source_file,
name: ident.name.as_str().to_string(),
def_id: decl_id.owner_id.to_def_id(),
body: tcx.hir_body(body_id),
});
}
Expand All @@ -205,6 +213,44 @@ fn decl_source_file(
)
}

fn type_derives<'tcx>(
tcx: rustc_middle::ty::TyCtxt<'tcx>,
ty: rustc_middle::ty::Ty<'tcx>,
) -> Vec<String> {
use rustc_infer::infer::TyCtxtInferExt;
use rustc_span::sym;
use rustc_trait_selection::infer::InferCtxtExt;

let lang = tcx.lang_items();
let derivable = [
lang.copy_trait(),
lang.clone_trait(),
tcx.get_diagnostic_item(sym::Debug),
tcx.get_diagnostic_item(sym::Default),
tcx.get_diagnostic_item(sym::PartialEq),
tcx.get_diagnostic_item(sym::Eq),
tcx.get_diagnostic_item(sym::PartialOrd),
tcx.get_diagnostic_item(sym::Ord),
tcx.get_diagnostic_item(sym::Hash),
];

let infcx = tcx
.infer_ctxt()
.build(rustc_middle::ty::TypingMode::non_body_analysis());

derivable
.into_iter()
.flatten()
.filter(|&trait_def_id| {
let args = vec![ty; tcx.generics_of(trait_def_id).count()];
infcx
.type_implements_trait(trait_def_id, args, rustc_middle::ty::ParamEnv::empty())
.must_apply_modulo_regions()
})
.map(|trait_def_id| tcx.item_name(trait_def_id).to_string())
.collect()
}

struct AstVisitor<'a, 'tcx> {
tcx: rustc_middle::ty::TyCtxt<'tcx>,
param_names: Vec<String>,
Expand Down
3 changes: 3 additions & 0 deletions rule-preprocessor/src/syntactic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ impl<'a> FnIrBuilder<'a> {
ty: ty_str,
is_refcount_pointer,
is_unsafe_pointer,
derives: Vec::new(),
})
}
}
Expand Down Expand Up @@ -482,6 +483,7 @@ impl<'a> FnIrBuilder<'a> {
ty: p.ty.clone(),
is_refcount_pointer: p.is_refcount_pointer,
is_unsafe_pointer: p.is_unsafe_pointer,
derives: Vec::new(),
},
)
})
Expand Down Expand Up @@ -560,6 +562,7 @@ impl<'a> TypeIrBuilder<'a> {
ty: ty.syntax().text().to_string(),
is_refcount_pointer,
is_unsafe_pointer,
derives: Vec::new(),
},
}
}
Expand Down
2 changes: 2 additions & 0 deletions rules/socket/src.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include <sys/types.h>
#include <sys/socket.h>

typedef struct sockaddr t1;

int f1() {
return MSG_NOSIGNAL;
}
Expand Down
4 changes: 4 additions & 0 deletions rules/socket/tgt_unsafe.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
fn t1() -> libc::sockaddr {
unsafe { std::mem::zeroed() }
}

unsafe fn f1() -> i32 {
libc::MSG_NOSIGNAL
}
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/array_of_noncopy_struct.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <cassert>
#include <vector>

struct NonCopy {
std::vector<int> data;
int tag = 0;
};

int main() {
NonCopy arr[3];
arr[0].tag = 7;
arr[1].data.push_back(42);
assert(arr[0].tag == 7);
assert(arr[1].data.size() == 1);
assert(arr[1].data[0] == 42);
assert(arr[2].tag == 0);
assert(arr[2].data.size() == 0);
return 0;
}
46 changes: 46 additions & 0 deletions tests/unit/out/refcount/array_of_noncopy_struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
#[derive(Default)]
pub struct NonCopy {
pub data: Value<Vec<i32>>,
pub tag: Value<i32>,
}
impl Clone for NonCopy {
fn clone(&self) -> Self {
let mut this = Self {
data: Rc::new(RefCell::new((*self.data.borrow()).clone())),
tag: Rc::new(RefCell::new((*self.tag.borrow()))),
};
this
}
}
impl ByteRepr for NonCopy {}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let arr: Value<Box<[NonCopy]>> = Rc::new(RefCell::new(
(0..3)
.map(|_| <NonCopy>::default())
.collect::<Box<[NonCopy]>>(),
));
(*(*arr.borrow())[(0) as usize].tag.borrow_mut()) = 7;
(*(*arr.borrow())[(1) as usize].data.borrow_mut()).push(42);
assert!(((*(*arr.borrow())[(0) as usize].tag.borrow()) == 7));
assert!(((*(*arr.borrow())[(1) as usize].data.borrow()).len() == 1_usize));
assert!(
((((*arr.borrow())[(1) as usize].data.as_pointer() as Ptr<i32>)
.offset(0_usize as isize)
.read())
== 42)
);
assert!(((*(*arr.borrow())[(2) as usize].tag.borrow()) == 0));
assert!(((*(*arr.borrow())[(2) as usize].data.borrow()).len() == 0_usize));
return 0;
}
Loading
Loading