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, and user-defined structs, unless they have a
18- // 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 }
2546 } else if (type->isStructureOrClassType ()) {
26- if (!IsUserDefinedDecl (type->getAsRecordDecl ()) ||
47+ if (( !IsUserDefinedDecl (type->getAsRecordDecl ()) && ! IsUniquePtr (type )) ||
2748 TypeNeedsDestruction (type)) {
2849 return false ;
2950 }
@@ -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,27 +132,46 @@ 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 }
149+ // Dereferencing a unique_ptr reads the pointer it holds; the object it
150+ // points to is not stored in the unique_ptr.
151+ switch (expr->getOperator ()) {
152+ case clang::OO_Subscript:
153+ case clang::OO_Star:
154+ case clang::OO_Arrow:
155+ if (IsUniquePtr (expr->getArg (0 )->getType ())) {
156+ AddValueUse (IgnoreNoOpCasts (expr->getArg (0 )));
157+ }
158+ break ;
159+ default :
160+ break ;
161+ }
121162 return true ;
122163 }
123164
124165 bool VisitBinaryOperator (clang::BinaryOperator *expr) {
125166 if (expr->isAssignmentOp ()) {
126- AddValueUse (expr->getLHS ());
167+ AddValueUse (expr->getLHS (), /* write= */ true );
127168 }
128169 return true ;
129170 }
130171
131172 bool VisitUnaryOperator (clang::UnaryOperator *expr) {
132173 if (expr->isIncrementDecrementOp ()) {
133- AddValueUse (expr->getSubExpr ());
174+ AddValueUse (expr->getSubExpr (), /* write= */ true );
134175 }
135176 return true ;
136177 }
@@ -152,21 +193,48 @@ class AddressTakenVisitor
152193 }
153194
154195private:
155- // An element of an array, or a field of a struct, is accessed without
156- // making a pointer to it.
157- 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 ) {
158215 expr = expr->IgnoreParens ();
159216 if (auto *member = clang::dyn_cast<clang::MemberExpr>(expr)) {
160217 if (!member->isArrow () &&
161218 clang::isa<clang::FieldDecl>(member->getMemberDecl ())) {
162- AddValueUse (member->getBase ());
219+ AddValueUse (member->getBase (), write );
163220 }
164221 } else if (auto *subscript =
165222 clang::dyn_cast<clang::ArraySubscriptExpr>(expr)) {
166223 auto *cast =
167224 clang::dyn_cast<clang::ImplicitCastExpr>(subscript->getBase ());
168225 if (cast && cast->getCastKind () == clang::CK_ArrayToPointerDecay) {
169- 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);
170238 }
171239 } else if (auto *ref = clang::dyn_cast<clang::DeclRefExpr>(expr)) {
172240 value_uses_.insert (ref);
@@ -180,14 +248,15 @@ class AddressTakenVisitor
180248 }
181249 }
182250
251+ clang::ASTContext &ctx_;
183252 std::unordered_set<const clang::VarDecl *> &address_taken_;
184253 // The references to variables that only access their value.
185254 std::unordered_set<const clang::DeclRefExpr *> value_uses_;
186255};
187256} // namespace
188257
189258BoxedVars::BoxedVars (clang::ASTContext &ctx) {
190- AddressTakenVisitor (address_taken_)
259+ AddressTakenVisitor (ctx, address_taken_)
191260 .TraverseDecl (ctx.getTranslationUnitDecl ());
192261}
193262
0 commit comments