@@ -60,6 +60,17 @@ static bool IsBoxedType(clang::ASTContext &ctx, clang::QualType type) {
6060 return IsBoxedType (Mapper::Map (ctx, type.getUnqualifiedType ()));
6161}
6262
63+ // A Rust type without whitespace, and with the paths into libcc2rs, which the
64+ // rules import, unqualified, to compare it with another.
65+ static std::string NormalizeType (std::string type) {
66+ std::erase_if (type, [](char c) { return std::isspace (c); });
67+ static constexpr std::string_view kLib = " libcc2rs::" ;
68+ for (size_t pos; (pos = type.find (kLib )) != std::string::npos;) {
69+ type.erase (pos, kLib .size ());
70+ }
71+ return type;
72+ }
73+
6374// Virtual methods take &mut self, as the fields of the struct are stored in
6475// it.
6576static bool NeedsMutAccess (clang::ASTContext &ctx,
@@ -379,31 +390,92 @@ std::string ConverterRefCount::ConvertObject(clang::Expr *expr,
379390 PushExprKind push (*this , ExprKind::Object);
380391 auto saved_shape = std::exchange (object_shape_, shape);
381392 auto str = ToString (expr);
393+ // Unless the visitor already made a pointer to the elements.
394+ bool decay = object_shape_ == ObjectShape::Element;
382395 object_shape_ = saved_shape;
383- if (shape == ObjectShape::Element && expr->getType ()->isPointerType ()) {
384- auto pointee = expr->getType ()->getPointeeType ();
385- if (IsBoxedType (ctx_, pointee) || pointee->isArrayType ()) {
386- PushConversionKind push (*this , ConversionKind::Pointee);
396+ if (decay) {
397+ auto type = expr->getType ().getNonReferenceType ();
398+ bool is_ptr = type->isPointerType ();
399+ if (is_ptr) {
400+ type = type->getPointeeType ();
401+ }
402+ if (IsBoxedType (ctx_, type) || (is_ptr && type->isArrayType ())) {
387403 computed_expr_type_ = ComputedExprType::FreshPointer;
388- return std::format (" Ptr::<{}>::decay(&({}))" , ToString (pointee),
389- std::move (str));
404+ return std::move (str) + " .decay()" ;
390405 }
391406 }
392407 return str;
393408}
394409
395- std::string ConverterRefCount::AsPointerMethod (clang::QualType type) const {
396- return isObject () && WantsElementPtr () &&
397- type.getNonReferenceType ()->isRecordType ()
398- ? " .as_pointer().decay()"
399- : " .as_pointer()" ;
410+ std::string ConverterRefCount::AsPointerMethod (clang::QualType type) {
411+ if (isObject () && object_shape_ == ObjectShape::Element &&
412+ type->isRecordType () && IsBoxedType (ctx_, type)) {
413+ object_shape_ = ObjectShape::Whole;
414+ return " .decay()" ;
415+ }
416+ return " .as_pointer()" ;
400417}
401418
402419std::string ConverterRefCount::ConvertPointerReceiver (clang::Expr *arg,
403420 std::string_view) {
404421 return isObject () ? ConvertObject (arg) : ConvertFreshObject (arg);
405422}
406423
424+ bool ConverterRefCount::ParamIsElementPtr (clang::Expr *expr, clang::Expr *arg,
425+ unsigned index) {
426+ if (!RuleRegistry::ParamIsPointer (ctx_, expr, index)) {
427+ return false ;
428+ }
429+ auto type = arg->getType ().getNonReferenceType ();
430+ if (type->isPointerType ()) {
431+ type = type->getPointeeType ();
432+ }
433+ type = type.getUnqualifiedType ();
434+ if (!IsBoxedType (ctx_, type)) {
435+ return false ;
436+ }
437+ // The C++ parameter is a reference or pointer to the container, which the
438+ // rule takes either as a pointer to it or as one to its elements.
439+ auto param = NormalizeType (Mapper::GetParamType (*this , expr, index));
440+ auto whole = NormalizeType (ToString (ctx_.getPointerType (type)));
441+ if (param == whole) {
442+ return false ;
443+ }
444+ auto element = NormalizeType (ConvertPtrType (type));
445+ if (param != element) {
446+ llvm::errs () << " rule parameter " << index << " of type " << param
447+ << " is neither " << whole << " nor " << element << ' \n ' ;
448+ llvm::report_fatal_error (" rule parameter does not match the C++ one" );
449+ }
450+ return true ;
451+ }
452+
453+ std::string ConverterRefCount::ConvertElementPtr (clang::Expr *arg) {
454+ return ConvertObject (arg, ObjectShape::Element);
455+ }
456+
457+ void ConverterRefCount::CheckRuleReturnType (clang::Expr *expr) {
458+ auto *call = clang::dyn_cast<clang::CallExpr>(expr);
459+ if (!call ||
460+ !RuleRegistry::GetExprRule (ctx_, expr)->return_type .is_refcount_pointer ) {
461+ return ;
462+ }
463+ // A reference is returned as a pointer. The library may spell the pointer
464+ // or reference type with a typedef of its own, e.g., iterator::pointer,
465+ // which is not what the pointee is spelled with.
466+ auto type = GetReturnTypeOfFunction (call).getDesugaredType (ctx_);
467+ if (auto *ref = type->getAs <clang::ReferenceType>()) {
468+ type = ctx_.getPointerType (ref->getPointeeType ());
469+ }
470+ auto ret = NormalizeType (Mapper::GetReturnType (*this , expr));
471+ auto expected = NormalizeType (ToString (type));
472+ if (ret != expected) {
473+ llvm::errs () << " rule return type " << ret << " is not " << expected
474+ << ' \n ' ;
475+ llvm::report_fatal_error (" rule return type does not match the C++ one" );
476+ }
477+ }
478+
407479std::string ConverterRefCount::ConvertFreshObject (clang::Expr *expr) {
408480 auto str = ConvertObject (expr);
409481 if (isFresh ()) {
@@ -1020,14 +1092,6 @@ void ConverterRefCount::ConvertDeclRefValue(clang::Expr *expr,
10201092 }
10211093
10221094 if (auto *ref = decl_t ->getAs <clang::ReferenceType>()) {
1023- if (auto pointee = ref->getPointeeType ();
1024- isObject () && WantsElementPtr () && IsBoxedType (ctx_, pointee)) {
1025- StrCat (std::format (" Ptr::<{}>::decay(&({}))" , ToString (pointee),
1026- std::move (str)));
1027- computed_expr_type_ = ComputedExprType::FreshPointer;
1028- return ;
1029- }
1030-
10311095 // references are not boxed
10321096 if (isAddrOf ()) {
10331097 StrCat (str);
@@ -1351,14 +1415,6 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) {
13511415 return false ;
13521416 }
13531417
1354- if (isObject () && WantsElementPtr () && ref &&
1355- IsBoxedType (ctx_, ref->getPointeeType ())) {
1356- StrCat (std::format (" Ptr::<{}>::decay(&({}))" ,
1357- ToString (ref->getPointeeType ()), std::move (str)));
1358- computed_expr_type_ = ComputedExprType::FreshPointer;
1359- return false ;
1360- }
1361-
13621418 if (ctx && !ctx->temporary_bindings .empty ()) {
13631419 str = std::format (" ({{ {} {} }})" , ctx->temporary_bindings , str);
13641420 }
@@ -2299,8 +2355,8 @@ bool ConverterRefCount::VisitCXXConstructExpr(clang::CXXConstructExpr *expr) {
22992355 if (auto str = GetMappedAsString (expr, expr->getArgs (), expr->getNumArgs ());
23002356 !str.empty ()) {
23012357 if (isAddrOf ()) {
2302- StrCat (std::format (" Rc::new(RefCell::new({})).as_pointer() " ,
2303- std::move (str )));
2358+ StrCat (std::format (" Rc::new(RefCell::new({})){} " , std::move (str) ,
2359+ AsPointerMethod (expr-> getType () )));
23042360 computed_expr_type_ = ComputedExprType::FreshPointer;
23052361 } else {
23062362 StrCat (str);
@@ -2841,10 +2897,6 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
28412897 ConvertSubscriptIndex (expr->getArg (1 ))));
28422898 }
28432899
2844- if (is_inner_boxed && isObject () && WantsElementPtr ()) {
2845- StrCat (" .decay()" );
2846- }
2847-
28482900 if (isAddrOf ()) {
28492901 computed_expr_type_ = ComputedExprType::FreshPointer;
28502902 } else {
@@ -3123,16 +3175,6 @@ pub fn main() {{
31233175
31243176void ConverterRefCount::ConvertAddrOf (clang::Expr *expr,
31253177 clang::QualType pointer_type) {
3126- auto pointee_type = pointer_type->getPointeeType ();
3127- if (isObject () && WantsElementPtr () &&
3128- (IsBoxedType (ctx_, pointee_type) || pointee_type->isArrayType ())) {
3129- auto ptr = ConvertPointer (expr);
3130- PushConversionKind push (*this , ConversionKind::Pointee);
3131- StrCat (std::format (" Ptr::<{}>::decay(&({}))" , ToString (pointee_type),
3132- std::move (ptr)));
3133- computed_expr_type_ = ComputedExprType::FreshPointer;
3134- return ;
3135- }
31363178 StrCat (ConvertPointer (expr));
31373179}
31383180
@@ -3171,15 +3213,6 @@ void ConverterRefCount::ConvertDeref(clang::Expr *expr) {
31713213 if (isAddrOf () && pointee_type->isArrayType ()) {
31723214 str = std::format (" ({}).as_pointer()" , std::move (str));
31733215 }
3174-
3175- if (isObject () && WantsElementPtr () &&
3176- (IsBoxedType (ctx_, pointee_type) || pointee_type->isArrayType ())) {
3177- PushConversionKind push (*this , ConversionKind::Pointee);
3178- StrCat (std::format (" Ptr::<{}>::decay(&({}))" , ToString (pointee_type),
3179- std::move (str)));
3180- computed_expr_type_ = ComputedExprType::FreshPointer;
3181- return ;
3182- }
31833216 StrCat (std::move (str));
31843217}
31853218
@@ -3402,8 +3435,8 @@ void ConverterRefCount::SetUFCSReceiver(clang::Expr *base, bool is_arrow,
34023435 if (IsTemporaryObject (base) && base->getType ()->isRecordType () &&
34033436 !IsReferenceType (base->IgnoreImplicit ())) {
34043437 PushConversionKind push (*this , ConversionKind::FullRefCount);
3405- ufcs_receiver_ = token:: kRef + BoxValue ( ConvertRValue (base)) +
3406- AsPointerMethod (base-> getType ()) ;
3438+ ufcs_receiver_ =
3439+ token:: kRef + BoxValue ( ConvertRValue (base)) + " .as_pointer() " ;
34073440 return ;
34083441 }
34093442 ufcs_receiver_ = token::kRef + (base_is_pointer ? ConvertRValue (base)
0 commit comments