Skip to content

Commit bbd60c8

Browse files
author
Gabor Horvath
committed
[cxx-interop] Fix circular reference, remove feature flag check
It turns out the query to check the reference semantics of a type had the side effect of importing some functions/types. This could introduce circular reference errors with our queries. This PR removes this side effect from the query and updates the test files. Since we do the same work later on in another query, the main change is just the wording of the diagnostics (and we now can also infer immortal references based on the base types). This PR also reorders some operations, specifically now we mark base classes as imported before we attempt to import template arguments. After these changes it is possible to remove the last feature check for strict memory safe mode. We want to mark types as @unsafe in both language modes so we can diagnose redundant unsafe markers even when the feature is off.
1 parent fcc367a commit bbd60c8

File tree

4 files changed

+52
-63
lines changed

4 files changed

+52
-63
lines changed

lib/ClangImporter/ClangImporter.cpp

+9-15
Original file line numberDiff line numberDiff line change
@@ -7792,7 +7792,7 @@ getRefParentOrDiag(const clang::RecordDecl *decl, ASTContext &ctx,
77927792
if (refParentDecls.empty())
77937793
return nullptr;
77947794

7795-
std::unordered_set<ValueDecl *> uniqueRetainDecls{}, uniqueReleaseDecls{};
7795+
std::set<StringRef> uniqueRetainDecls{}, uniqueReleaseDecls{};
77967796
constexpr StringRef retainPrefix = "retain:";
77977797
constexpr StringRef releasePrefix = "release:";
77987798

@@ -7801,16 +7801,10 @@ getRefParentOrDiag(const clang::RecordDecl *decl, ASTContext &ctx,
78017801
for (const auto *attr : refParentDecl->getAttrs()) {
78027802
if (const auto swiftAttr = llvm::dyn_cast<clang::SwiftAttrAttr>(attr)) {
78037803
const auto &attribute = swiftAttr->getAttribute();
7804-
llvm::SmallVector<ValueDecl *, 1> valueDecls;
7805-
if (attribute.starts_with(retainPrefix)) {
7806-
auto name = attribute.drop_front(retainPrefix.size()).str();
7807-
valueDecls = getValueDeclsForName(decl, ctx, name);
7808-
uniqueRetainDecls.insert(valueDecls.begin(), valueDecls.end());
7809-
} else if (attribute.starts_with(releasePrefix)) {
7810-
auto name = attribute.drop_front(releasePrefix.size()).str();
7811-
valueDecls = getValueDeclsForName(decl, ctx, name);
7812-
uniqueReleaseDecls.insert(valueDecls.begin(), valueDecls.end());
7813-
}
7804+
if (attribute.starts_with(retainPrefix))
7805+
uniqueRetainDecls.insert(attribute.drop_front(retainPrefix.size()));
7806+
else if (attribute.starts_with(releasePrefix))
7807+
uniqueReleaseDecls.insert(attribute.drop_front(releasePrefix.size()));
78147808
}
78157809
}
78167810
}
@@ -8175,7 +8169,7 @@ CxxRecordAsSwiftType::evaluate(Evaluator &evaluator,
81758169
return nullptr;
81768170
}
81778171

8178-
bool anySubobjectsSelfContained(const clang::CXXRecordDecl *decl) {
8172+
static bool anySubobjectsSelfContained(const clang::CXXRecordDecl *decl) {
81798173
// std::pair and std::tuple might have copy and move constructors, or base
81808174
// classes with copy and move constructors, but they are not self-contained
81818175
// types, e.g. `std::pair<UnsafeType, T>`.
@@ -8339,11 +8333,11 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate(
83398333
}
83408334
}
83418335

8342-
if (retainReleaseAttrs.empty()) {
8336+
if (retainReleaseAttrs.empty())
83438337
return {CustomRefCountingOperationResult::noAttribute, nullptr, ""};
8344-
} else if (retainReleaseAttrs.size() > 1) {
8338+
8339+
if (retainReleaseAttrs.size() > 1)
83458340
return {CustomRefCountingOperationResult::tooManyAttributes, nullptr, ""};
8346-
}
83478341

83488342
auto name = retainReleaseAttrs.front()
83498343
->getAttribute()

lib/ClangImporter/ImportDecl.cpp

+39-43
Original file line numberDiff line numberDiff line change
@@ -2197,38 +2197,6 @@ namespace {
21972197
loc, std::nullopt, nullptr, dc);
21982198
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
21992199

2200-
// We have to do this after populating ImportedDecls to avoid importing
2201-
// the same multiple times.
2202-
if (Impl.SwiftContext.LangOpts.hasFeature(
2203-
Feature::StrictMemorySafety)) {
2204-
if (const auto *ctsd =
2205-
dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
2206-
for (auto arg : ctsd->getTemplateArgs().asArray()) {
2207-
llvm::SmallVector<clang::TemplateArgument, 1> nonPackArgs;
2208-
if (arg.getKind() == clang::TemplateArgument::Pack) {
2209-
auto pack = arg.getPackAsArray();
2210-
nonPackArgs.assign(pack.begin(), pack.end());
2211-
} else {
2212-
nonPackArgs.push_back(arg);
2213-
}
2214-
for (auto realArg : nonPackArgs) {
2215-
if (realArg.getKind() != clang::TemplateArgument::Type)
2216-
continue;
2217-
auto SwiftType = Impl.importTypeIgnoreIUO(
2218-
realArg.getAsType(), ImportTypeKind::Abstract,
2219-
[](Diagnostic &&diag) {}, false, Bridgeability::None,
2220-
ImportTypeAttrs());
2221-
if (SwiftType && SwiftType->isUnsafe()) {
2222-
auto attr =
2223-
new (Impl.SwiftContext) UnsafeAttr(/*implicit=*/true);
2224-
result->getAttrs().add(attr);
2225-
break;
2226-
}
2227-
}
2228-
}
2229-
}
2230-
}
2231-
22322200
if (recordHasMoveOnlySemantics(decl)) {
22332201
if (decl->isInStdNamespace() && decl->getName() == "promise") {
22342202
// Do not import std::promise.
@@ -2238,16 +2206,6 @@ namespace {
22382206
MoveOnlyAttr(/*Implicit=*/true));
22392207
}
22402208

2241-
bool isNonEscapable = false;
2242-
if (evaluateOrDefault(
2243-
Impl.SwiftContext.evaluator,
2244-
ClangTypeEscapability({decl->getTypeForDecl(), &Impl}),
2245-
CxxEscapability::Unknown) == CxxEscapability::NonEscapable) {
2246-
result->getAttrs().add(new (Impl.SwiftContext)
2247-
NonEscapableAttr(/*Implicit=*/true));
2248-
isNonEscapable = true;
2249-
}
2250-
22512209
// FIXME: Figure out what to do with superclasses in C++. One possible
22522210
// solution would be to turn them into members and add conversion
22532211
// functions.
@@ -2259,6 +2217,44 @@ namespace {
22592217
}
22602218
}
22612219

2220+
// We have to do this after populating ImportedDecls to avoid importing
2221+
// the same decl multiple times. Also after we imported the bases.
2222+
if (const auto *ctsd =
2223+
dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
2224+
for (auto arg : ctsd->getTemplateArgs().asArray()) {
2225+
llvm::SmallVector<clang::TemplateArgument, 1> nonPackArgs;
2226+
if (arg.getKind() == clang::TemplateArgument::Pack) {
2227+
auto pack = arg.getPackAsArray();
2228+
nonPackArgs.assign(pack.begin(), pack.end());
2229+
} else {
2230+
nonPackArgs.push_back(arg);
2231+
}
2232+
for (auto realArg : nonPackArgs) {
2233+
if (realArg.getKind() != clang::TemplateArgument::Type)
2234+
continue;
2235+
auto SwiftType = Impl.importTypeIgnoreIUO(
2236+
realArg.getAsType(), ImportTypeKind::Abstract,
2237+
[](Diagnostic &&diag) {}, false, Bridgeability::None,
2238+
ImportTypeAttrs());
2239+
if (SwiftType && SwiftType->isUnsafe()) {
2240+
auto attr = new (Impl.SwiftContext) UnsafeAttr(/*implicit=*/true);
2241+
result->getAttrs().add(attr);
2242+
break;
2243+
}
2244+
}
2245+
}
2246+
}
2247+
2248+
bool isNonEscapable = false;
2249+
if (evaluateOrDefault(
2250+
Impl.SwiftContext.evaluator,
2251+
ClangTypeEscapability({decl->getTypeForDecl(), &Impl}),
2252+
CxxEscapability::Unknown) == CxxEscapability::NonEscapable) {
2253+
result->getAttrs().add(new (Impl.SwiftContext)
2254+
NonEscapableAttr(/*Implicit=*/true));
2255+
isNonEscapable = true;
2256+
}
2257+
22622258
// Import each of the members.
22632259
SmallVector<VarDecl *, 4> members;
22642260
SmallVector<FuncDecl *, 4> methods;
@@ -2965,7 +2961,7 @@ namespace {
29652961
}
29662962
}
29672963

2968-
// It is import that we bail on an unimportable record *before* we import
2964+
// It is important that we bail on an unimportable record *before* we import
29692965
// any of its members or cache the decl.
29702966
auto semanticsKind = evaluateOrDefault(
29712967
Impl.SwiftContext.evaluator,

test/Interop/Cxx/foreign-reference/Inputs/inheritance.h

+3-4
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ __attribute__((swift_attr("release:immortal"))) ImmortalRefType {};
8080

8181
ImmortalRefType *returnImmortalRefType() { return new ImmortalRefType(); };
8282

83-
// Doubt: Is it fine to not infer in the case of SWIFT_IMMORTAL_REFERENCE
84-
// rdar://145193396
85-
struct DerivedFromImmortalRefType : ImmortalRefType {}; // expected-warning {{unable to infer SWIFT_SHARED_REFERENCE for 'DerivedFromImmortalRefType', although one of its transitive base types is marked as SWIFT_SHARED_REFERENCE}}
83+
struct DerivedFromImmortalRefType : ImmortalRefType {};
8684
DerivedFromImmortalRefType *returnDerivedFromImmortalRefType() {
8785
return new DerivedFromImmortalRefType();
8886
};
@@ -284,7 +282,8 @@ __attribute__((swift_attr("retain:sameretain")))
284282
__attribute__((swift_attr("release:samerelease"))) B2 {}; // expected-error {{multiple functions 'sameretain' found; there must be exactly one retain function for reference type 'B2'}}
285283
// expected-error@-1 {{multiple functions 'samerelease' found; there must be exactly one release function for reference type 'B2'}}
286284

287-
struct D : B1, B2 {}; // expected-warning {{unable to infer SWIFT_SHARED_REFERENCE for 'D', although one of its transitive base types is marked as SWIFT_SHARED_REFERENCE}}
285+
struct D : B1, B2 {}; // expected-error {{multiple functions 'sameretain' found; there must be exactly one retain function for reference type 'D'}}
286+
// expected-error@-1 {{multiple functions 'samerelease' found; there must be exactly one release function for reference type 'D'}}
288287
D *returnD() { return new D(); };
289288
} // namespace OverloadedRetainRelease
290289

test/Interop/Cxx/foreign-reference/inheritance.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ FrtInheritanceTestSuite.test("ParentChild") {
5050

5151
let derivedFromImmortalRefType = ImmortalRefereceExample.returnDerivedFromImmortalRefType()
5252
expectTrue(
53-
!(type(of: derivedFromImmortalRefType) is AnyObject.Type),
53+
type(of: derivedFromImmortalRefType) is AnyObject.Type,
5454
"Expected derivedFromImmortalRefType to be a value type, but it’s a reference type")
5555

5656
let valType = ExplicitAnnotationHasPrecedence1.returnValueType()

0 commit comments

Comments
 (0)