Skip to content

Commit 73d08a8

Browse files
authored
Translate access of static member through object (#430)
```cpp struct S { static int static_member = 0; } assert(S{}.static_member == 0); assert(S::static_member == 0); ``` Both are valid C++. Same for static methods.
1 parent 96eae96 commit 73d08a8

7 files changed

Lines changed: 119 additions & 38 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2967,16 +2967,16 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) {
29672967
return false;
29682968
}
29692969

2970-
std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) {
2970+
std::string Converter::ConvertDeclRef(clang::Expr *expr,
2971+
clang::ValueDecl *decl) {
29712972
if (isAddrOf()) {
29722973
clang::Expr *addrof_op = ToAddrOf(ctx_, expr);
29732974
if (auto str = GetMappedAsString(addrof_op); !str.empty()) {
29742975
return str;
29752976
}
29762977
}
29772978

2978-
auto *decl = expr->getDecl();
2979-
if (ShouldReplaceWithMappedBody(expr)) {
2979+
if (ShouldReplaceWithMappedBody(decl)) {
29802980
if (auto str = GetMappedAsString(expr); !str.empty()) {
29812981
return str;
29822982
}
@@ -2999,7 +2999,8 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) {
29992999
return name;
30003000
}
30013001

3002-
if (IsGlobalVar(expr)) {
3002+
if (auto *var = clang::dyn_cast<clang::VarDecl>(decl);
3003+
var && IsGlobalVar(var)) {
30033004
if (LazyStaticInit()) {
30043005
return std::format("(*std::cell::LazyCell::force_mut(&mut *&raw mut {}))",
30053006
GetNamedDeclAsString(decl));
@@ -3011,24 +3012,28 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) {
30113012
}
30123013

30133014
bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
3014-
auto str = ConvertDeclRefExpr(expr);
3015-
auto decl = expr->getDecl();
3015+
ConvertDeclRefValue(expr, expr->getDecl());
3016+
return false;
3017+
}
3018+
3019+
void Converter::ConvertDeclRefValue(clang::Expr *expr, clang::ValueDecl *decl) {
3020+
auto str = ConvertDeclRef(expr, decl);
30163021

30173022
if (decl->getType()->getAs<clang::ReferenceType>() && !isAddrOf() &&
30183023
!map_iter_decls_.contains(clang::dyn_cast<clang::VarDecl>(decl))) {
30193024
EmitDeref(std::move(str), decl->getType().getNonReferenceType());
30203025
SetValueFreshness(expr->getType());
3021-
return false;
3026+
return;
30223027
}
30233028

30243029
if (auto *fn_decl = clang::dyn_cast<clang::FunctionDecl>(decl)) {
30253030
if (isAddrOf()) {
30263031
ConvertFunctionToFunctionPointer(fn_decl);
3027-
return false;
3032+
return;
30283033
}
30293034
StrCat(str);
30303035
SetFreshType(expr->getType());
3031-
return false;
3036+
return;
30323037
}
30333038

30343039
if (auto var_decl = clang::dyn_cast<clang::VarDecl>(decl)) {
@@ -3039,7 +3044,7 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
30393044
PushParen paren(*this);
30403045
VisitLambdaExpr(lambda);
30413046
computed_expr_type_ = ComputedExprType::FreshValue;
3042-
return false;
3047+
return;
30433048
}
30443049
}
30453050
}
@@ -3049,16 +3054,15 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
30493054
StrCat(token::kRef, decl->getType().isConstQualified() ? "" : keyword_mut_,
30503055
str);
30513056
computed_expr_type_ = ComputedExprType::FreshPointer;
3052-
return false;
3057+
return;
30533058
}
30543059

30553060
StrCat(str);
30563061
if (clang::isa<clang::EnumConstantDecl>(decl)) {
30573062
computed_expr_type_ = ComputedExprType::FreshValue;
3058-
return false;
3063+
return;
30593064
}
30603065
SetValueFreshness(expr->getType());
3061-
return false;
30623066
}
30633067

30643068
bool Converter::VisitParenExpr(clang::ParenExpr *expr) {
@@ -3142,6 +3146,10 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) {
31423146

31433147
bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
31443148
auto *member = expr->getMemberDecl();
3149+
if (!member->isCXXInstanceMember()) {
3150+
ConvertDeclRefValue(expr, member);
3151+
return false;
3152+
}
31453153
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(member);
31463154
method && IsMethodOnPtr(method) && !Mapper::Contains(expr)) {
31473155
SetUFCSReceiver(expr->getBase(), expr->isArrow(), method);
@@ -5099,8 +5107,9 @@ bool Converter::isCallee() const {
50995107
return !curr_expr_kind_.empty() && curr_expr_kind_.back() == ExprKind::Callee;
51005108
}
51015109

5102-
bool Converter::ShouldReplaceWithMappedBody(clang::DeclRefExpr *expr) const {
5103-
if (clang::isa<clang::FunctionDecl>(expr->getDecl()) && isAddrOf()) {
5110+
bool Converter::ShouldReplaceWithMappedBody(
5111+
const clang::ValueDecl *decl) const {
5112+
if (clang::isa<clang::FunctionDecl>(decl) && isAddrOf()) {
51045113
return false;
51055114
}
51065115
return true;

‎cpp2rust/converter/converter.h‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,10 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
407407
virtual bool VisitConditionalOperator(clang::ConditionalOperator *expr);
408408

409409
virtual bool VisitDeclRefExpr(clang::DeclRefExpr *expr);
410-
std::string ConvertDeclRefExpr(clang::DeclRefExpr *expr);
410+
411+
virtual void ConvertDeclRefValue(clang::Expr *expr, clang::ValueDecl *decl);
412+
413+
std::string ConvertDeclRef(clang::Expr *expr, clang::ValueDecl *decl);
411414

412415
virtual bool VisitParenExpr(clang::ParenExpr *expr);
413416

@@ -730,7 +733,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
730733

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

733-
bool ShouldReplaceWithMappedBody(clang::DeclRefExpr *expr) const;
736+
bool ShouldReplaceWithMappedBody(const clang::ValueDecl *decl) const;
734737

735738
std::string *rs_code_;
736739
clang::ASTContext &ctx_;

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -818,26 +818,26 @@ bool ConverterRefCount::VisitConditionalOperator(
818818
return false;
819819
}
820820

821-
bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
821+
void ConverterRefCount::ConvertDeclRefValue(clang::Expr *expr,
822+
clang::ValueDecl *decl) {
822823
if (isAddrOf()) {
823824
clang::Expr *addrof_op = ToAddrOf(ctx_, expr);
824825
if (auto str = GetMappedAsString(addrof_op); !str.empty()) {
825826
StrCat(str);
826827
SetFreshType(expr->getType());
827-
return false;
828+
return;
828829
}
829830
}
830831

831-
if (ShouldReplaceWithMappedBody(expr)) {
832+
if (ShouldReplaceWithMappedBody(decl)) {
832833
if (auto str = GetMappedAsString(expr); !str.empty()) {
833834
StrCat(str);
834835
SetFreshType(expr->getType());
835-
return false;
836+
return;
836837
}
837838
}
838839

839-
auto str = ConvertDeclRefExpr(expr);
840-
auto decl = expr->getDecl();
840+
auto str = ConvertDeclRef(expr, decl);
841841

842842
if (auto fn_decl = clang::dyn_cast<clang::FunctionDecl>(decl)) {
843843
if (isAddrOf()) {
@@ -846,18 +846,19 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
846846
StrCat(str);
847847
SetFreshType(expr->getType());
848848
}
849-
return false;
849+
return;
850850
}
851851

852852
if (clang::isa<clang::EnumConstantDecl>(decl)) {
853853
StrCat(str);
854854
computed_expr_type_ = ComputedExprType::FreshValue;
855-
return false;
855+
return;
856856
}
857857

858858
const auto decl_t = decl->getType();
859859
bool is_global_value = false, is_global_ptr = false;
860-
if (IsGlobalVar(expr)) {
860+
if (auto *var = clang::dyn_cast<clang::VarDecl>(decl);
861+
var && IsGlobalVar(var)) {
861862
if (decl_t->isReferenceType()) {
862863
str += ".with(Ptr::clone)";
863864
is_global_ptr = true;
@@ -870,15 +871,15 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
870871
if (map_iter_decls_.contains(clang::dyn_cast<clang::VarDecl>(decl))) {
871872
StrCat(str);
872873
SetValueFreshness(expr->getType());
873-
return false;
874+
return;
874875
}
875876

876877
if (auto pointee = ref->getPointeeType();
877878
isObject() && WantsElementPtr() && IsBoxedType(pointee)) {
878879
StrCat(std::format("Ptr::<{}>::decay(&({}))", ToString(pointee),
879880
std::move(str)));
880881
computed_expr_type_ = ComputedExprType::FreshPointer;
881-
return false;
882+
return;
882883
}
883884

884885
// references are not boxed
@@ -891,13 +892,13 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
891892
} else {
892893
if (isLValue()) {
893894
pending_deref_.set(str, /*fresh=*/false);
894-
return false;
895+
return;
895896
}
896897
StrCat(DerefPtrExpr(str, ref->getPointeeType()));
897898
}
898899
SetValueFreshness(expr->getType());
899900
}
900-
return false;
901+
return;
901902
}
902903

903904
if (isAddrOf()) {
@@ -909,7 +910,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
909910
StrCat(str, ".as_pointer()");
910911
}
911912
computed_expr_type_ = ComputedExprType::FreshPointer;
912-
return false;
913+
return;
913914
}
914915

915916
bool fresh = false;
@@ -934,18 +935,17 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
934935
StrCat(std::format("(*{}.borrow_mut())", std::move(str)));
935936
}
936937

937-
if (auto *decl = clang::dyn_cast<clang::VarDecl>(expr->getDecl())) {
938-
if (decl->getType()->isPointerType()) {
938+
if (auto *var = clang::dyn_cast<clang::VarDecl>(decl)) {
939+
if (var->getType()->isPointerType()) {
939940
computed_expr_type_ = ComputedExprType::Pointer;
940-
return false;
941+
return;
941942
}
942943
}
943944
if (fresh) {
944945
SetFreshType(expr->getType());
945946
} else {
946947
SetValueFreshness(expr->getType());
947948
}
948-
return false;
949949
}
950950

951951
static std::vector<const char *> printf2fmt(std::string &format) {
@@ -1727,6 +1727,10 @@ void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) {
17271727

17281728
bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
17291729
auto *member = expr->getMemberDecl();
1730+
if (!member->isCXXInstanceMember()) {
1731+
ConvertDeclRefValue(expr, member);
1732+
return false;
1733+
}
17301734
bool known = Mapper::Contains(expr);
17311735

17321736
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(member);
@@ -2495,7 +2499,8 @@ clang::DeclRefExpr *ConverterRefCount::GetGlobalArrayRValue(clang::Expr *base) {
24952499
auto *ref = clang::dyn_cast<clang::DeclRefExpr>(base->IgnoreImplicit());
24962500
if (!isRValue() || !ref || !IsGlobalVar(ref) ||
24972501
ref->getDecl()->getType()->isReferenceType() ||
2498-
(ShouldReplaceWithMappedBody(ref) && !GetMappedAsString(ref).empty())) {
2502+
(ShouldReplaceWithMappedBody(ref->getDecl()) &&
2503+
!GetMappedAsString(ref).empty())) {
24992504
return nullptr;
25002505
}
25012506
auto *arr_ty = ctx_.getAsArrayType(ref->getType());
@@ -2551,7 +2556,7 @@ void ConverterRefCount::ConvertArraySubscript(clang::Expr *base,
25512556
// The index is evaluated first, as it may itself access the global.
25522557
StrCat(std::format(
25532558
"({{ let __idx = ({}) as usize; {}.with(|rc| rc.borrow()[__idx]{}) }})",
2554-
ConvertRValue(idx), ConvertDeclRefExpr(global),
2559+
ConvertRValue(idx), ConvertDeclRef(global, global->getDecl()),
25552560
TypeIsCopyable(type) ? "" : ".clone()"));
25562561
SetFreshType(type);
25572562
} else {

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class ConverterRefCount final : public Converter {
9797

9898
bool ConvertLambdaVarDecl(clang::VarDecl *decl) override;
9999

100-
bool VisitDeclRefExpr(clang::DeclRefExpr *expr) override;
100+
void ConvertDeclRefValue(clang::Expr *expr, clang::ValueDecl *decl) override;
101101

102102
bool ConvertIncAndDec(clang::UnaryOperator *expr) override;
103103

‎tests/unit/out/refcount/static_var_in_class.rs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,18 @@ pub struct C {}
1414
thread_local!(
1515
pub static inner_const_1: Value<i32> = Rc::new(RefCell::new(2));
1616
);
17+
pub type anon_3 = u32;
18+
pub const anon_3_kValue: anon_3 = 3;
1719
#[derive(Clone, ByteRepr, Default)]
1820
pub struct S {}
21+
impl S {
22+
pub fn f() -> i32 {
23+
return counter_2.with(|rc| *rc.borrow());
24+
}
25+
}
26+
thread_local!(
27+
pub static counter_2: Value<i32> = Rc::new(RefCell::new(10));
28+
);
1929
pub fn main() {
2030
__cpp2rust_init_globals();
2131
std::process::exit(main_0());
@@ -24,6 +34,19 @@ fn main_0() -> i32 {
2434
let c: Value<C> = Rc::new(RefCell::new(<C>::default()));
2535
assert!((({ CImpl::get(&c.as_pointer(),) }) == 1));
2636
assert!((inner_const_1.with(|rc| *rc.borrow()) == 2));
37+
let s: Value<S> = Rc::new(RefCell::new(<S>::default()));
38+
let p: Value<Ptr<S>> = Rc::new(RefCell::new((s.as_pointer())));
39+
assert!((inner_const_1.with(|rc| *rc.borrow()) == 2));
40+
assert!((inner_const_1.with(|rc| *rc.borrow()) == 2));
41+
assert!(((anon_3_kValue as i32) == 3));
42+
assert!(((anon_3_kValue as i32) == 3));
43+
(*counter_2.with(Value::clone).borrow_mut()) = 20;
44+
assert!((counter_2.with(|rc| *rc.borrow()) == 20));
45+
(*counter_2.with(Value::clone).borrow_mut()) += 5;
46+
assert!((counter_2.with(|rc| *rc.borrow()) == 25));
47+
assert!((counter_2.with(|rc| *rc.borrow()) == 25));
48+
assert!((({ S::f() }) == 25));
49+
assert!((({ S::f() }) == 25));
2750
return 0;
2851
}
2952
pub trait CImpl {
@@ -37,4 +60,5 @@ impl CImpl for Ptr<C> {
3760
pub fn __cpp2rust_init_globals() {
3861
let _ = inner_const_0.with(|_| ());
3962
let _ = inner_const_1.with(|_| ());
63+
let _ = counter_2.with(|_| ());
4064
}

‎tests/unit/out/unsafe/static_var_in_class.rs‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,17 @@ impl C {
1616
}
1717
}
1818
pub static mut inner_const_1: std::cell::LazyCell<i32> = std::cell::LazyCell::new(|| unsafe { 2 });
19+
pub type anon_3 = u32;
20+
pub const anon_3_kValue: anon_3 = 3;
1921
#[repr(C)]
2022
#[derive(Copy, Clone, Default)]
2123
pub struct S {}
24+
impl S {
25+
pub unsafe fn f() -> i32 {
26+
return (*std::cell::LazyCell::force_mut(&mut *&raw mut counter_2));
27+
}
28+
}
29+
pub static mut counter_2: std::cell::LazyCell<i32> = std::cell::LazyCell::new(|| unsafe { 10 });
2230
pub fn main() {
2331
unsafe {
2432
__cpp2rust_init_globals();
@@ -29,9 +37,23 @@ unsafe fn main_0() -> i32 {
2937
let mut c: C = <C>::default();
3038
assert!(((unsafe { C::get(&mut c,) }) == (1)));
3139
assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut inner_const_1)) == (2)));
40+
let mut s: S = <S>::default();
41+
let mut p: *mut S = (&mut s as *mut S);
42+
assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut inner_const_1)) == (2)));
43+
assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut inner_const_1)) == (2)));
44+
assert!(((anon_3_kValue as i32) == (3)));
45+
assert!(((anon_3_kValue as i32) == (3)));
46+
(*std::cell::LazyCell::force_mut(&mut *&raw mut counter_2)) = 20;
47+
assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut counter_2)) == (20)));
48+
(*std::cell::LazyCell::force_mut(&mut *&raw mut counter_2)) += 5;
49+
assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut counter_2)) == (25)));
50+
assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut counter_2)) == (25)));
51+
assert!(((unsafe { S::f() }) == (25)));
52+
assert!(((unsafe { S::f() }) == (25)));
3253
return 0;
3354
}
3455
pub unsafe fn __cpp2rust_init_globals() {
3556
std::cell::LazyCell::force(&*&raw const inner_const_0);
3657
std::cell::LazyCell::force(&*&raw const inner_const_1);
58+
std::cell::LazyCell::force(&*&raw const counter_2);
3759
}

0 commit comments

Comments
 (0)