55
66#include < clang/AST/RecursiveASTVisitor.h>
77
8+ #include < algorithm>
89#include < unordered_map>
910#include < vector>
1011
1112#include " converter/converter_lib.h"
1213#include " converter/mapper.h"
14+ #include " converter/rules/registry.h"
1315
1416namespace cpp2rust {
1517namespace {
18+ // Whether type is translated to a Vec whose elements are not in Values:
19+ // std::vector and std::string of scalars or user-defined structs.
20+ bool IsFlatVec (clang::QualType type) {
21+ auto *record =
22+ clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
23+ type->getAsCXXRecordDecl ());
24+ if (!record || !record->isInStdNamespace () ||
25+ (record->getName () != " vector" && record->getName () != " basic_string" )) {
26+ return false ;
27+ }
28+ auto element = record->getTemplateArgs ()[0 ].getAsType ();
29+ return element->isScalarType () ||
30+ (element->isStructureOrClassType () &&
31+ IsUserDefinedDecl (element->getAsRecordDecl ()));
32+ }
33+
1634// Whether decl may be stored without a Value, if its address is not taken:
17- // scalars, arrays of non-arrays, user-defined structs and unique_ptrs, unless
18- // they have a destructor, which is called with a pointer to them.
35+ // scalars, arrays of non-arrays, user-defined structs, unique_ptrs and
36+ // vectors, unless they have a destructor, which is called with a pointer to
37+ // them.
1938bool CanUnbox (const clang::VarDecl *decl) {
2039 auto type = decl->getType ();
21- if (type->isConstantArrayType ()) {
40+ if (IsFlatVec (type)) {
41+ // Vectors are flat Vecs.
42+ } else if (type->isConstantArrayType ()) {
2243 if (type->getAsArrayTypeUnsafe ()->getElementType ()->isArrayType ()) {
2344 return false ;
2445 }
@@ -72,8 +93,9 @@ bool IsTrivialAssignment(clang::CXXOperatorCallExpr *expr) {
7293class AddressTakenVisitor
7394 : public clang::RecursiveASTVisitor<AddressTakenVisitor> {
7495public:
75- explicit AddressTakenVisitor (std::unordered_set<const clang::VarDecl *> &vars)
76- : address_taken_(vars) {}
96+ AddressTakenVisitor (clang::ASTContext &ctx,
97+ std::unordered_set<const clang::VarDecl *> &vars)
98+ : ctx_(ctx), address_taken_(vars) {}
7799
78100 bool shouldVisitTemplateInstantiations () const { return true ; }
79101
@@ -110,12 +132,18 @@ class AddressTakenVisitor
110132 if (auto *source = GetTrivialCopySource (expr)) {
111133 AddValueUse (source);
112134 }
135+ AddRuleArgs (expr, expr->getArgs (), expr->getNumArgs ());
136+ return true ;
137+ }
138+
139+ bool VisitCallExpr (clang::CallExpr *expr) {
140+ AddRuleArgs (expr, expr->getArgs (), expr->getNumArgs ());
113141 return true ;
114142 }
115143
116144 bool VisitCXXOperatorCallExpr (clang::CXXOperatorCallExpr *expr) {
117145 if (IsTrivialAssignment (expr)) {
118- AddValueUse (expr->getArg (0 ));
146+ AddValueUse (expr->getArg (0 ), /* write= */ true );
119147 AddValueUse (IgnoreNoOpCasts (expr->getArg (1 )));
120148 }
121149 // Dereferencing a unique_ptr reads the pointer it holds; the object it
@@ -136,14 +164,14 @@ class AddressTakenVisitor
136164
137165 bool VisitBinaryOperator (clang::BinaryOperator *expr) {
138166 if (expr->isAssignmentOp ()) {
139- AddValueUse (expr->getLHS ());
167+ AddValueUse (expr->getLHS (), /* write= */ true );
140168 }
141169 return true ;
142170 }
143171
144172 bool VisitUnaryOperator (clang::UnaryOperator *expr) {
145173 if (expr->isIncrementDecrementOp ()) {
146- AddValueUse (expr->getSubExpr ());
174+ AddValueUse (expr->getSubExpr (), /* write= */ true );
147175 }
148176 return true ;
149177 }
@@ -165,21 +193,48 @@ class AddressTakenVisitor
165193 }
166194
167195private:
168- // An element of an array, or a field of a struct, is accessed without
169- // making a pointer to it.
170- void AddValueUse (clang::Expr *expr) {
196+ // The arguments of a call translated by a rule are passed by value or
197+ // borrowed, unless the rule takes a pointer to them.
198+ void AddRuleArgs (clang::Expr *expr, clang::Expr **args, unsigned num_args) {
199+ auto *rule = RuleRegistry::GetExprRule (ctx_, GetCalleeOrExpr (expr));
200+ if (!rule) {
201+ return ;
202+ }
203+ // Variadic arguments are not considered.
204+ auto all_args = BuildUnifiedArgs (expr, args, num_args);
205+ for (unsigned i = 0 ; i < all_args.size () && i < rule->params .size (); ++i) {
206+ if (!rule->params [i].is_pointer ()) {
207+ AddValueUse (IgnoreNoOpCasts (all_args[i]));
208+ }
209+ }
210+ }
211+
212+ // An element of an array or vector, or a field of a struct, is accessed
213+ // without making a pointer to it.
214+ void AddValueUse (clang::Expr *expr, bool write = false ) {
171215 expr = expr->IgnoreParens ();
172216 if (auto *member = clang::dyn_cast<clang::MemberExpr>(expr)) {
173217 if (!member->isArrow () &&
174218 clang::isa<clang::FieldDecl>(member->getMemberDecl ())) {
175- AddValueUse (member->getBase ());
219+ AddValueUse (member->getBase (), write );
176220 }
177221 } else if (auto *subscript =
178222 clang::dyn_cast<clang::ArraySubscriptExpr>(expr)) {
179223 auto *cast =
180224 clang::dyn_cast<clang::ImplicitCastExpr>(subscript->getBase ());
181225 if (cast && cast->getCastKind () == clang::CK_ArrayToPointerDecay) {
182- AddValueUse (cast->getSubExpr ());
226+ AddValueUse (cast->getSubExpr (), write);
227+ }
228+ } else if (auto *op = clang::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
229+ // Rust doesn't let the index of an element that is written to read the
230+ // vector, as the vector is borrowed mutably first.
231+ auto *vec = IgnoreNoOpCasts (op->getArg (0 ));
232+ if (op->getOperator () == clang::OO_Subscript &&
233+ IsFlatVec (vec->getType ()) &&
234+ (!write || std::ranges::none_of (GetAllVars (vec), [&](auto *var) {
235+ return GetAllVars (op->getArg (1 )).contains (var);
236+ }))) {
237+ AddValueUse (vec, write);
183238 }
184239 } else if (auto *ref = clang::dyn_cast<clang::DeclRefExpr>(expr)) {
185240 value_uses_.insert (ref);
@@ -193,14 +248,15 @@ class AddressTakenVisitor
193248 }
194249 }
195250
251+ clang::ASTContext &ctx_;
196252 std::unordered_set<const clang::VarDecl *> &address_taken_;
197253 // The references to variables that only access their value.
198254 std::unordered_set<const clang::DeclRefExpr *> value_uses_;
199255};
200256} // namespace
201257
202258BoxedVars::BoxedVars (clang::ASTContext &ctx) {
203- AddressTakenVisitor (address_taken_)
259+ AddressTakenVisitor (ctx, address_taken_)
204260 .TraverseDecl (ctx.getTranslationUnitDecl ());
205261}
206262
0 commit comments