-
Notifications
You must be signed in to change notification settings - Fork 5
Fix wrong expected output for default_in_statics.cpp/unsafe test and shared reference to mutable static errors #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c19d2b5
c61fdd4
0e8a426
be00acf
167627e
05258a5
413c515
7e9aea5
55c480d
f9eb263
6df6b81
ac5ef58
fbf98c5
c3e4b41
d9f2940
b3def05
8f677b7
2e76b75
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1986,15 +1986,25 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { | |
| StrCat(keyword::kAs, dest_pointee_const ? "*const u8" : "*mut u8"); | ||
| break; | ||
| } | ||
| Convert(sub_expr); | ||
| if (clang::isa<clang::StringLiteral>(sub_expr) || | ||
| clang::isa<clang::PredefinedExpr>(sub_expr)) { | ||
| StrCat(".as_ptr()"); | ||
| if (!dest_pointee_const) { | ||
| StrCat(".cast_mut()"); | ||
| if (IsGlobalVar(sub_expr)) { | ||
| { | ||
| PushParen paren(*this); | ||
| StrCat("&raw", dest_pointee_const ? keyword::kConst : keyword_mut_); | ||
| Convert(sub_expr); | ||
| } | ||
| StrCat(".cast::<", | ||
| GetUnsafeTypeAsString(expr->getType()->getPointeeType()), ">()"); | ||
| } else { | ||
| StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()"); | ||
| Convert(sub_expr); | ||
| if (clang::isa<clang::StringLiteral>(sub_expr) || | ||
| clang::isa<clang::PredefinedExpr>(sub_expr)) { | ||
| StrCat(".as_ptr()"); | ||
| if (!dest_pointee_const) { | ||
| StrCat(".cast_mut()"); | ||
| } | ||
| } else { | ||
| StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()"); | ||
| } | ||
| } | ||
| break; | ||
| } | ||
|
|
@@ -2322,31 +2332,40 @@ bool Converter::IsReferenceType(const clang::Expr *expr) const { | |
| bool Converter::ConvertIncAndDec(clang::UnaryOperator *expr) { | ||
| auto opcode = expr->getOpcode(); | ||
| auto *sub_expr = expr->getSubExpr(); | ||
| auto emit_target = [&]() { | ||
| if (IsGlobalVar(sub_expr)) { | ||
| StrCat("(*(&raw", keyword_mut_); | ||
| Convert(sub_expr); | ||
| StrCat("))"); | ||
| } else { | ||
| Convert(sub_expr); | ||
| } | ||
| }; | ||
| switch (opcode) { | ||
| case clang::UO_PostInc: { | ||
| PushExprKind push(*this, ExprKind::RValue); | ||
| Convert(sub_expr); | ||
| emit_target(); | ||
| StrCat(".postfix_inc()"); | ||
| SetFresh(); | ||
| return true; | ||
| } | ||
| case clang::UO_PostDec: { | ||
| PushExprKind push(*this, ExprKind::RValue); | ||
| Convert(sub_expr); | ||
| emit_target(); | ||
| StrCat(".postfix_dec()"); | ||
| SetFresh(); | ||
| return true; | ||
| } | ||
| case clang::UO_PreInc: { | ||
| PushExprKind push(*this, ExprKind::RValue); | ||
| Convert(sub_expr); | ||
| emit_target(); | ||
| StrCat(".prefix_inc()"); | ||
| SetFresh(); | ||
| return true; | ||
| } | ||
| case clang::UO_PreDec: { | ||
| PushExprKind push(*this, ExprKind::RValue); | ||
| Convert(sub_expr); | ||
| emit_target(); | ||
| StrCat(".prefix_dec()"); | ||
| SetFresh(); | ||
| return true; | ||
|
|
@@ -2539,8 +2558,15 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { | |
| } | ||
|
|
||
| if (!decl->getType()->getAs<clang::ReferenceType>() && isAddrOf()) { | ||
| StrCat(token::kRef, decl->getType().isConstQualified() ? "" : keyword_mut_, | ||
| str); | ||
| if (IsGlobalVar(expr)) { | ||
| StrCat("&raw", | ||
| decl->getType().isConstQualified() ? keyword::kConst | ||
| : keyword_mut_, | ||
| str); | ||
| } else { | ||
| StrCat(token::kRef, | ||
| decl->getType().isConstQualified() ? "" : keyword_mut_, str); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
|
|
@@ -3509,14 +3535,78 @@ void Converter::ConvertUnsignedArithOperand(clang::Expr *expr, | |
| } | ||
| } | ||
|
|
||
| void Converter::ConvertGlobalVarBaseSuffix(clang::Expr *expr) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not good. The logic here should go into VisitMemberExpr and VisitArraySubscriptExpr |
||
| expr = expr->IgnoreImplicit(); | ||
| // Base case: this expression IS the global var root — no suffix to emit. | ||
| if (IsGlobalVar(expr)) { | ||
| return; | ||
| } | ||
| if (auto *member = clang::dyn_cast<clang::MemberExpr>(expr)) { | ||
| ConvertGlobalVarBaseSuffix(member->getBase()); | ||
| StrCat(token::kDot); | ||
| StrCat(GetNamedDeclAsString(member->getMemberDecl())); | ||
| return; | ||
| } | ||
| if (auto *subscript = clang::dyn_cast<clang::ArraySubscriptExpr>(expr)) { | ||
| ConvertGlobalVarBaseSuffix(subscript->getBase()); | ||
| PushBracket bracket(*this); | ||
| { | ||
| PushParen paren(*this); | ||
| Convert(subscript->getIdx()); | ||
| } | ||
| StrCat(keyword::kAs, "usize"); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| void Converter::ConvertEqualsNullPtr(clang::Expr *expr) { | ||
| StrCat('('); | ||
| Convert(expr); | ||
| if (IsUniquePtr(expr->getType()) || | ||
| expr->getType()->isFunctionPointerType()) { | ||
| StrCat(").is_none()"); | ||
| // Walk up through member accesses and array subscripts to find the root | ||
| // global var (file-scope or static-local). Any fn-ptr field access on a | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not the right place to check against global variables. Prefer to propagate a flag from here to VisitVarDecl |
||
| // static mut struct requires the raw-const pattern to avoid Rust 2024's | ||
| // shared-reference-to-static-mut restriction. | ||
| clang::Expr *root = expr; | ||
| while (root) { | ||
| if (IsGlobalVar(root)) { | ||
| break; | ||
| } | ||
| auto *r = root->IgnoreImplicit(); | ||
| if (auto *member = clang::dyn_cast<clang::MemberExpr>(r)) { | ||
| root = member->getBase(); | ||
| continue; | ||
| } | ||
| if (auto *subscript = clang::dyn_cast<clang::ArraySubscriptExpr>(r)) { | ||
| root = subscript->getBase(); | ||
| continue; | ||
| } | ||
| root = nullptr; | ||
| break; | ||
| } | ||
| if (root != nullptr) { | ||
| StrCat(keyword_unsafe_); | ||
| PushBrace unsafe_brace(*this); | ||
| { | ||
| PushParen paren(*this); | ||
| StrCat("&raw", keyword::kConst); | ||
| Convert(root->IgnoreImplicit()); | ||
| } | ||
| StrCat(".as_ref().unwrap()"); | ||
| ConvertGlobalVarBaseSuffix(expr); | ||
| StrCat(".is_none()"); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| { | ||
| PushParen paren(*this); | ||
| Convert(expr); | ||
| } | ||
| if (IsUniquePtr(expr->getType()) || | ||
| expr->getType()->isFunctionPointerType()) { | ||
| StrCat(".is_none()"); | ||
| } else { | ||
| StrCat(").is_null()"); | ||
| StrCat(".is_null()"); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -4084,12 +4174,35 @@ std::string Converter::ConvertIRFragment( | |
| auto all_args = BuildUnifiedArgs(expr, args, num_args); | ||
|
|
||
| std::string result; | ||
| for (auto &frag : fragments) { | ||
| if (auto *t = std::get_if<TextFragment>(&frag)) { | ||
| result += t->text; | ||
| } else if (auto *g = std::get_if<GenericFragment>(&frag)) { | ||
| for (size_t i = 0; i < fragments.size(); ++i) { | ||
| const auto &frag = fragments[i]; | ||
| if (const auto *t = std::get_if<TextFragment>(&frag)) { | ||
| std::string text = t->text; | ||
| // If this text fragment ends with a lone '&' (reference operator, not | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doing string manipulation on the text fragments is fragile. Prefer adding new attributes in the IR if this change is necessary. |
||
| // '&&' or '&mut') and the immediately following fragment is a placeholder | ||
| // for a global variable, upgrade '&' to '&raw const' or '&raw mut' to | ||
| // comply with Rust 2024's ban on shared references to mutable statics. | ||
| if (!text.empty() && text.back() == '&' && | ||
| (text.size() < 2 || text[text.size() - 2] != '&') && | ||
| i + 1 < fragments.size()) { | ||
| if (const auto *next_ph = | ||
| std::get_if<PlaceholderFragment>(&fragments[i + 1])) { | ||
| auto next_idx = next_ph->n; | ||
| if (next_idx < all_args.size() && IsGlobalVar(all_args[next_idx])) { | ||
| const auto *decl_ref = clang::dyn_cast<clang::DeclRefExpr>( | ||
| all_args[next_idx]->IgnoreImplicit()); | ||
| bool is_const = | ||
| decl_ref && | ||
| decl_ref->getDecl()->getType().isConstQualified(); | ||
| text.pop_back(); // remove '&' | ||
| text += is_const ? "&raw const " : std::string("&raw") + keyword_mut_; | ||
| } | ||
| } | ||
| } | ||
| result += text; | ||
| } else if (const auto *g = std::get_if<GenericFragment>(&frag)) { | ||
| result += Mapper::InstantiateTemplate(GetCalleeOrExpr(expr), g->n); | ||
| } else if (auto *ph = std::get_if<PlaceholderFragment>(&frag)) { | ||
| } else if (const auto *ph = std::get_if<PlaceholderFragment>(&frag)) { | ||
| auto arg_idx = ph->n; | ||
| assert(arg_idx < all_args.size()); | ||
| auto *arg = all_args[arg_idx]; | ||
|
|
@@ -4109,7 +4222,7 @@ std::string Converter::ConvertIRFragment( | |
| .is_index_base = ph->is_index_base, | ||
| }; | ||
| result += ConvertPlaceholder(expr, arg, ph_ctx); | ||
| } else if (auto *mc = | ||
| } else if (const auto *mc = | ||
| std::get_if<std::unique_ptr<MethodCallFragment>>(&frag)) { | ||
| result += ConvertMappedMethodCall(expr, **mc, args, num_args, ctx); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use PushParen instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot comply with this review.