@@ -2534,24 +2534,23 @@ namespace {
25342534 void validateForeignReferenceType (const clang::CXXRecordDecl *decl,
25352535 ClassDecl *classDecl) {
25362536
2537- enum class RetainReleaseOperatonKind {
2537+ enum class RetainReleaseOperationKind {
25382538 notAfunction,
2539- doesntReturnVoid ,
2539+ doesntReturnVoidOrSelf ,
25402540 invalidParameters,
25412541 valid
25422542 };
25432543
25442544 auto getOperationValidity =
2545- [&](ValueDecl *operation) -> RetainReleaseOperatonKind {
2545+ [&](ValueDecl *operation,
2546+ CustomRefCountingOperationKind operationKind)
2547+ -> RetainReleaseOperationKind {
25462548 auto operationFn = dyn_cast<FuncDecl>(operation);
25472549 if (!operationFn)
2548- return RetainReleaseOperatonKind::notAfunction;
2549-
2550- if (!operationFn->getResultInterfaceType ()->isVoid ())
2551- return RetainReleaseOperatonKind::doesntReturnVoid;
2550+ return RetainReleaseOperationKind::notAfunction;
25522551
25532552 if (operationFn->getParameters ()->size () != 1 )
2554- return RetainReleaseOperatonKind ::invalidParameters;
2553+ return RetainReleaseOperationKind ::invalidParameters;
25552554
25562555 Type paramType =
25572556 operationFn->getParameters ()->get (0 )->getInterfaceType ();
@@ -2561,20 +2560,31 @@ namespace {
25612560 }
25622561
25632562 swift::NominalTypeDecl *paramDecl = paramType->getAnyNominal ();
2563+
2564+ // The return type should be void (for release functions), or void
2565+ // or the parameter type (for retain functions).
2566+ auto resultInterfaceType = operationFn->getResultInterfaceType ();
2567+ if (!resultInterfaceType->isVoid ()) {
2568+ if (operationKind == CustomRefCountingOperationKind::release ||
2569+ !resultInterfaceType->lookThroughSingleOptionalType ()->isEqual (paramType))
2570+ return RetainReleaseOperationKind::doesntReturnVoidOrSelf;
2571+ }
2572+
25642573 // The parameter of the retain/release function should be pointer to the
25652574 // same FRT or a base FRT.
25662575 if (paramDecl != classDecl) {
25672576 if (const clang::Decl *paramClangDecl = paramDecl->getClangDecl ()) {
25682577 if (const auto *paramTypeDecl =
25692578 dyn_cast<clang::CXXRecordDecl>(paramClangDecl)) {
25702579 if (decl->isDerivedFrom (paramTypeDecl)) {
2571- return RetainReleaseOperatonKind ::valid;
2580+ return RetainReleaseOperationKind ::valid;
25722581 }
25732582 }
25742583 }
2575- return RetainReleaseOperatonKind ::invalidParameters;
2584+ return RetainReleaseOperationKind ::invalidParameters;
25762585 }
2577- return RetainReleaseOperatonKind::valid;
2586+
2587+ return RetainReleaseOperationKind::valid;
25782588 };
25792589
25802590 auto retainOperation = evaluateOrDefault (
@@ -2611,28 +2621,29 @@ namespace {
26112621 false , retainOperation.name , decl->getNameAsString ());
26122622 } else if (retainOperation.kind ==
26132623 CustomRefCountingOperationResult::foundOperation) {
2614- RetainReleaseOperatonKind operationKind =
2615- getOperationValidity (retainOperation.operation );
2624+ RetainReleaseOperationKind operationKind =
2625+ getOperationValidity (retainOperation.operation ,
2626+ CustomRefCountingOperationKind::retain);
26162627 HeaderLoc loc (decl->getLocation ());
26172628 switch (operationKind) {
2618- case RetainReleaseOperatonKind ::notAfunction:
2629+ case RetainReleaseOperationKind ::notAfunction:
26192630 Impl.diagnose (
26202631 loc,
26212632 diag::foreign_reference_types_retain_release_not_a_function_decl,
26222633 false , retainOperation.name );
26232634 break ;
2624- case RetainReleaseOperatonKind::doesntReturnVoid :
2635+ case RetainReleaseOperationKind::doesntReturnVoidOrSelf :
26252636 Impl.diagnose (
26262637 loc,
2627- diag::foreign_reference_types_retain_release_non_void_return_type ,
2628- false , retainOperation.name );
2638+ diag::foreign_reference_types_retain_non_void_or_self_return_type ,
2639+ retainOperation.name );
26292640 break ;
2630- case RetainReleaseOperatonKind ::invalidParameters:
2641+ case RetainReleaseOperationKind ::invalidParameters:
26312642 Impl.diagnose (loc,
26322643 diag::foreign_reference_types_invalid_retain_release,
26332644 false , retainOperation.name , classDecl->getNameStr ());
26342645 break ;
2635- case RetainReleaseOperatonKind ::valid:
2646+ case RetainReleaseOperationKind ::valid:
26362647 break ;
26372648 }
26382649 } else {
@@ -2675,28 +2686,29 @@ namespace {
26752686 true , releaseOperation.name , decl->getNameAsString ());
26762687 } else if (releaseOperation.kind ==
26772688 CustomRefCountingOperationResult::foundOperation) {
2678- RetainReleaseOperatonKind operationKind =
2679- getOperationValidity (releaseOperation.operation );
2689+ RetainReleaseOperationKind operationKind =
2690+ getOperationValidity (releaseOperation.operation ,
2691+ CustomRefCountingOperationKind::release);
26802692 HeaderLoc loc (decl->getLocation ());
26812693 switch (operationKind) {
2682- case RetainReleaseOperatonKind ::notAfunction:
2694+ case RetainReleaseOperationKind ::notAfunction:
26832695 Impl.diagnose (
26842696 loc,
26852697 diag::foreign_reference_types_retain_release_not_a_function_decl,
26862698 true , releaseOperation.name );
26872699 break ;
2688- case RetainReleaseOperatonKind::doesntReturnVoid :
2700+ case RetainReleaseOperationKind::doesntReturnVoidOrSelf :
26892701 Impl.diagnose (
26902702 loc,
2691- diag::foreign_reference_types_retain_release_non_void_return_type ,
2692- true , releaseOperation.name );
2703+ diag::foreign_reference_types_release_non_void_return_type ,
2704+ releaseOperation.name );
26932705 break ;
2694- case RetainReleaseOperatonKind ::invalidParameters:
2706+ case RetainReleaseOperationKind ::invalidParameters:
26952707 Impl.diagnose (loc,
26962708 diag::foreign_reference_types_invalid_retain_release,
26972709 true , releaseOperation.name , classDecl->getNameStr ());
26982710 break ;
2699- case RetainReleaseOperatonKind ::valid:
2711+ case RetainReleaseOperationKind ::valid:
27002712 break ;
27012713 }
27022714 } else {
0 commit comments