@@ -2424,6 +2424,70 @@ namespace {
24242424 return result;
24252425 }
24262426
2427+ void validateForeignReferenceType (const clang::CXXRecordDecl *decl,
2428+ ClassDecl *classDecl) {
2429+ auto isValidOperation = [&](ValueDecl *operation) -> bool {
2430+ auto operationFn = dyn_cast<FuncDecl>(operation);
2431+ if (!operationFn)
2432+ return false ;
2433+
2434+ if (!operationFn->getResultInterfaceType ()->isVoid ())
2435+ return false ;
2436+
2437+ if (operationFn->getParameters ()->size () != 1 )
2438+ return false ;
2439+
2440+ if (operationFn->getParameters ()->get (0 )->getInterfaceType ()->isEqual (classDecl->getInterfaceType ()))
2441+ return false ;
2442+
2443+ return true ;
2444+ };
2445+
2446+ auto retainOperation = evaluateOrDefault (
2447+ Impl.SwiftContext .evaluator ,
2448+ CustomRefCountingOperation ({classDecl, CustomRefCountingOperationKind::retain}), {});
2449+ if (retainOperation.kind == CustomRefCountingOperationResult::noAttribute) {
2450+ HeaderLoc loc (decl->getLocation ());
2451+ Impl.diagnose (loc, diag::reference_type_must_have_retain_attr, decl->getNameAsString ());
2452+ } else if (retainOperation.kind == CustomRefCountingOperationResult::notFound) {
2453+ HeaderLoc loc (decl->getLocation ());
2454+ Impl.diagnose (loc, diag::foreign_reference_types_cannot_find_retain, retainOperation.name , decl->getNameAsString ());
2455+ } else if (retainOperation.kind == CustomRefCountingOperationResult::tooManyFound) {
2456+ HeaderLoc loc (decl->getLocation ());
2457+ Impl.diagnose (loc, diag::too_many_reference_type_retain_operations, retainOperation.name , decl->getNameAsString ());
2458+ } else if (retainOperation.kind == CustomRefCountingOperationResult::foundOperation) {
2459+ if (!isValidOperation (retainOperation.operation )) {
2460+ HeaderLoc loc (decl->getLocation ());
2461+ Impl.diagnose (loc, diag::foreign_reference_types_invalid_retain, retainOperation.name , decl->getNameAsString ());
2462+ }
2463+ } else {
2464+ // Nothing to do.
2465+ assert (retainOperation.kind == CustomRefCountingOperationResult::immortal);
2466+ }
2467+
2468+ auto releaseOperation = evaluateOrDefault (
2469+ Impl.SwiftContext .evaluator ,
2470+ CustomRefCountingOperation ({classDecl, CustomRefCountingOperationKind::release}), {});
2471+ if (releaseOperation.kind == CustomRefCountingOperationResult::noAttribute) {
2472+ HeaderLoc loc (decl->getLocation ());
2473+ Impl.diagnose (loc, diag::reference_type_must_have_release_attr, decl->getNameAsString ());
2474+ } else if (releaseOperation.kind == CustomRefCountingOperationResult::notFound) {
2475+ HeaderLoc loc (decl->getLocation ());
2476+ Impl.diagnose (loc, diag::foreign_reference_types_cannot_find_release, releaseOperation.name , decl->getNameAsString ());
2477+ } else if (releaseOperation.kind == CustomRefCountingOperationResult::tooManyFound) {
2478+ HeaderLoc loc (decl->getLocation ());
2479+ Impl.diagnose (loc, diag::too_many_reference_type_release_operations, releaseOperation.name , decl->getNameAsString ());
2480+ } else if (releaseOperation.kind == CustomRefCountingOperationResult::foundOperation) {
2481+ if (!isValidOperation (releaseOperation.operation )) {
2482+ HeaderLoc loc (decl->getLocation ());
2483+ Impl.diagnose (loc, diag::foreign_reference_types_invalid_release, releaseOperation.name , decl->getNameAsString ());
2484+ }
2485+ } else {
2486+ // Nothing to do.
2487+ assert (releaseOperation.kind == CustomRefCountingOperationResult::immortal);
2488+ }
2489+ }
2490+
24272491 Decl *VisitCXXRecordDecl (const clang::CXXRecordDecl *decl) {
24282492 // This can be called from lldb without C++ interop being enabled: There
24292493 // may be C++ declarations in imported modules, but the interface for
@@ -2504,6 +2568,9 @@ namespace {
25042568
25052569 auto result = VisitRecordDecl (decl);
25062570
2571+ if (auto classDecl = dyn_cast_or_null<ClassDecl>(result))
2572+ validateForeignReferenceType (decl, classDecl);
2573+
25072574 // If this module is declared as a C++ module, try to synthesize
25082575 // conformances to Swift protocols from the Cxx module.
25092576 auto clangModule = decl->getOwningModule ();
0 commit comments