Skip to content

Commit 42a07be

Browse files
committed
Translate access to flexible array member (#165)
Changed the access pattern of flexible arrays from ```rs let bytes: [u8; 1] = ...; bytes[10] = ... ``` to ```rs let bytes: [u8; 1] = ...; *bytes.as_mut_ptr().add(10) = ...; ``` The original access panics because the bounds are violated, i.e. accessing the 10th element in an array declared with 1 element. The new access does not panic, it preserves the C/C++ behavior.
1 parent a785482 commit 42a07be

1 file changed

Lines changed: 48 additions & 0 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <clang/AST/APValue.h>
77
#include <clang/AST/ParentMapContext.h>
8+
#include <clang/Basic/LangOptions.h>
89
#include <clang/Basic/SourceManager.h>
910
#include <llvm/ADT/DenseMap.h>
1011
#include <llvm/Support/ConvertUTF.h>
@@ -3532,8 +3533,42 @@ void Converter::ConvertPointerOffset(clang::Expr *base, clang::Expr *idx,
35323533
computed_expr_type_ = ComputedExprType::FreshPointer;
35333534
}
35343535

3536+
static bool IsFlexibleArrayMemberAccess(clang::ASTContext &ctx,
3537+
clang::Expr *array) {
3538+
return array->isFlexibleArrayMemberLike(
3539+
ctx, clang::LangOptions::StrictFlexArraysLevelKind::OneZeroOrIncomplete,
3540+
/*IgnoreTemplateOrMacroSubstitution=*/true);
3541+
}
3542+
3543+
void Converter::EmitFlexibleArrayElementPtr(clang::Expr *array,
3544+
clang::Expr *idx, bool is_mut) {
3545+
{
3546+
PushExplicitAutoref no_autoref(*this, std::nullopt);
3547+
Convert(array);
3548+
}
3549+
StrCat(is_mut ? ".as_mut_ptr()" : ".as_ptr()", ".add");
3550+
{
3551+
PushParen call(*this);
3552+
{
3553+
PushParen paren(*this);
3554+
Convert(idx);
3555+
}
3556+
StrCat(keyword::kAs, "usize");
3557+
}
3558+
}
3559+
35353560
void Converter::ConvertArraySubscript(clang::Expr *base, clang::Expr *idx,
35363561
clang::QualType type) {
3562+
if (auto inner = base->IgnoreImplicit()) {
3563+
if (inner->getType()->isArrayType() &&
3564+
IsFlexibleArrayMemberAccess(ctx_, inner)) {
3565+
PushParen outer(*this);
3566+
StrCat(token::kStar);
3567+
EmitFlexibleArrayElementPtr(inner, idx,
3568+
!inner->getType().isConstQualified());
3569+
return;
3570+
}
3571+
}
35373572
if (IsUniquePtr(base->getType())) {
35383573
PushExplicitAutoref no_autoref(*this, std::nullopt);
35393574
Convert(base->IgnoreImplicit());
@@ -3836,6 +3871,19 @@ void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op,
38363871

38373872
void Converter::ConvertAddrOf(clang::Expr *expr, clang::QualType pointer_type) {
38383873
assert(pointer_type->isPointerType());
3874+
if (auto ase =
3875+
clang::dyn_cast<clang::ArraySubscriptExpr>(expr->IgnoreParens())) {
3876+
auto base = ase->getBase();
3877+
auto inner = base->IgnoreImplicit();
3878+
if (base->IgnoreCasts()->getType()->isArrayType() &&
3879+
IsFlexibleArrayMemberAccess(ctx_, inner)) {
3880+
EmitFlexibleArrayElementPtr(
3881+
inner, ase->getIdx(),
3882+
!pointer_type->getPointeeType().isConstQualified());
3883+
computed_expr_type_ = ComputedExprType::FreshPointer;
3884+
return;
3885+
}
3886+
}
38393887
if (IsReferenceType(expr) || pointer_type->isFunctionPointerType()) {
38403888
PushExprKind push(*this, ExprKind::AddrOf);
38413889
Convert(expr);

0 commit comments

Comments
 (0)