Skip to content

Commit 048bcc1

Browse files
authored
Merge pull request #63250 from zoecarver/object-model
2 parents 6f67a3c + d283aa0 commit 048bcc1

File tree

5 files changed

+141
-20
lines changed

5 files changed

+141
-20
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ ERROR(conforms_to_ambiguous,none,
248248
ERROR(conforms_to_not_protocol,none,
249249
"%0 %1 referenced in protocol conformance '%2' is not a protocol", (DescriptiveDeclKind, ValueDecl *, StringRef))
250250

251+
ERROR(move_only_requires_move_only,none,
252+
"use of move-only C++ type '%0' requires -enable-experimental-move-only",
253+
(StringRef))
254+
251255
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))
252256
NOTE(record_field_not_imported, none, "field %0 unavailable (cannot import)", (const clang::NamedDecl*))
253257
NOTE(invoked_func_not_imported, none, "function %0 unavailable (cannot import)", (const clang::NamedDecl*))

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ class ObjCInterfaceAndImplementationRequest
303303
enum class CxxRecordSemanticsKind {
304304
Trivial,
305305
Owned,
306+
MoveOnly,
306307
Reference,
307308
Iterator,
308309
// An API that has be annotated as explicitly unsafe, but still importable.

lib/ClangImporter/ClangImporter.cpp

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6479,13 +6479,7 @@ static bool isSufficientlyTrivial(const clang::CXXRecordDecl *decl) {
64796479

64806480
/// Checks if a record provides the required value type lifetime operations
64816481
/// (copy and destroy).
6482-
static bool hasRequiredValueTypeOperations(const clang::CXXRecordDecl *decl) {
6483-
if (auto dtor = decl->getDestructor()) {
6484-
if (dtor->isDeleted() || dtor->getAccess() != clang::AS_public) {
6485-
return false;
6486-
}
6487-
}
6488-
6482+
static bool hasCopyTypeOperations(const clang::CXXRecordDecl *decl) {
64896483
// If we have no way of copying the type we can't import the class
64906484
// at all because we cannot express the correct semantics as a swift
64916485
// struct.
@@ -6495,9 +6489,35 @@ static bool hasRequiredValueTypeOperations(const clang::CXXRecordDecl *decl) {
64956489
}))
64966490
return false;
64976491

6492+
// TODO: this should probably check to make sure we actually have a copy ctor.
64986493
return true;
64996494
}
65006495

6496+
static bool hasMoveTypeOperations(const clang::CXXRecordDecl *decl) {
6497+
// If we have no way of copying the type we can't import the class
6498+
// at all because we cannot express the correct semantics as a swift
6499+
// struct.
6500+
if (llvm::any_of(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
6501+
return ctor->isMoveConstructor() &&
6502+
(ctor->isDeleted() || ctor->getAccess() != clang::AS_public);
6503+
}))
6504+
return false;
6505+
6506+
return llvm::any_of(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
6507+
return ctor->isMoveConstructor();
6508+
});
6509+
}
6510+
6511+
static bool hasDestroyTypeOperations(const clang::CXXRecordDecl *decl) {
6512+
if (auto dtor = decl->getDestructor()) {
6513+
if (dtor->isDeleted() || dtor->getAccess() != clang::AS_public) {
6514+
return false;
6515+
}
6516+
return true;
6517+
}
6518+
return false;
6519+
}
6520+
65016521
static bool isSwiftClassType(const clang::CXXRecordDecl *decl) {
65026522
// Swift type must be annotated with external_source_symbol attribute.
65036523
auto essAttr = decl->getAttr<clang::ExternalSourceSymbolAttr>();
@@ -6538,7 +6558,8 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
65386558
if (isSwiftClassType(cxxDecl))
65396559
return CxxRecordSemanticsKind::SwiftClassType;
65406560

6541-
if (!hasRequiredValueTypeOperations(cxxDecl)) {
6561+
if (!hasDestroyTypeOperations(cxxDecl) ||
6562+
(!hasCopyTypeOperations(cxxDecl) && !hasMoveTypeOperations(cxxDecl))) {
65426563
if (hasUnsafeAPIAttr(cxxDecl))
65436564
desc.ctx.Diags.diagnose({}, diag::api_pattern_attr_ignored,
65446565
"import_unsafe", decl->getNameAsString());
@@ -6563,16 +6584,26 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
65636584
if (hasIteratorAPIAttr(cxxDecl) || isIterator(cxxDecl)) {
65646585
return CxxRecordSemanticsKind::Iterator;
65656586
}
6566-
6567-
if (hasPointerInSubobjects(cxxDecl)) {
6587+
6588+
if (!cxxDecl->hasUserDeclaredCopyConstructor() &&
6589+
!cxxDecl->hasUserDeclaredMoveConstructor() &&
6590+
hasPointerInSubobjects(cxxDecl)) {
65686591
return CxxRecordSemanticsKind::UnsafePointerMember;
65696592
}
65706593

6594+
if (hasCopyTypeOperations(cxxDecl)) {
6595+
return CxxRecordSemanticsKind::Owned;
6596+
}
6597+
6598+
if (hasMoveTypeOperations(cxxDecl)) {
6599+
return CxxRecordSemanticsKind::MoveOnly;
6600+
}
6601+
65716602
if (isSufficientlyTrivial(cxxDecl)) {
65726603
return CxxRecordSemanticsKind::Trivial;
65736604
}
65746605

6575-
return CxxRecordSemanticsKind::Owned;
6606+
llvm_unreachable("Could not classify C++ type.");
65766607
}
65776608

65786609
ValueDecl *

lib/ClangImporter/ImportDecl.cpp

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,10 +1960,21 @@ namespace {
19601960
!Impl.SwiftContext.LangOpts.CForeignReferenceTypes)
19611961
return false;
19621962

1963+
return decl->hasAttrs() && llvm::any_of(decl->getAttrs(), [](auto *attr) {
1964+
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
1965+
return swiftAttr->getAttribute() == "import_reference" ||
1966+
// TODO: Remove this once libSwift hosttools no longer
1967+
// requires it.
1968+
swiftAttr->getAttribute() == "import_as_ref";
1969+
return false;
1970+
});
1971+
}
1972+
1973+
bool recordHasMoveOnlySemantics(const clang::RecordDecl *decl) {
19631974
auto semanticsKind = evaluateOrDefault(
19641975
Impl.SwiftContext.evaluator,
19651976
CxxRecordSemantics({decl, Impl.SwiftContext}), {});
1966-
return semanticsKind == CxxRecordSemanticsKind::Reference;
1977+
return semanticsKind == CxxRecordSemanticsKind::MoveOnly;
19671978
}
19681979

19691980
Decl *VisitRecordDecl(const clang::RecordDecl *decl) {
@@ -2118,6 +2129,20 @@ namespace {
21182129
decl, AccessLevel::Public, loc, name, loc, None, nullptr, dc);
21192130
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
21202131

2132+
if (recordHasMoveOnlySemantics(decl)) {
2133+
if (!Impl.SwiftContext.LangOpts.hasFeature(Feature::MoveOnly)) {
2134+
Impl.addImportDiagnostic(
2135+
decl, Diagnostic(
2136+
diag::move_only_requires_move_only,
2137+
Impl.SwiftContext.AllocateCopy(decl->getNameAsString())),
2138+
decl->getLocation());
2139+
return nullptr;
2140+
}
2141+
2142+
result->getAttrs().add(new (Impl.SwiftContext)
2143+
MoveOnlyAttr(/*Implicit=*/true));
2144+
}
2145+
21212146
// FIXME: Figure out what to do with superclasses in C++. One possible
21222147
// solution would be to turn them into members and add conversion
21232148
// functions.
@@ -2573,33 +2598,42 @@ namespace {
25732598
// default). Make sure we only do this if the class has been fully defined
25742599
// and we're not in a dependent context (this is equivalent to the logic
25752600
// in CanDeclareSpecialMemberFunction in Clang's SemaLookup.cpp).
2576-
if (decl->getDefinition() && !decl->isBeingDefined() &&
2577-
!decl->isDependentContext()) {
2601+
// TODO: I suspect this if-statement does not need to be here.
2602+
if (!decl->isBeingDefined() && !decl->isDependentContext()) {
25782603
if (decl->needsImplicitDefaultConstructor()) {
25792604
clang::CXXConstructorDecl *ctor =
25802605
clangSema.DeclareImplicitDefaultConstructor(
2581-
const_cast<clang::CXXRecordDecl *>(decl->getDefinition()));
2606+
const_cast<clang::CXXRecordDecl *>(decl));
25822607
if (!ctor->isDeleted())
25832608
clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(),
25842609
ctor);
25852610
}
25862611
clang::CXXConstructorDecl *copyCtor = nullptr;
2612+
clang::CXXConstructorDecl *moveCtor = nullptr;
25872613
if (decl->needsImplicitCopyConstructor()) {
25882614
copyCtor = clangSema.DeclareImplicitCopyConstructor(
25892615
const_cast<clang::CXXRecordDecl *>(decl));
2616+
} else if (decl->needsImplicitMoveConstructor()) {
2617+
moveCtor = clangSema.DeclareImplicitMoveConstructor(
2618+
const_cast<clang::CXXRecordDecl *>(decl));
25902619
} else {
25912620
// We may have a defaulted copy constructor that needs to be defined.
25922621
// Try to find it.
25932622
for (auto methods : decl->methods()) {
25942623
if (auto declCtor = dyn_cast<clang::CXXConstructorDecl>(methods)) {
2595-
if (declCtor->isCopyConstructor() && declCtor->isDefaulted() &&
2624+
if (declCtor->isDefaulted() &&
25962625
declCtor->getAccess() == clang::AS_public &&
25972626
!declCtor->isDeleted() &&
25982627
// Note: we use "doesThisDeclarationHaveABody" here because
25992628
// that's what "DefineImplicitCopyConstructor" checks.
26002629
!declCtor->doesThisDeclarationHaveABody()) {
2601-
copyCtor = declCtor;
2602-
break;
2630+
if (declCtor->isCopyConstructor()) {
2631+
copyCtor = declCtor;
2632+
break;
2633+
} else if (declCtor->isMoveConstructor()) {
2634+
moveCtor = declCtor;
2635+
break;
2636+
}
26032637
}
26042638
}
26052639
}
@@ -2608,14 +2642,27 @@ namespace {
26082642
clangSema.DefineImplicitCopyConstructor(clang::SourceLocation(),
26092643
copyCtor);
26102644
}
2645+
if (moveCtor) {
2646+
clangSema.DefineImplicitMoveConstructor(clang::SourceLocation(),
2647+
moveCtor);
2648+
}
2649+
2650+
if (decl->needsImplicitDestructor()) {
2651+
auto dtor = clangSema.DeclareImplicitDestructor(
2652+
const_cast<clang::CXXRecordDecl *>(decl));
2653+
clangSema.DefineImplicitDestructor(clang::SourceLocation(), dtor);
2654+
}
26112655
}
26122656

26132657
// It is import that we bail on an unimportable record *before* we import
26142658
// any of its members or cache the decl.
26152659
auto semanticsKind =
26162660
evaluateOrDefault(Impl.SwiftContext.evaluator,
26172661
CxxRecordSemantics({decl, Impl.SwiftContext}), {});
2618-
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation) {
2662+
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation &&
2663+
// Let un-specialized class templates through. We'll sort out their
2664+
// members once they're instranciated.
2665+
!Impl.importSymbolicCXXDecls) {
26192666
Impl.addImportDiagnostic(
26202667
decl,
26212668
Diagnostic(diag::record_not_automatically_importable,

lib/IRGen/GenStruct.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,28 @@ namespace {
556556
return nullptr;
557557
for (auto method : cxxRecordDecl->methods()) {
558558
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(method)) {
559-
if (ctor->isCopyConstructor())
559+
if (ctor->isCopyConstructor() &&
560+
ctor->getAccess() == clang::AS_public &&
561+
// rdar://106964356
562+
// ctor->doesThisDeclarationHaveABody() &&
563+
!ctor->isDeleted())
564+
return ctor;
565+
}
566+
}
567+
return nullptr;
568+
}
569+
570+
const clang::CXXConstructorDecl *findMoveConstructor() const {
571+
const clang::CXXRecordDecl *cxxRecordDecl =
572+
dyn_cast<clang::CXXRecordDecl>(ClangDecl);
573+
if (!cxxRecordDecl)
574+
return nullptr;
575+
for (auto method : cxxRecordDecl->methods()) {
576+
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(method)) {
577+
if (ctor->isMoveConstructor() &&
578+
ctor->getAccess() == clang::AS_public &&
579+
ctor->doesThisDeclarationHaveABody() &&
580+
!ctor->isDeleted())
560581
return ctor;
561582
}
562583
}
@@ -785,6 +806,14 @@ namespace {
785806

786807
void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
787808
SILType T, bool isOutlined) const override {
809+
if (auto moveConstructor = findMoveConstructor()) {
810+
emitCopyWithCopyConstructor(IGF, T, moveConstructor,
811+
src.getAddress(),
812+
dest.getAddress());
813+
destroy(IGF, src, T, isOutlined);
814+
return;
815+
}
816+
788817
if (auto copyConstructor = findCopyConstructor()) {
789818
emitCopyWithCopyConstructor(IGF, T, copyConstructor,
790819
src.getAddress(),
@@ -800,6 +829,15 @@ namespace {
800829

801830
void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T,
802831
bool isOutlined) const override {
832+
if (auto moveConstructor = findMoveConstructor()) {
833+
destroy(IGF, dest, T, isOutlined);
834+
emitCopyWithCopyConstructor(IGF, T, moveConstructor,
835+
src.getAddress(),
836+
dest.getAddress());
837+
destroy(IGF, src, T, isOutlined);
838+
return;
839+
}
840+
803841
if (auto copyConstructor = findCopyConstructor()) {
804842
destroy(IGF, dest, T, isOutlined);
805843
emitCopyWithCopyConstructor(IGF, T, copyConstructor,

0 commit comments

Comments
 (0)