diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index e9ecb5104..df5dfb1b1 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2434,8 +2434,8 @@ void Converter::ConvertIntegralToBooleanCast(clang::ImplicitCastExpr *expr) { bool Converter::IsCastRedundantInRust(clang::Expr *expr, clang::QualType target_type) { auto target = GetUnsafeTypeAsString(target_type); - if (const auto *rule = RuleRegistry::GetExprRule(ctx_, expr)) { - return rule->return_type.type == target; + if (RuleRegistry::GetExprRule(ctx_, expr)) { + return Trim(Mapper::GetReturnType(*this, expr)) == target; } return GetUnsafeTypeAsString(expr->getType()) == target; } diff --git a/cpp2rust/converter/rules/expr_matcher.cpp b/cpp2rust/converter/rules/expr_matcher.cpp index 603f99c24..932be0415 100644 --- a/cpp2rust/converter/rules/expr_matcher.cpp +++ b/cpp2rust/converter/rules/expr_matcher.cpp @@ -342,6 +342,28 @@ MatchResult matchFunction(clang::Sema &sema, const clang::Expr *use, return llvm::ArrayRef(); } +bool constructsReturnType(const clang::Expr *returned, clang::QualType ret, + const ResolvedDecl &usage_decl) { + auto list = + llvm::dyn_cast(RuleDecls::SkipImplicit(returned)); + if (!list || list->getType()->isRecordType()) { + return false; + } + auto record = ret->getAsCXXRecordDecl(); + if (!record) { + return false; + } + if (auto decl = std::get_if(&usage_decl)) { + auto ctor = llvm::dyn_cast(*decl); + return ctor && + ctor->getParent()->getCanonicalDecl() == record->getCanonicalDecl(); + } + if (auto aggregate = std::get_if(&usage_decl)) { + return RuleKeys::GetTypeKey(ret) == aggregate->type; + } + return false; +} + MatchResult matchTemplate(clang::Sema &sema, const clang::Expr *use, const ResolvedDecl &usage_decl, clang::FunctionTemplateDecl *rule) { @@ -355,7 +377,9 @@ MatchResult matchTemplate(clang::Sema &sema, const clang::Expr *use, } if (std::holds_alternative(usage_decl)) { auto returned = RuleDecls::GetReturned(rule->getTemplatedDecl()); - if (getResolvedDecl(ctx, returned, /*must_resolve=*/false) != usage_decl) { + if (getResolvedDecl(ctx, returned, /*must_resolve=*/false) != usage_decl && + !constructsReturnType(returned, specialization->getReturnType(), + usage_decl)) { return std::nullopt; } checkCallable(sema, use, rule->getTemplatedDecl()); @@ -363,8 +387,15 @@ MatchResult matchTemplate(clang::Sema &sema, const clang::Expr *use, } auto returned = substituteSpecializationInRuleTmpl(sema, rule, specialization); - if (!returned || - getResolvedDecl(ctx, returned, /*must_resolve=*/true) != usage_decl) { + if (!returned) { + return std::nullopt; + } + if (constructsReturnType(returned, specialization->getReturnType(), + usage_decl)) { + checkCallable(sema, use, rule->getTemplatedDecl()); + return specialization->getTemplateSpecializationArgs()->asArray(); + } + if (getResolvedDecl(ctx, returned, /*must_resolve=*/true) != usage_decl) { return std::nullopt; } checkCallable(sema, use, rule->getTemplatedDecl()); diff --git a/cpp2rust/converter/rules/registry.cpp b/cpp2rust/converter/rules/registry.cpp index d186647e5..40bfffd7a 100644 --- a/cpp2rust/converter/rules/registry.cpp +++ b/cpp2rust/converter/rules/registry.cpp @@ -410,7 +410,10 @@ Matcher::Match Search(clang::ASTContext &ctx, } auto bindings = getBindings(match.rule_decl->decl, match.match.args); if (auto generic = match.rule_decl->rule.generic) { - return Search(ctx, bindings.at(generic - 1).getAsType()); + if (auto bound = Search(ctx, bindings.at(generic - 1).getAsType()); + bound.first) { + return bound; + } } return {&match.rule_decl->rule, std::move(bindings)}; } diff --git a/cpp2rust/converter/rules/rule_keys.cpp b/cpp2rust/converter/rules/rule_keys.cpp index bac8fc8d3..72fee28a1 100644 --- a/cpp2rust/converter/rules/rule_keys.cpp +++ b/cpp2rust/converter/rules/rule_keys.cpp @@ -32,7 +32,6 @@ const clang::Decl *getParent(clang::QualType type) { spec->getTemplateName().getAsTemplateDecl())) { return tmpl->getCanonicalDecl(); } - return nullptr; } auto record = type->getAsCXXRecordDecl(); if (!record) { @@ -137,6 +136,10 @@ std::optional GetExprKey(clang::ASTContext &ctx, rewritten->getOperator())); } if (auto cast = llvm::dyn_cast(expr)) { + if (auto key = getConstructorKey(getParent(cast->getSubExpr()->getType())); + key && cast->isTypeDependent()) { + return key; + } return GetExprKey(ctx, cast->getSubExpr()); } if (auto construct = llvm::dyn_cast(expr)) { @@ -147,6 +150,9 @@ std::optional GetExprKey(clang::ASTContext &ctx, return getConstructorKey(getParent(construct->getTypeAsWritten())); } if (auto call = llvm::dyn_cast(expr)) { + if (llvm::isa(call)) { + return GetExprKey(ctx, call->getCallee()); + } if (auto callee = call->getDirectCallee()) { return GetDeclKey(callee); } @@ -172,7 +178,9 @@ std::optional GetExprKey(clang::ASTContext &ctx, sm, ctx.getLangOpts()); return Unqualified{clang::DeclarationName(&ctx.Idents.get(macro))}; } - return GetDeclKey(member->getMemberDecl()); + return getMemberKey( + getParent(member->getBase()->IgnoreImpCasts()->getType()), + member->getMemberDecl()->getDeclName()); } if (auto ref = llvm::dyn_cast(expr)) { return GetDeclKey(ref->getDecl()); @@ -226,6 +234,9 @@ std::vector GetExprKeys(clang::ASTContext &ctx, return keys; } auto key = GetExprKey(ctx, returned); + if (!key && llvm::isa(returned)) { + key = getConstructorKey(getParent(rule->getAsFunction()->getReturnType())); + } assert(key && "expression rule has no key"); return {*key}; } diff --git a/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp b/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp index 3ccf98225..7cf1b7b6c 100644 --- a/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp +++ b/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp @@ -274,6 +274,11 @@ void IndexRuleFile(clang::ASTContext &ctx, const std::string &dir_name, if (key.empty()) { key = ClassOfParameters(decl); } + if (auto returned = RuleExpr(decl); + key.empty() && returned && + llvm::isa(returned->IgnoreImplicit())) { + key = ClassOf(decl->getAsFunction()->getReturnType()); + } bool any_class = key.empty() && llvm::isa(decl); if (any_class) { key = RulesLoader::kAnyClassKey; diff --git a/rules/atomic/src.cpp b/rules/atomic/src.cpp new file mode 100644 index 000000000..bb292c03f --- /dev/null +++ b/rules/atomic/src.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +template using t1 = std::atomic; + +template std::atomic f1() { return {}; } + +template T1 f2(const std::atomic &a0) { + return static_cast(a0); +} diff --git a/rules/atomic/tgt_unsafe.rs b/rules/atomic/tgt_unsafe.rs new file mode 100644 index 000000000..9ea5044d5 --- /dev/null +++ b/rules/atomic/tgt_unsafe.rs @@ -0,0 +1,16 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +// TODO: use proper atomic translation + +fn t1() -> T1 { + T1::default() +} + +unsafe fn f1() -> T1 { + T1::default() +} + +unsafe fn f2(a0: T1) -> T1 { + a0 +} diff --git a/tests/unit/atomic.cpp b/tests/unit/atomic.cpp new file mode 100644 index 000000000..8e0c58777 --- /dev/null +++ b/tests/unit/atomic.cpp @@ -0,0 +1,13 @@ +#include +#include + +struct Counter { + int n; +}; + +int main() { + std::atomic a{}; + Counter v = a; + assert(v.n == 0); + return 0; +} diff --git a/tests/unit/out/refcount/atomic.rs b/tests/unit/out/refcount/atomic.rs new file mode 100644 index 000000000..d5576c337 --- /dev/null +++ b/tests/unit/out/refcount/atomic.rs @@ -0,0 +1,25 @@ +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(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(4)] +pub struct Counter { + #[offset(0)] + pub n: i32, +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(Counter::default())); + let mut v: Counter = (*a.borrow()).clone(); + assert!((v.n == 0)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/atomic.rs b/tests/unit/out/unsafe/atomic.rs new file mode 100644 index 000000000..ce9dbc817 --- /dev/null +++ b/tests/unit/out/unsafe/atomic.rs @@ -0,0 +1,26 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +pub struct Counter { + pub n: i32, +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: Counter = Counter::default(); + let mut v: Counter = a; + assert!(((v.n) == (0))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {}