mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[cxx-interop] Refactor copyability out of CxxRecordSemantics
This commit is contained in:
@@ -342,15 +342,9 @@ private:
|
||||
};
|
||||
|
||||
enum class CxxRecordSemanticsKind {
|
||||
Trivial,
|
||||
Owned,
|
||||
MoveOnly,
|
||||
Value,
|
||||
Reference,
|
||||
Iterator,
|
||||
// A record that is either not copyable/movable or not destructible.
|
||||
MissingLifetimeOperation,
|
||||
// A record that has no copy and no move operations
|
||||
UnavailableConstructors,
|
||||
// A C++ record that represents a Swift class type exposed to C++ from Swift.
|
||||
SwiftClassType
|
||||
};
|
||||
@@ -576,6 +570,59 @@ private:
|
||||
void simple_display(llvm::raw_ostream &out, EscapabilityLookupDescriptor desc);
|
||||
SourceLoc extractNearestSourceLoc(EscapabilityLookupDescriptor desc);
|
||||
|
||||
// Swift value semantics of C++ types
|
||||
// These are usually equivalent, with the exception of references.
|
||||
// When a reference type is copied, the pointer’s value is copied rather than
|
||||
// the object’s storage. This means reference types can be imported as
|
||||
// copyable to Swift, even when they are non-copyable in C++.
|
||||
enum class CxxValueSemanticsKind {
|
||||
Copyable,
|
||||
MoveOnly,
|
||||
// A record that is either not copyable/movable or not destructible.
|
||||
MissingLifetimeOperation,
|
||||
// A record that has no copy and no move operations
|
||||
UnavailableConstructors,
|
||||
};
|
||||
|
||||
struct CxxValueSemanticsDescriptor final {
|
||||
const clang::Type *type;
|
||||
ClangImporter::Implementation *importerImpl;
|
||||
|
||||
friend llvm::hash_code hash_value(const CxxValueSemanticsDescriptor &desc) {
|
||||
return llvm::hash_combine(desc.type);
|
||||
}
|
||||
|
||||
friend bool operator==(const CxxValueSemanticsDescriptor &lhs,
|
||||
const CxxValueSemanticsDescriptor &rhs) {
|
||||
return lhs.type == rhs.type;
|
||||
}
|
||||
|
||||
friend bool operator!=(const CxxValueSemanticsDescriptor &lhs,
|
||||
const CxxValueSemanticsDescriptor &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
class CxxValueSemantics
|
||||
: public SimpleRequest<CxxValueSemantics,
|
||||
CxxValueSemanticsKind(
|
||||
CxxValueSemanticsDescriptor),
|
||||
RequestFlags::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
|
||||
bool isCached() const { return true; }
|
||||
|
||||
private:
|
||||
friend SimpleRequest;
|
||||
|
||||
CxxValueSemanticsKind evaluate(Evaluator &evaluator,
|
||||
CxxValueSemanticsDescriptor desc) const;
|
||||
};
|
||||
|
||||
void simple_display(llvm::raw_ostream &out, CxxValueSemanticsDescriptor desc);
|
||||
SourceLoc extractNearestSourceLoc(CxxValueSemanticsDescriptor desc);
|
||||
|
||||
struct CxxDeclExplicitSafetyDescriptor final {
|
||||
const clang::Decl *decl;
|
||||
bool isClass;
|
||||
|
||||
@@ -45,6 +45,9 @@ SWIFT_REQUEST(ClangImporter, CustomRefCountingOperation,
|
||||
SWIFT_REQUEST(ClangImporter, ClangTypeEscapability,
|
||||
CxxEscapability(EscapabilityLookupDescriptor), Cached,
|
||||
NoLocationInfo)
|
||||
SWIFT_REQUEST(ClangImporter, CxxValueSemantics,
|
||||
CxxValueSemanticsKind(CxxValueSemanticsDescriptor), Cached,
|
||||
NoLocationInfo)
|
||||
SWIFT_REQUEST(ClangImporter, ClangDeclExplicitSafety,
|
||||
ExplicitSafety(CxxDeclExplicitSafetyDescriptor), Cached,
|
||||
NoLocationInfo)
|
||||
|
||||
@@ -8094,85 +8094,10 @@ bool importer::isViewType(const clang::CXXRecordDecl *decl) {
|
||||
return !hasOwnedValueAttr(decl) && hasPointerInSubobjects(decl);
|
||||
}
|
||||
|
||||
static bool copyConstructorIsDefaulted(const clang::CXXRecordDecl *decl) {
|
||||
auto ctor = llvm::find_if(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
|
||||
return ctor->isCopyConstructor();
|
||||
});
|
||||
|
||||
assert(ctor != decl->ctor_end());
|
||||
return ctor->isDefaulted();
|
||||
}
|
||||
|
||||
static bool copyAssignOperatorIsDefaulted(const clang::CXXRecordDecl *decl) {
|
||||
auto copyAssignOp = llvm::find_if(decl->decls(), [](clang::Decl *member) {
|
||||
if (auto method = dyn_cast<clang::CXXMethodDecl>(member))
|
||||
return method->isCopyAssignmentOperator();
|
||||
return false;
|
||||
});
|
||||
|
||||
assert(copyAssignOp != decl->decls_end());
|
||||
return cast<clang::CXXMethodDecl>(*copyAssignOp)->isDefaulted();
|
||||
}
|
||||
|
||||
/// Recursively checks that there are no user-provided copy constructors or
|
||||
/// destructors in any fields or base classes.
|
||||
/// Does not check C++ records with specific API annotations.
|
||||
static bool isSufficientlyTrivial(const clang::CXXRecordDecl *decl) {
|
||||
// Probably a class template that has not yet been specialized:
|
||||
if (!decl->getDefinition())
|
||||
return true;
|
||||
|
||||
if ((decl->hasUserDeclaredCopyConstructor() &&
|
||||
!copyConstructorIsDefaulted(decl)) ||
|
||||
(decl->hasUserDeclaredCopyAssignment() &&
|
||||
!copyAssignOperatorIsDefaulted(decl)) ||
|
||||
(decl->hasUserDeclaredDestructor() && decl->getDestructor() &&
|
||||
!decl->getDestructor()->isDefaulted()))
|
||||
return false;
|
||||
|
||||
auto checkType = [](clang::QualType t) {
|
||||
if (auto recordType = dyn_cast<clang::RecordType>(t.getCanonicalType())) {
|
||||
if (auto cxxRecord =
|
||||
dyn_cast<clang::CXXRecordDecl>(recordType->getDecl())) {
|
||||
if (hasImportAsRefAttr(cxxRecord) || hasOwnedValueAttr(cxxRecord) ||
|
||||
hasUnsafeAPIAttr(cxxRecord))
|
||||
return true;
|
||||
|
||||
if (!isSufficientlyTrivial(cxxRecord))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
for (auto field : decl->fields()) {
|
||||
if (!checkType(field->getType()))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto base : decl->bases()) {
|
||||
if (!checkType(base.getType()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Checks if a record provides the required value type lifetime operations
|
||||
/// (copy and destroy).
|
||||
static bool hasCopyTypeOperations(const clang::CXXRecordDecl *decl) {
|
||||
// Hack for a base type of std::optional from the Microsoft standard library.
|
||||
if (decl->isInStdNamespace() && decl->getIdentifier() &&
|
||||
decl->getName() == "_Optional_construct_base")
|
||||
return true;
|
||||
|
||||
if (decl->hasSimpleCopyConstructor())
|
||||
return true;
|
||||
|
||||
// If we have no way of copying the type we can't import the class
|
||||
// at all because we cannot express the correct semantics as a swift
|
||||
// struct.
|
||||
return llvm::any_of(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
|
||||
return ctor->isCopyConstructor() && !ctor->isDeleted() &&
|
||||
!ctor->isIneligibleOrNotSelected() &&
|
||||
@@ -8183,12 +8108,10 @@ static bool hasCopyTypeOperations(const clang::CXXRecordDecl *decl) {
|
||||
}
|
||||
|
||||
static bool hasMoveTypeOperations(const clang::CXXRecordDecl *decl) {
|
||||
// If we have no way of copying the type we can't import the class
|
||||
// at all because we cannot express the correct semantics as a swift
|
||||
// struct.
|
||||
if (llvm::any_of(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
|
||||
return ctor->isMoveConstructor() &&
|
||||
(ctor->isDeleted() || ctor->getAccess() != clang::AS_public);
|
||||
(ctor->isDeleted() || ctor->isIneligibleOrNotSelected() ||
|
||||
ctor->getAccess() != clang::AS_public);
|
||||
}))
|
||||
return false;
|
||||
|
||||
@@ -8201,7 +8124,8 @@ static bool hasMoveTypeOperations(const clang::CXXRecordDecl *decl) {
|
||||
|
||||
static bool hasDestroyTypeOperations(const clang::CXXRecordDecl *decl) {
|
||||
if (auto dtor = decl->getDestructor()) {
|
||||
if (dtor->isDeleted() || dtor->getAccess() != clang::AS_public) {
|
||||
if (dtor->isDeleted() || dtor->isIneligibleOrNotSelected() ||
|
||||
dtor->getAccess() != clang::AS_public) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -8257,49 +8181,17 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
|
||||
|
||||
auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
|
||||
if (!cxxDecl) {
|
||||
if (hasNonCopyableAttr(decl))
|
||||
return CxxRecordSemanticsKind::MoveOnly;
|
||||
|
||||
return CxxRecordSemanticsKind::Trivial;
|
||||
return CxxRecordSemanticsKind::Value;
|
||||
}
|
||||
|
||||
if (isSwiftClassType(cxxDecl))
|
||||
return CxxRecordSemanticsKind::SwiftClassType;
|
||||
|
||||
if (!hasDestroyTypeOperations(cxxDecl) ||
|
||||
(!hasCopyTypeOperations(cxxDecl) && !hasMoveTypeOperations(cxxDecl))) {
|
||||
|
||||
if (hasConstructorWithUnsupportedDefaultArgs(cxxDecl))
|
||||
return CxxRecordSemanticsKind::UnavailableConstructors;
|
||||
|
||||
return CxxRecordSemanticsKind::MissingLifetimeOperation;
|
||||
}
|
||||
|
||||
if (hasNonCopyableAttr(cxxDecl) && hasMoveTypeOperations(cxxDecl)) {
|
||||
return CxxRecordSemanticsKind::MoveOnly;
|
||||
}
|
||||
|
||||
if (hasOwnedValueAttr(cxxDecl)) {
|
||||
return CxxRecordSemanticsKind::Owned;
|
||||
}
|
||||
|
||||
if (hasIteratorAPIAttr(cxxDecl) || isIterator(cxxDecl)) {
|
||||
return CxxRecordSemanticsKind::Iterator;
|
||||
}
|
||||
|
||||
if (hasCopyTypeOperations(cxxDecl)) {
|
||||
return CxxRecordSemanticsKind::Owned;
|
||||
}
|
||||
|
||||
if (hasMoveTypeOperations(cxxDecl)) {
|
||||
return CxxRecordSemanticsKind::MoveOnly;
|
||||
}
|
||||
|
||||
if (isSufficientlyTrivial(cxxDecl)) {
|
||||
return CxxRecordSemanticsKind::Trivial;
|
||||
}
|
||||
|
||||
llvm_unreachable("Could not classify C++ type.");
|
||||
return CxxRecordSemanticsKind::Value;
|
||||
}
|
||||
|
||||
ValueDecl *
|
||||
@@ -8330,6 +8222,74 @@ CxxRecordAsSwiftType::evaluate(Evaluator &evaluator,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CxxValueSemanticsKind
|
||||
CxxValueSemantics::evaluate(Evaluator &evaluator,
|
||||
CxxValueSemanticsDescriptor desc) const {
|
||||
|
||||
const auto *type = desc.type;
|
||||
|
||||
auto desugared = type->getUnqualifiedDesugaredType();
|
||||
const auto *recordType = desugared->getAs<clang::RecordType>();
|
||||
if (!recordType)
|
||||
return CxxValueSemanticsKind::Copyable;
|
||||
|
||||
auto recordDecl = recordType->getDecl();
|
||||
|
||||
// When a reference type is copied, the pointer’s value is copied rather than
|
||||
// the object’s storage. This means reference types can be imported as
|
||||
// copyable to Swift, even when they are non-copyable in C++.
|
||||
if (recordHasReferenceSemantics(recordDecl, desc.importerImpl))
|
||||
return CxxValueSemanticsKind::Copyable;
|
||||
|
||||
if (recordDecl->isInStdNamespace()) {
|
||||
// Hack for a base type of std::optional from the Microsoft standard
|
||||
// library.
|
||||
if (recordDecl->getIdentifier() &&
|
||||
recordDecl->getName() == "_Optional_construct_base")
|
||||
return CxxValueSemanticsKind::Copyable;
|
||||
}
|
||||
|
||||
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
|
||||
if (!cxxRecordDecl) {
|
||||
if (hasNonCopyableAttr(recordDecl))
|
||||
return CxxValueSemanticsKind::MoveOnly;
|
||||
return CxxValueSemanticsKind::Copyable;
|
||||
}
|
||||
|
||||
bool isCopyable = hasCopyTypeOperations(cxxRecordDecl);
|
||||
bool isMovable = hasMoveTypeOperations(cxxRecordDecl);
|
||||
|
||||
if (!hasDestroyTypeOperations(cxxRecordDecl) || (!isCopyable && !isMovable)) {
|
||||
|
||||
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
|
||||
return CxxValueSemanticsKind::UnavailableConstructors;
|
||||
|
||||
return CxxValueSemanticsKind::MissingLifetimeOperation;
|
||||
}
|
||||
|
||||
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
|
||||
return CxxValueSemanticsKind::MoveOnly;
|
||||
|
||||
if (isCopyable)
|
||||
return CxxValueSemanticsKind::Copyable;
|
||||
|
||||
if (isMovable)
|
||||
return CxxValueSemanticsKind::MoveOnly;
|
||||
|
||||
llvm_unreachable("Could not classify C++ type.");
|
||||
}
|
||||
|
||||
void swift::simple_display(llvm::raw_ostream &out,
|
||||
CxxValueSemanticsDescriptor desc) {
|
||||
out << "Checking if '";
|
||||
out << clang::QualType(desc.type, 0).getAsString();
|
||||
out << "' is copyable or movable.";
|
||||
}
|
||||
|
||||
SourceLoc swift::extractNearestSourceLoc(CxxValueSemanticsDescriptor) {
|
||||
return SourceLoc();
|
||||
}
|
||||
|
||||
static bool anySubobjectsSelfContained(const clang::CXXRecordDecl *decl) {
|
||||
// std::pair and std::tuple might have copy and move constructors, or base
|
||||
// classes with copy and move constructors, but they are not self-contained
|
||||
|
||||
@@ -2080,8 +2080,8 @@ namespace {
|
||||
bool recordHasMoveOnlySemantics(const clang::RecordDecl *decl) {
|
||||
auto semanticsKind = evaluateOrDefault(
|
||||
Impl.SwiftContext.evaluator,
|
||||
CxxRecordSemantics({decl, Impl.SwiftContext, &Impl}), {});
|
||||
return semanticsKind == CxxRecordSemanticsKind::MoveOnly;
|
||||
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
|
||||
return semanticsKind == CxxValueSemanticsKind::MoveOnly;
|
||||
}
|
||||
|
||||
void markReturnsUnsafeNonescapable(AbstractFunctionDecl *fd) {
|
||||
@@ -3144,11 +3144,11 @@ namespace {
|
||||
|
||||
// It is important that we bail on an unimportable record *before* we import
|
||||
// any of its members or cache the decl.
|
||||
auto semanticsKind = evaluateOrDefault(
|
||||
auto valueSemanticsKind = evaluateOrDefault(
|
||||
Impl.SwiftContext.evaluator,
|
||||
CxxRecordSemantics({decl, Impl.SwiftContext, &Impl}), {});
|
||||
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation ||
|
||||
semanticsKind == CxxRecordSemanticsKind::UnavailableConstructors) {
|
||||
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
|
||||
if (valueSemanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation ||
|
||||
valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
|
||||
|
||||
HeaderLoc loc(decl->getLocation());
|
||||
if (hasUnsafeAPIAttr(decl))
|
||||
@@ -3161,7 +3161,7 @@ namespace {
|
||||
Impl.diagnose(loc, diag::api_pattern_attr_ignored, "import_iterator",
|
||||
decl->getNameAsString());
|
||||
|
||||
if (semanticsKind == CxxRecordSemanticsKind::UnavailableConstructors) {
|
||||
if (valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
|
||||
Impl.addImportDiagnostic(
|
||||
decl, Diagnostic(diag::record_unsupported_default_args),
|
||||
decl->getLocation());
|
||||
@@ -3175,7 +3175,12 @@ namespace {
|
||||
decl->getLocation());
|
||||
return nullptr;
|
||||
}
|
||||
if (semanticsKind == CxxRecordSemanticsKind::SwiftClassType) {
|
||||
|
||||
auto cxxRecordsemanticsKind = evaluateOrDefault(
|
||||
Impl.SwiftContext.evaluator,
|
||||
CxxRecordSemantics({decl, Impl.SwiftContext, &Impl}), {});
|
||||
|
||||
if (cxxRecordsemanticsKind == CxxRecordSemanticsKind::SwiftClassType) {
|
||||
// FIXME: add a diagnostic here for unsupported imported use of Swift
|
||||
// type?
|
||||
return nullptr;
|
||||
@@ -3411,8 +3416,8 @@ namespace {
|
||||
decl->getAnonField()->getParent())) {
|
||||
auto semanticsKind = evaluateOrDefault(
|
||||
Impl.SwiftContext.evaluator,
|
||||
CxxRecordSemantics({parent, Impl.SwiftContext, &Impl}), {});
|
||||
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation)
|
||||
CxxValueSemantics({parent->getTypeForDecl(), &Impl}), {});
|
||||
if (semanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -2864,6 +2864,71 @@ static void markDeprecated(Decl *decl, llvm::Twine message) {
|
||||
ctx, ctx.AllocateCopy(message.str())));
|
||||
}
|
||||
|
||||
static bool copyConstructorIsDefaulted(const clang::CXXRecordDecl *decl) {
|
||||
auto ctor = llvm::find_if(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
|
||||
return ctor->isCopyConstructor();
|
||||
});
|
||||
|
||||
assert(ctor != decl->ctor_end());
|
||||
return ctor->isDefaulted();
|
||||
}
|
||||
|
||||
static bool copyAssignOperatorIsDefaulted(const clang::CXXRecordDecl *decl) {
|
||||
auto copyAssignOp = llvm::find_if(decl->decls(), [](clang::Decl *member) {
|
||||
if (auto method = dyn_cast<clang::CXXMethodDecl>(member))
|
||||
return method->isCopyAssignmentOperator();
|
||||
return false;
|
||||
});
|
||||
|
||||
assert(copyAssignOp != decl->decls_end());
|
||||
return cast<clang::CXXMethodDecl>(*copyAssignOp)->isDefaulted();
|
||||
}
|
||||
|
||||
/// Recursively checks that there are no user-provided copy constructors or
|
||||
/// destructors in any fields or base classes.
|
||||
/// Does not check C++ records with specific API annotations.
|
||||
static bool isSufficientlyTrivial(const clang::CXXRecordDecl *decl) {
|
||||
// Probably a class template that has not yet been specialized:
|
||||
if (!decl->getDefinition())
|
||||
return true;
|
||||
|
||||
if ((decl->hasUserDeclaredCopyConstructor() &&
|
||||
!copyConstructorIsDefaulted(decl)) ||
|
||||
(decl->hasUserDeclaredCopyAssignment() &&
|
||||
!copyAssignOperatorIsDefaulted(decl)) ||
|
||||
(decl->hasUserDeclaredDestructor() && decl->getDestructor() &&
|
||||
!decl->getDestructor()->isDefaulted()))
|
||||
return false;
|
||||
|
||||
auto checkType = [](clang::QualType t) {
|
||||
if (auto recordType = dyn_cast<clang::RecordType>(t.getCanonicalType())) {
|
||||
if (auto cxxRecord =
|
||||
dyn_cast<clang::CXXRecordDecl>(recordType->getDecl())) {
|
||||
if (hasImportAsRefAttr(cxxRecord) || hasOwnedValueAttr(cxxRecord) ||
|
||||
hasUnsafeAPIAttr(cxxRecord))
|
||||
return true;
|
||||
|
||||
if (!isSufficientlyTrivial(cxxRecord))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
for (auto field : decl->fields()) {
|
||||
if (!checkType(field->getType()))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto base : decl->bases()) {
|
||||
if (!checkType(base.getType()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Find an explicitly-provided "destroy" operation specified for the
|
||||
/// given Clang type and return it.
|
||||
FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy(
|
||||
@@ -2943,14 +3008,23 @@ FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy(
|
||||
// If this type isn't imported as noncopyable, we can't respect the request
|
||||
// for a destroy operation.
|
||||
ASTContext &ctx = ImporterImpl.SwiftContext;
|
||||
auto semanticsKind = evaluateOrDefault(
|
||||
ctx.evaluator,
|
||||
CxxRecordSemantics({clangType, ctx, &ImporterImpl}), {});
|
||||
switch (semanticsKind) {
|
||||
case CxxRecordSemanticsKind::Owned:
|
||||
auto valueSemanticsKind = evaluateOrDefault(
|
||||
ctx.evaluator,
|
||||
CxxValueSemantics({clangType->getTypeForDecl(), &ImporterImpl}), {});
|
||||
|
||||
if (valueSemanticsKind == CxxValueSemanticsKind::MoveOnly)
|
||||
return destroyFunc;
|
||||
|
||||
if (valueSemanticsKind != CxxValueSemanticsKind::Copyable)
|
||||
return nullptr;
|
||||
|
||||
auto cxxRecordSemanticsKind = evaluateOrDefault(
|
||||
ctx.evaluator, CxxRecordSemantics({clangType, ctx, &ImporterImpl}), {});
|
||||
switch (cxxRecordSemanticsKind) {
|
||||
case CxxRecordSemanticsKind::Value:
|
||||
case CxxRecordSemanticsKind::Reference:
|
||||
if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(clangType)) {
|
||||
if (!cxxRecord->hasTrivialDestructor()) {
|
||||
if (!isSufficientlyTrivial(cxxRecord)) {
|
||||
markDeprecated(
|
||||
nominal,
|
||||
"destroy operation '" +
|
||||
@@ -2960,9 +3034,6 @@ FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy(
|
||||
}
|
||||
}
|
||||
|
||||
LLVM_FALLTHROUGH;
|
||||
|
||||
case CxxRecordSemanticsKind::Trivial:
|
||||
markDeprecated(
|
||||
nominal,
|
||||
"destroy operation '" +
|
||||
@@ -2972,20 +3043,9 @@ FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy(
|
||||
return nullptr;
|
||||
|
||||
case CxxRecordSemanticsKind::Iterator:
|
||||
case CxxRecordSemanticsKind::MissingLifetimeOperation:
|
||||
case CxxRecordSemanticsKind::SwiftClassType:
|
||||
return nullptr;
|
||||
|
||||
case CxxRecordSemanticsKind::MoveOnly:
|
||||
case CxxRecordSemanticsKind::UnavailableConstructors:
|
||||
// Handled below.
|
||||
break;
|
||||
}
|
||||
if (semanticsKind != CxxRecordSemanticsKind::MoveOnly) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return destroyFunc;
|
||||
}
|
||||
|
||||
/// Function body synthesizer for a deinit of a noncopyable type, which
|
||||
|
||||
Reference in New Issue
Block a user