Skip to content

Commit eaf9a80

Browse files
authored
Merge pull request #83810 from egorzhdan/egorzhdan/6.2-c-frt-validation
🍒[cxx-interop] Validate C foreign reference types
2 parents f408b2d + fd7b7fe commit eaf9a80

File tree

4 files changed

+66
-25
lines changed

4 files changed

+66
-25
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,6 +2667,25 @@ namespace {
26672667
}
26682668
}
26692669

2670+
if (auto classDecl = dyn_cast<ClassDecl>(result)) {
2671+
validateForeignReferenceType(decl, classDecl);
2672+
2673+
auto availability = Impl.SwiftContext.getSwift58Availability();
2674+
if (!availability.isAlwaysAvailable()) {
2675+
assert(availability.hasMinimumVersion());
2676+
auto AvAttr = AvailableAttr::createPlatformVersioned(
2677+
Impl.SwiftContext, targetPlatform(Impl.SwiftContext.LangOpts),
2678+
/*Message=*/"", /*Rename=*/"",
2679+
availability.getRawMinimumVersion(), /*Deprecated=*/{},
2680+
/*Obsoleted=*/{});
2681+
classDecl->getAttrs().add(AvAttr);
2682+
}
2683+
2684+
if (cxxRecordDecl && cxxRecordDecl->isEffectivelyFinal())
2685+
classDecl->getAttrs().add(new (Impl.SwiftContext)
2686+
FinalAttr(/*IsImplicit=*/true));
2687+
}
2688+
26702689
// If we need it, add an explicit "deinit" to this type.
26712690
synthesizer.addExplicitDeinitIfRequired(result, decl);
26722691

@@ -2712,7 +2731,7 @@ namespace {
27122731
}
27132732
}
27142733

2715-
void validateForeignReferenceType(const clang::CXXRecordDecl *decl,
2734+
void validateForeignReferenceType(const clang::RecordDecl *decl,
27162735
ClassDecl *classDecl) {
27172736

27182737
enum class RetainReleaseOperationKind {
@@ -2764,11 +2783,13 @@ namespace {
27642783
// The parameter of the retain/release function should be pointer to the
27652784
// same FRT or a base FRT.
27662785
if (paramDecl != classDecl) {
2767-
if (const clang::Decl *paramClangDecl = paramDecl->getClangDecl()) {
2768-
if (const auto *paramTypeDecl =
2769-
dyn_cast<clang::CXXRecordDecl>(paramClangDecl)) {
2770-
if (decl->isDerivedFrom(paramTypeDecl)) {
2771-
return RetainReleaseOperationKind::valid;
2786+
if (auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl)) {
2787+
if (const clang::Decl *paramClangDecl = paramDecl->getClangDecl()) {
2788+
if (const auto *paramTypeDecl =
2789+
dyn_cast<clang::CXXRecordDecl>(paramClangDecl)) {
2790+
if (cxxDecl->isDerivedFrom(paramTypeDecl)) {
2791+
return RetainReleaseOperationKind::valid;
2792+
}
27722793
}
27732794
}
27742795
}
@@ -3109,25 +3130,6 @@ namespace {
31093130

31103131
validatePrivateFileIDAttributes(decl);
31113132

3112-
if (auto classDecl = dyn_cast<ClassDecl>(result)) {
3113-
validateForeignReferenceType(decl, classDecl);
3114-
3115-
auto availability = Impl.SwiftContext.getSwift58Availability();
3116-
if (!availability.isAlwaysAvailable()) {
3117-
assert(availability.hasMinimumVersion());
3118-
auto AvAttr = AvailableAttr::createPlatformVersioned(
3119-
Impl.SwiftContext, targetPlatform(Impl.SwiftContext.LangOpts),
3120-
/*Message=*/"", /*Rename=*/"",
3121-
availability.getRawMinimumVersion(), /*Deprecated=*/{},
3122-
/*Obsoleted=*/{});
3123-
classDecl->getAttrs().add(AvAttr);
3124-
}
3125-
3126-
if (decl->isEffectivelyFinal())
3127-
classDecl->getAttrs().add(new (Impl.SwiftContext)
3128-
FinalAttr(/*IsImplicit=*/true));
3129-
}
3130-
31313133
// If this module is declared as a C++ module, try to synthesize
31323134
// conformances to Swift protocols from the Cxx module.
31333135
auto clangModule = Impl.getClangOwningModule(result->getClangNode());
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdlib.h>
2+
3+
struct __attribute__((swift_attr("import_reference")))
4+
__attribute__((swift_attr("retain:nonexistent")))
5+
__attribute__((swift_attr("release:nonexistent"))) NonExistent {
6+
int value;
7+
};
8+
9+
struct __attribute__((swift_attr("import_reference"))) NoRetainRelease {
10+
int value;
11+
};
12+
13+
struct __attribute__((swift_attr("import_reference")))
14+
__attribute__((swift_attr("retain:badRetain")))
15+
__attribute__((swift_attr("release:badRelease"))) BadRetainRelease {
16+
int value;
17+
};
18+
19+
float badRetain(struct BadRetainRelease *v);
20+
void badRelease(struct BadRetainRelease *v, int i);

test/Interop/C/struct/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ module ForeignReference {
77
header "foreign-reference.h"
88
}
99

10+
module ForeignReferenceInvalid {
11+
header "foreign-reference-invalid.h"
12+
}
13+
1014
module StructAsOptionSet {
1115
header "struct-as-option-set.h"
1216
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: not %target-swift-frontend -typecheck %s -I %S/Inputs -disable-availability-checking -diagnostic-style llvm 2>&1 | %FileCheck %s
2+
3+
import ForeignReferenceInvalid
4+
5+
// CHECK: error: cannot find retain function 'nonexistent' for reference type 'NonExistent'
6+
// CHECK: error: cannot find release function 'nonexistent' for reference type 'NonExistent'
7+
public func test(x: NonExistent) { }
8+
9+
// CHECK: error: reference type 'NoRetainRelease' must have 'retain:' Swift attribute
10+
// CHECK: error: reference type 'NoRetainRelease' must have 'release:' Swift attribute
11+
public func test(x: NoRetainRelease) { }
12+
13+
// CHECK: error: specified retain function 'badRetain' is invalid; retain function must either return have 'void', the reference count as an integer, or the parameter type
14+
// CHECK: error: specified release function 'badRelease' is invalid; release function must have exactly one argument of type 'BadRetainRelease'
15+
public func test(x: BadRetainRelease) { }

0 commit comments

Comments
 (0)