@@ -2542,24 +2542,23 @@ namespace {
25422542 void validateForeignReferenceType (const clang::CXXRecordDecl *decl,
25432543 ClassDecl *classDecl) {
25442544
2545- enum class RetainReleaseOperatonKind {
2545+ enum class RetainReleaseOperationKind {
25462546 notAfunction,
2547- doesntReturnVoid ,
2547+ doesntReturnVoidOrSelf ,
25482548 invalidParameters,
25492549 valid
25502550 };
25512551
25522552 auto getOperationValidity =
2553- [&](ValueDecl *operation) -> RetainReleaseOperatonKind {
2553+ [&](ValueDecl *operation,
2554+ CustomRefCountingOperationKind operationKind)
2555+ -> RetainReleaseOperationKind {
25542556 auto operationFn = dyn_cast<FuncDecl>(operation);
25552557 if (!operationFn)
2556- return RetainReleaseOperatonKind::notAfunction;
2557-
2558- if (!operationFn->getResultInterfaceType ()->isVoid ())
2559- return RetainReleaseOperatonKind::doesntReturnVoid;
2558+ return RetainReleaseOperationKind::notAfunction;
25602559
25612560 if (operationFn->getParameters ()->size () != 1 )
2562- return RetainReleaseOperatonKind ::invalidParameters;
2561+ return RetainReleaseOperationKind ::invalidParameters;
25632562
25642563 Type paramType =
25652564 operationFn->getParameters ()->get (0 )->getInterfaceType ();
@@ -2569,20 +2568,31 @@ namespace {
25692568 }
25702569
25712570 swift::NominalTypeDecl *paramDecl = paramType->getAnyNominal ();
2571+
2572+ // The return type should be void (for release functions), or void
2573+ // or the parameter type (for retain functions).
2574+ auto resultInterfaceType = operationFn->getResultInterfaceType ();
2575+ if (!resultInterfaceType->isVoid ()) {
2576+ if (operationKind == CustomRefCountingOperationKind::release ||
2577+ !resultInterfaceType->lookThroughSingleOptionalType ()->isEqual (paramType))
2578+ return RetainReleaseOperationKind::doesntReturnVoidOrSelf;
2579+ }
2580+
25722581 // The parameter of the retain/release function should be pointer to the
25732582 // same FRT or a base FRT.
25742583 if (paramDecl != classDecl) {
25752584 if (const clang::Decl *paramClangDecl = paramDecl->getClangDecl ()) {
25762585 if (const auto *paramTypeDecl =
25772586 dyn_cast<clang::CXXRecordDecl>(paramClangDecl)) {
25782587 if (decl->isDerivedFrom (paramTypeDecl)) {
2579- return RetainReleaseOperatonKind ::valid;
2588+ return RetainReleaseOperationKind ::valid;
25802589 }
25812590 }
25822591 }
2583- return RetainReleaseOperatonKind ::invalidParameters;
2592+ return RetainReleaseOperationKind ::invalidParameters;
25842593 }
2585- return RetainReleaseOperatonKind::valid;
2594+
2595+ return RetainReleaseOperationKind::valid;
25862596 };
25872597
25882598 auto retainOperation = evaluateOrDefault (
@@ -2619,28 +2629,29 @@ namespace {
26192629 false , retainOperation.name , decl->getNameAsString ());
26202630 } else if (retainOperation.kind ==
26212631 CustomRefCountingOperationResult::foundOperation) {
2622- RetainReleaseOperatonKind operationKind =
2623- getOperationValidity (retainOperation.operation );
2632+ RetainReleaseOperationKind operationKind =
2633+ getOperationValidity (retainOperation.operation ,
2634+ CustomRefCountingOperationKind::retain);
26242635 HeaderLoc loc (decl->getLocation ());
26252636 switch (operationKind) {
2626- case RetainReleaseOperatonKind ::notAfunction:
2637+ case RetainReleaseOperationKind ::notAfunction:
26272638 Impl.diagnose (
26282639 loc,
26292640 diag::foreign_reference_types_retain_release_not_a_function_decl,
26302641 false , retainOperation.name );
26312642 break ;
2632- case RetainReleaseOperatonKind::doesntReturnVoid :
2643+ case RetainReleaseOperationKind::doesntReturnVoidOrSelf :
26332644 Impl.diagnose (
26342645 loc,
2635- diag::foreign_reference_types_retain_release_non_void_return_type ,
2636- false , retainOperation.name );
2646+ diag::foreign_reference_types_retain_non_void_or_self_return_type ,
2647+ retainOperation.name );
26372648 break ;
2638- case RetainReleaseOperatonKind ::invalidParameters:
2649+ case RetainReleaseOperationKind ::invalidParameters:
26392650 Impl.diagnose (loc,
26402651 diag::foreign_reference_types_invalid_retain_release,
26412652 false , retainOperation.name , classDecl->getNameStr ());
26422653 break ;
2643- case RetainReleaseOperatonKind ::valid:
2654+ case RetainReleaseOperationKind ::valid:
26442655 break ;
26452656 }
26462657 } else {
@@ -2683,28 +2694,29 @@ namespace {
26832694 true , releaseOperation.name , decl->getNameAsString ());
26842695 } else if (releaseOperation.kind ==
26852696 CustomRefCountingOperationResult::foundOperation) {
2686- RetainReleaseOperatonKind operationKind =
2687- getOperationValidity (releaseOperation.operation );
2697+ RetainReleaseOperationKind operationKind =
2698+ getOperationValidity (releaseOperation.operation ,
2699+ CustomRefCountingOperationKind::release);
26882700 HeaderLoc loc (decl->getLocation ());
26892701 switch (operationKind) {
2690- case RetainReleaseOperatonKind ::notAfunction:
2702+ case RetainReleaseOperationKind ::notAfunction:
26912703 Impl.diagnose (
26922704 loc,
26932705 diag::foreign_reference_types_retain_release_not_a_function_decl,
26942706 true , releaseOperation.name );
26952707 break ;
2696- case RetainReleaseOperatonKind::doesntReturnVoid :
2708+ case RetainReleaseOperationKind::doesntReturnVoidOrSelf :
26972709 Impl.diagnose (
26982710 loc,
2699- diag::foreign_reference_types_retain_release_non_void_return_type ,
2700- true , releaseOperation.name );
2711+ diag::foreign_reference_types_release_non_void_return_type ,
2712+ releaseOperation.name );
27012713 break ;
2702- case RetainReleaseOperatonKind ::invalidParameters:
2714+ case RetainReleaseOperationKind ::invalidParameters:
27032715 Impl.diagnose (loc,
27042716 diag::foreign_reference_types_invalid_retain_release,
27052717 true , releaseOperation.name , classDecl->getNameStr ());
27062718 break ;
2707- case RetainReleaseOperatonKind ::valid:
2719+ case RetainReleaseOperationKind ::valid:
27082720 break ;
27092721 }
27102722 } else {
0 commit comments