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
58 changes: 14 additions & 44 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,9 +723,8 @@ bool Converter::TypeDerivesDefault(clang::QualType qual_type) {
return false;
}

// Types that need a custom array initializer (e.g., std::array, which is
// translated to Vec)
if (!GetArrayDefaultAsString(qual_type).empty()) {
auto *cxx_record = qual_type->getAsCXXRecordDecl();
if (IsStdDecl(cxx_record, "array") || IsStdDecl(cxx_record, "basic_string")) {
return false;
}

Expand Down Expand Up @@ -3613,22 +3612,20 @@ bool Converter::VisitInitListExpr(clang::InitListExpr *expr) {
}
} else if (qual_type->isRecordType()) {
const auto *record = qual_type->getAsRecordDecl();
if (record->getQualifiedNameAsString() == "std::array") {
if (auto init = clang::dyn_cast<clang::InitListExpr>(expr->getInit(0))) {
StrCat("vec!");
VisitInitListExpr(init);
} else {
StrCat(GetArrayDefaultAsString(qual_type));
}
if (syntactic->getNumInits() == 0) {
StrCat(GetDefaultAsString(qual_type));
SetFreshType(qual_type);
return false;
}

if (syntactic->getNumInits() == 0) {
StrCat(GetDefaultAsString(qual_type));
if (auto str =
GetMappedAsString(expr, expr->getInits(), expr->getNumInits());
!str.empty()) {
StrCat(str);
SetFreshType(qual_type);
return false;
}
assert(IsUserDefinedDecl(record) && "aggregate list without a rule");

StrCat(GetUnsafeTypeAsString(qual_type));
PushBrace brace(*this);
Expand Down Expand Up @@ -4258,11 +4255,11 @@ bool Converter::VisitClassTemplateDecl(clang::ClassTemplateDecl *decl) {

bool Converter::VisitCXXStdInitializerListExpr(
clang::CXXStdInitializerListExpr *expr) {
if (expr->getSubExpr()->getType()->isArrayType()) {
// Arrays become Vec's
StrCat("vec!");
}
Convert(expr->getSubExpr());
auto *backing = expr->getSubExpr();
auto str = GetMappedAsString(expr, &backing, 1);
ENSURE(!str.empty());
StrCat(str);
SetFreshType(expr->getType());
return false;
}

Expand All @@ -4283,33 +4280,6 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
if (clang::isa<clang::IncompleteArrayType>(qual_type)) {
return "[]";
}
if (IsStdDecl(qual_type->getAsCXXRecordDecl(), "array")) {
assert(GetTemplateArgs(qual_type).has_value());
auto template_args = *GetTemplateArgs(qual_type);
assert(template_args.size() == 2);
auto array_size = template_args[1];
unsigned size = 0;
switch (array_size.getKind()) {
case clang::TemplateArgument::Expression: {
auto array_size_expr = array_size.getAsExpr();
assert(array_size_expr && !array_size_expr->isValueDependent());
clang::Expr::EvalResult result;
ENSURE(array_size_expr->EvaluateAsInt(result, ctx_));
size = result.Val.getInt().getZExtValue();
break;
}
case clang::TemplateArgument::Integral: {
size = array_size.getAsIntegral().getZExtValue();
break;
}
default:
assert(0 && "Unsupported array size kind");
break;
}
return std::format(
"std::array::from_fn::<_, {}, _>(|_| Default::default()).to_vec()",
size);
}
return {};
}

Expand Down
24 changes: 12 additions & 12 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1882,18 +1882,6 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) {

if (qual_type->isRecordType()) {
const auto *record = qual_type->getAsRecordDecl();
if (record->getQualifiedNameAsString() == "std::array") {
if (auto init = clang::dyn_cast<clang::InitListExpr>(expr->getInit(0))) {
StrCat("vec!");
PushConversionKind push(*this, ConversionKind::Unboxed);
ConverterRefCount::VisitInitListExpr(init);
} else {
StrCat(GetArrayDefaultAsString(qual_type));
}
computed_expr_type_ = ComputedExprType::FreshValue;
return false;
}

if (syntactic->getNumInits() == 0) {
{
PushConversionKind push(*this, ConversionKind::Unboxed);
Expand All @@ -1903,6 +1891,18 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) {
return false;
}

{
PushConversionKind push(*this, ConversionKind::Unboxed);
if (auto str =
GetMappedAsString(expr, expr->getInits(), expr->getNumInits());
!str.empty()) {
StrCat(str);
computed_expr_type_ = ComputedExprType::FreshValue;
return false;
}
}
assert(IsUserDefinedDecl(record) && "aggregate list without a rule");

if (record->isUnion()) {
auto *field = expr->getInitializedFieldInUnion();
assert(field && expr->getNumInits() == 1);
Expand Down
9 changes: 9 additions & 0 deletions cpp2rust/converter/rules/decls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
trial.failed()) {
return std::nullopt;
}
for (unsigned i = 0; i < deduced.size(); ++i) {
auto nttp =
llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(params->getParam(i));
if (nttp && !nttp->getType()->isDependentType() &&
deduced[i].getKind() == clang::TemplateArgument::Integral) {
deduced[i] = clang::TemplateArgument(
sema.Context, deduced[i].getAsIntegral(), nttp->getType());
}
}
return std::vector<clang::TemplateArgument>(deduced.begin(), deduced.end());
}

Expand Down
51 changes: 45 additions & 6 deletions cpp2rust/converter/rules/expr_matcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
#include <llvm/ADT/SmallBitVector.h>

#include <cassert>
#include <compare>
#include <optional>
#include <string>
#include <variant>
#include <vector>

#include "converter/rules/decls.h"
#include "converter/rules/rule_keys.h"

namespace cpp2rust::AstMatcher {

Expand Down Expand Up @@ -50,18 +52,25 @@ bool hasSameArgTypes(clang::ASTContext &ctx, const clang::Expr *use,
struct MacroUsage {
std::string name;

bool operator==(const MacroUsage &) const = default;
auto operator<=>(const MacroUsage &) const = default;
};

struct RewrittenOperatorUsage {
const clang::Decl *decl;
clang::BinaryOperatorKind op;

bool operator==(const RewrittenOperatorUsage &) const = default;
auto operator<=>(const RewrittenOperatorUsage &) const = default;
};

using ResolvedDecl = std::variant<std::monostate, const clang::Decl *,
MacroUsage, RewrittenOperatorUsage>;
struct AggregateUsage {
RuleKeys::TypeKey type;

auto operator<=>(const AggregateUsage &) const = default;
};

using ResolvedDecl =
std::variant<std::monostate, const clang::Decl *, MacroUsage,
RewrittenOperatorUsage, AggregateUsage>;

ResolvedDecl getResolvedDecl(clang::ASTContext &ctx, const clang::Expr *expr,
bool must_resolve) {
Expand All @@ -85,6 +94,17 @@ ResolvedDecl getResolvedDecl(clang::ASTContext &ctx, const clang::Expr *expr,
if (auto cast = llvm::dyn_cast<clang::ExplicitCastExpr>(expr)) {
return getResolvedDecl(ctx, cast->getSubExpr(), must_resolve);
}
if (auto list = llvm::dyn_cast<clang::InitListExpr>(expr);
list && list->getType()->isRecordType()) {
return AggregateUsage{*RuleKeys::GetTypeKey(list->getType())};
}
if (llvm::isa<clang::CXXStdInitializerListExpr>(expr)) {
return AggregateUsage{*RuleKeys::GetTypeKey(expr->getType())};
}
if (auto construct = llvm::dyn_cast<clang::CXXUnresolvedConstructExpr>(expr);
construct && construct->isListInitialization()) {
return AggregateUsage{*RuleKeys::GetTypeKey(construct->getTypeAsWritten())};
}
if (auto call = llvm::dyn_cast<clang::CallExpr>(expr)) {
if (auto callee = call->getDirectCallee()) {
return callee->getCanonicalDecl();
Expand Down Expand Up @@ -149,6 +169,11 @@ std::vector<clang::Expr *> getOperands(clang::ASTContext &ctx,
operands.insert(operands.end(), call->arg_begin(), call->arg_end());
} else if (auto construct = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
operands.assign(construct->arg_begin(), construct->arg_end());
} else if (auto list = llvm::dyn_cast<clang::InitListExpr>(expr)) {
operands.assign(list->inits().begin(), list->inits().end());
} else if (auto list =
llvm::dyn_cast<clang::CXXStdInitializerListExpr>(expr)) {
operands.push_back(list->getSubExpr()->IgnoreImplicit());
} else if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
auto macro_base =
RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member);
Expand Down Expand Up @@ -233,7 +258,10 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema,
clang::TemplateArgumentListInfo explicit_args(loc, loc);
llvm::SmallBitVector deducible;
sema.MarkDeducedTemplateParameters(rule, deducible);
if (deducible.all()) {
bool aggregate =
llvm::isa<clang::InitListExpr, clang::CXXStdInitializerListExpr>(
RuleDecls::SkipImplicit(use));
if (deducible.all() && !aggregate) {
return explicit_args;
}
auto params = rule->getTemplateParameters();
Expand All @@ -247,7 +275,7 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema,
return explicit_args;
}
auto last = static_cast<unsigned>(deducible.find_last_unset());
for (unsigned i = 0; i <= last; ++i) {
for (unsigned i = 0; i < params->size() && i <= last; ++i) {
auto param = params->getParam(i);
if (param->isParameterPack() || (*deduced)[i].isNull()) {
break;
Expand Down Expand Up @@ -320,6 +348,17 @@ MatchResult matchTemplate(clang::Sema &sema, const clang::Expr *use,
auto explicit_args = getResultArgs(sema, rule, use);
auto specialization =
deduce(sema, rule, explicit_args, getOperands(ctx, use));
if (!specialization) {
return std::nullopt;
}
if (std::holds_alternative<AggregateUsage>(usage_decl)) {
auto returned = RuleDecls::GetReturned(rule->getTemplatedDecl());
if (getResolvedDecl(ctx, returned, /*must_resolve=*/false) != usage_decl) {
return std::nullopt;
}
checkCallable(sema, use, rule->getTemplatedDecl());
return specialization->getTemplateSpecializationArgs()->asArray();
}
auto returned =
substituteSpecializationInRuleTmpl(sema, rule, specialization);
if (!returned ||
Expand Down
7 changes: 7 additions & 0 deletions cpp2rust/converter/rules/rule_keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ std::optional<ExprKey> getExprKey(clang::ASTContext &ctx,
if (llvm::isa<clang::ArraySubscriptExpr>(expr)) {
return getOperatorKey(ctx, clang::OO_Subscript);
}
if (auto list = llvm::dyn_cast<clang::InitListExpr>(expr);
list && list->getType()->isRecordType()) {
return getConstructorKey(getParent(list->getType()));
}
if (llvm::isa<clang::CXXStdInitializerListExpr>(expr)) {
return getConstructorKey(getParent(expr->getType()));
}
return std::nullopt;
}

Expand Down
3 changes: 2 additions & 1 deletion cpp2rust/converter/rules/rule_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <clang/AST/Type.h>
#include <llvm/ADT/Hashing.h>

#include <compare>
#include <optional>
#include <variant>
#include <vector>
Expand All @@ -26,7 +27,7 @@ struct Member {
struct Constructor {
const clang::Decl *parent;

bool operator==(const Constructor &) const = default;
auto operator<=>(const Constructor &) const = default;
};

struct Unqualified {
Expand Down
7 changes: 7 additions & 0 deletions cpp2rust/converter/rules/rules_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,13 @@ std::string ExprKey(clang::ASTContext &ctx, const clang::Expr *expr) {
if (auto construct = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
return FunctionKey(construct->getConstructor());
}
if (llvm::isa<clang::InitListExpr, clang::CXXStdInitializerListExpr>(expr)) {
if (auto record = expr->getType()->getAsRecordDecl();
record && !IsUserDefinedDecl(record)) {
return ConstructorKey(ClassKey(record));
}
return {};
}
if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
if (RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member)) {
return clang::Lexer::getImmediateMacroName(member->getMemberLoc(),
Expand Down
4 changes: 4 additions & 0 deletions rules/array/src.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,7 @@ template <typename T1, std::size_t T2>
std::array<T1, T2> &f7(std::array<T1, T2> &dst, const std::array<T1, T2> &src) {
return dst = src;
}

template <typename T1, std::size_t T2> std::array<T1, T2> f8(T1 (&&a0)[T2]) {
return std::array<T1, T2>{a0};
}
8 changes: 6 additions & 2 deletions rules/array/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

use libcc2rs::*;

fn t1<T1>() -> Vec<T1> {
Default::default()
fn t1<T1: Default + Clone, const T2: usize>() -> Vec<T1> {
std::array::from_fn::<_, T2, _>(|_| <T1>::default()).to_vec()
}

fn t2() -> usize {
Expand Down Expand Up @@ -38,3 +38,7 @@ unsafe fn f6<T1: Clone>(a0: Vec<T1>) -> Vec<T1> {
unsafe fn f7<T1: Clone>(a0: &mut Vec<T1>, a1: Vec<T1>) {
*a0 = a1.clone()
}

unsafe fn f8<T1, const T2: usize>(a0: [T1; T2]) -> Vec<T1> {
Vec::from(a0)
}
6 changes: 6 additions & 0 deletions rules/initializer_list/src.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2022-present INESC-ID.
// Distributed under the MIT license that can be found in the LICENSE file.

#include <cstddef>
#include <initializer_list>

template <typename T1> using t1 = std::initializer_list<T1>;
Expand All @@ -12,3 +13,8 @@ typename std::initializer_list<T1>::size_type
f1(const std::initializer_list<T1> &o) {
return o.size();
}

template <typename T1, std::size_t T2>
std::initializer_list<T1> f2(const T1 (&a0)[T2]) {
return std::initializer_list<T1>{a0};
}
4 changes: 4 additions & 0 deletions rules/initializer_list/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ fn t2() -> usize {
unsafe fn f1<T1>(a0: Vec<T1>) -> usize {
a0.len()
}

unsafe fn f2<T1, const T2: usize>(a0: [T1; T2]) -> Vec<T1> {
Vec::from(a0)
}
2 changes: 1 addition & 1 deletion tests/ub/out/refcount/dangling-prvalue-as-lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let v: Value<Vec<i32>> = Rc::new(RefCell::new(vec![1, 2]));
let v: Value<Vec<i32>> = Rc::new(RefCell::new(Vec::from([1, 2])));
let b: Ptr<i32> =
({ foo_0(RandomAccessIterator::Vec((v.as_pointer() as Ptr<i32>)).iter_deref()) });
(*v.borrow_mut()).clear();
Expand Down
5 changes: 4 additions & 1 deletion tests/ub/out/refcount/row_ptr_outlives_vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
pub fn second_row_0() -> Ptr<i32> {
let rows: Value<Vec<Vec<i32>>> = Rc::new(RefCell::new(vec![vec![1, 2, 3], vec![4, 5, 6]]));
let rows: Value<Vec<Vec<i32>>> = Rc::new(RefCell::new(Vec::from([
Vec::from([1, 2, 3]),
Vec::from([4, 5, 6]),
])));
return ((rows.as_pointer() as Ptr<Vec<i32>>)
.offset(1_usize)
.as_pointer() as Ptr<i32>);
Expand Down
2 changes: 1 addition & 1 deletion tests/ub/out/unsafe/dangling-prvalue-as-lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub fn main() {
}
}
unsafe fn main_0() -> i32 {
let mut v: Vec<i32> = vec![1, 2];
let mut v: Vec<i32> = Vec::from([1, 2]);
let b: *const i32 =
(unsafe { foo_0(&(*UnsafeRandomAccessIterator::Vec(v.as_mut_ptr()).iter_deref())) });
v.clear();
Expand Down
2 changes: 1 addition & 1 deletion tests/ub/out/unsafe/row_ptr_outlives_vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::io::{Read, Seek, Write};
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
use std::rc::Rc;
pub unsafe fn second_row_0() -> *mut i32 {
let mut rows: Vec<Vec<i32>> = vec![vec![1, 2, 3], vec![4, 5, 6]];
let mut rows: Vec<Vec<i32>> = Vec::from([Vec::from([1, 2, 3]), Vec::from([4, 5, 6])]);
return rows[(1_usize)].as_mut_ptr();
}
pub fn main() {
Expand Down
Loading
Loading