Skip to content

Commit 68b22ec

Browse files
committed
Simplify CxxValueSemanticsKind
1 parent 8458b79 commit 68b22ec

File tree

4 files changed

+54
-61
lines changed

4 files changed

+54
-61
lines changed

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -575,15 +575,7 @@ SourceLoc extractNearestSourceLoc(EscapabilityLookupDescriptor desc);
575575
// When a reference type is copied, the pointer’s value is copied rather than
576576
// the object’s storage. This means reference types can be imported as
577577
// copyable to Swift, even when they are non-copyable in C++.
578-
enum class CxxValueSemanticsKind {
579-
Unknown,
580-
Copyable,
581-
MoveOnly,
582-
// A record that is either not copyable/movable or not destructible.
583-
MissingLifetimeOperation,
584-
// A record that has no copy and no move operations
585-
UnavailableConstructors,
586-
};
578+
enum class CxxValueSemanticsKind { Unknown, Copyable, MoveOnly };
587579

588580
struct CxxValueSemanticsDescriptor final {
589581
const clang::Type *type;

lib/ClangImporter/ClangImporter.cpp

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5403,10 +5403,9 @@ static const llvm::StringMap<std::vector<int>> STLConditionalParams{
54035403

54045404
template <typename Kind>
54055405
static bool checkConditionalParams(
5406-
clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
5406+
const clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
54075407
const std::vector<int> &STLParams, std::set<StringRef> &conditionalParams,
5408-
std::function<void(const clang::Type *)> &maybePushToStack) {
5409-
HeaderLoc loc{recordDecl->getLocation()};
5408+
llvm::function_ref<void(const clang::Type *)> maybePushToStack) {
54105409
bool foundErrors = false;
54115410
auto specDecl = cast<clang::ClassTemplateSpecializationDecl>(recordDecl);
54125411
SmallVector<std::pair<unsigned, StringRef>, 4> argumentsToCheck;
@@ -5437,7 +5436,8 @@ static bool checkConditionalParams(
54375436
for (auto nonPackArg : nonPackArgs) {
54385437
if (nonPackArg.getKind() != clang::TemplateArgument::Type) {
54395438
if (impl)
5440-
impl->diagnose(loc, diag::type_template_parameter_expected,
5439+
impl->diagnose(HeaderLoc(recordDecl->getLocation()),
5440+
diag::type_template_parameter_expected,
54415441
argToCheck.second);
54425442
foundErrors = true;
54435443
} else {
@@ -5448,7 +5448,7 @@ static bool checkConditionalParams(
54485448
}
54495449
if (hasInjectedSTLAnnotation)
54505450
break;
5451-
clang::DeclContext *dc = specDecl;
5451+
const clang::DeclContext *dc = specDecl;
54525452
specDecl = nullptr;
54535453
while ((dc = dc->getParent())) {
54545454
specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
@@ -5495,19 +5495,33 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
54955495
CxxEscapability
54965496
ClangTypeEscapability::evaluate(Evaluator &evaluator,
54975497
EscapabilityLookupDescriptor desc) const {
5498+
5499+
// Escapability inference rules:
5500+
// - array and vector types have the same escapability as their element type
5501+
// - pointer and reference types are currently imported as escapable
5502+
// (importing them as non-escapable broke backward compatibility)
5503+
// - a record type is escapable or non-escapable if it is explicitly annotated
5504+
// as such
5505+
// - a record type is escapable if it is annotated with SWIFT_ESCAPABLE_IF()
5506+
// and none of the annotation arguments are non-escapable
5507+
// - in all other cases, the record has unknown escapability (e.g. no
5508+
// escapability annotations, malformed escapability annotations)
5509+
54985510
bool hasUnknown = false;
54995511
auto desugared = desc.type->getUnqualifiedDesugaredType();
55005512
if (const auto *recordType = desugared->getAs<clang::RecordType>()) {
55015513
auto recordDecl = recordType->getDecl();
5514+
// If the root type has a SWIFT_ESCAPABLE annotation, we import the type as
5515+
// Escapable without entering the loop
55025516
if (hasEscapableAttr(recordDecl))
55035517
return CxxEscapability::Escapable;
55045518
}
55055519

55065520
llvm::SmallVector<const clang::Type *, 4> stack;
5507-
// Keep track of Decls we've seen to avoid cycles
5521+
// Keep track of Types we've seen to avoid cycles
55085522
llvm::SmallDenseSet<const clang::Type *, 4> seen;
55095523

5510-
std::function maybePushToStack = [&](const clang::Type *type) {
5524+
auto maybePushToStack = [&](const clang::Type *type) {
55115525
auto desugared = type->getUnqualifiedDesugaredType();
55125526
if (seen.insert(desugared).second)
55135527
stack.push_back(desugared);
@@ -5545,6 +5559,10 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55455559

55465560
continue;
55475561
}
5562+
// The `annotationOnly` flag used to control which types we infered
5563+
// escapability for. Currently, this flag is always set to true, meaning
5564+
// that any type without an annotation (CxxRecordDecls, aggregates, decls
5565+
// lacking definition, etc.) will raise `hasUnknown`.
55485566
if (desc.annotationOnly) {
55495567
hasUnknown = true;
55505568
continue;
@@ -5560,8 +5578,7 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55605578
maybePushToStack(field->getType()->getUnqualifiedDesugaredType());
55615579
continue;
55625580
}
5563-
}
5564-
if (type->isArrayType()) {
5581+
} else if (type->isArrayType()) {
55655582
auto elemTy = cast<clang::ArrayType>(type)
55665583
->getElementType()
55675584
->getUnqualifiedDesugaredType();
@@ -8467,21 +8484,25 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
84678484
// We assume a type can be imported as Copyable unless:
84688485
// - There's no copy constructor
84698486
// - The type has a SWIFT_NONCOPYABLE annotation
8470-
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8471-
// - It is one of the STL types in `STLConditionalParams`
8487+
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of
8488+
// T is ~Copyable
8489+
// - It is one of the STL types in `STLConditionalParams`, and at least one of
8490+
// its revelant types is ~Copyable
84728491

84738492
const auto *type = desc.type->getUnqualifiedDesugaredType();
84748493
auto *importerImpl = desc.importerImpl;
84758494

8476-
llvm::SmallVector<clang::RecordDecl *, 4> stack;
8495+
bool hasUnknown = false;
8496+
llvm::SmallVector<const clang::RecordDecl *, 4> stack;
84778497
// Keep track of Decls we've seen to avoid cycles
8478-
llvm::SmallDenseSet<clang::RecordDecl *, 4> seen;
8498+
llvm::SmallDenseSet<const clang::RecordDecl *, 4> seen;
84798499

8480-
std::function maybePushToStack = [&](const clang::Type *type) {
8481-
auto recordDecl = type->getAsRecordDecl();
8482-
if (!recordDecl)
8500+
auto maybePushToStack = [&](const clang::Type *type) {
8501+
auto recordType = type->getAs<clang::RecordType>();
8502+
if (!recordType)
84838503
return;
84848504

8505+
auto recordDecl = recordType->getDecl();
84858506
if (seen.insert(recordDecl).second) {
84868507
// When a reference type is copied, the pointer’s value is copied rather
84878508
// than the object’s storage. This means reference types can be imported
@@ -8502,7 +8523,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85028523

85038524
maybePushToStack(type);
85048525
while (!stack.empty()) {
8505-
clang::RecordDecl *recordDecl = stack.back();
8526+
const clang::RecordDecl *recordDecl = stack.back();
85068527
stack.pop_back();
85078528

85088529
if (!hasNonCopyableAttr(recordDecl)) {
@@ -8516,22 +8537,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85168537
auto conditionalParams = getConditionalCopyableAttrParams(recordDecl);
85178538

85188539
if (!STLParams.empty() || !conditionalParams.empty()) {
8519-
HeaderLoc loc{recordDecl->getLocation()};
8520-
std::function checkArgValueSemantics =
8521-
[&](clang::TemplateArgument &arg,
8522-
StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8523-
if (arg.getKind() != clang::TemplateArgument::Type) {
8524-
if (importerImpl)
8525-
importerImpl->diagnose(
8526-
loc, diag::type_template_parameter_expected, argToCheck);
8527-
return std::nullopt;
8528-
}
8529-
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
8530-
// FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8531-
return std::nullopt;
8532-
};
8533-
8534-
checkConditionalParams<CxxValueSemanticsKind>(
8540+
hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
85358541
recordDecl, importerImpl, STLParams, conditionalParams,
85368542
maybePushToStack);
85378543

@@ -8546,7 +8552,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85468552
}
85478553

85488554
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8549-
if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition()) {
8555+
if (!cxxRecordDecl || !recordDecl->isCompleteDefinition()) {
85508556
if (hasNonCopyableAttr(recordDecl))
85518557
return CxxValueSemanticsKind::MoveOnly;
85528558
continue;
@@ -8560,9 +8566,11 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85608566
(!isCopyable && !isMovable)) {
85618567

85628568
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
8563-
return CxxValueSemanticsKind::UnavailableConstructors;
8564-
8565-
return CxxValueSemanticsKind::MissingLifetimeOperation;
8569+
importerImpl->addImportDiagnostic(
8570+
cxxRecordDecl, Diagnostic(diag::record_unsupported_default_args),
8571+
cxxRecordDecl->getLocation());
8572+
hasUnknown = true;
8573+
continue;
85668574
}
85678575

85688576
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
@@ -8577,7 +8585,8 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85778585
llvm_unreachable("Could not classify C++ type.");
85788586
}
85798587

8580-
return CxxValueSemanticsKind::Copyable;
8588+
return hasUnknown ? CxxValueSemanticsKind::Unknown
8589+
: CxxValueSemanticsKind::Copyable;
85818590
}
85828591

85838592
void swift::simple_display(llvm::raw_ostream &out,

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,11 +2095,11 @@ namespace {
20952095
return importer::recordHasReferenceSemantics(decl, &Impl);
20962096
}
20972097

2098-
bool recordHasMoveOnlySemantics(const clang::RecordDecl *decl) {
2098+
bool recordIsCopyable(const clang::RecordDecl *decl) {
20992099
auto semanticsKind = evaluateOrDefault(
21002100
Impl.SwiftContext.evaluator,
21012101
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
2102-
return semanticsKind == CxxValueSemanticsKind::MoveOnly;
2102+
return semanticsKind == CxxValueSemanticsKind::Copyable;
21032103
}
21042104

21052105
void markReturnsUnsafeNonescapable(AbstractFunctionDecl *fd) {
@@ -2278,7 +2278,7 @@ namespace {
22782278
loc, ArrayRef<InheritedEntry>(), nullptr, dc);
22792279
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
22802280

2281-
if (recordHasMoveOnlySemantics(decl)) {
2281+
if (!recordIsCopyable(decl)) {
22822282
if (decl->isInStdNamespace() && decl->getName() == "promise") {
22832283
// Do not import std::promise.
22842284
return nullptr;
@@ -3162,8 +3162,7 @@ namespace {
31623162
auto valueSemanticsKind = evaluateOrDefault(
31633163
Impl.SwiftContext.evaluator,
31643164
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
3165-
if (valueSemanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation ||
3166-
valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
3165+
if (valueSemanticsKind == CxxValueSemanticsKind::Unknown) {
31673166

31683167
HeaderLoc loc(decl->getLocation());
31693168
if (hasUnsafeAPIAttr(decl))
@@ -3176,12 +3175,6 @@ namespace {
31763175
Impl.diagnose(loc, diag::api_pattern_attr_ignored, "import_iterator",
31773176
decl->getNameAsString());
31783177

3179-
if (valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
3180-
Impl.addImportDiagnostic(
3181-
decl, Diagnostic(diag::record_unsupported_default_args),
3182-
decl->getLocation());
3183-
}
3184-
31853178
Impl.addImportDiagnostic(
31863179
decl,
31873180
Diagnostic(diag::record_not_automatically_importable,
@@ -3418,7 +3411,7 @@ namespace {
34183411
auto semanticsKind = evaluateOrDefault(
34193412
Impl.SwiftContext.evaluator,
34203413
CxxValueSemantics({parent->getTypeForDecl(), &Impl}), {});
3421-
if (semanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation)
3414+
if (semanticsKind == CxxValueSemanticsKind::Unknown)
34223415
return nullptr;
34233416
}
34243417

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3076,8 +3076,7 @@ FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy(
30763076
ctx.evaluator,
30773077
CxxValueSemantics({clangType->getTypeForDecl(), &ImporterImpl}), {});
30783078

3079-
if (valueSemanticsKind != CxxValueSemanticsKind::Copyable &&
3080-
valueSemanticsKind != CxxValueSemanticsKind::MoveOnly)
3079+
if (valueSemanticsKind == CxxValueSemanticsKind::Unknown)
30813080
return nullptr;
30823081

30833082
auto cxxRecordSemanticsKind = evaluateOrDefault(

0 commit comments

Comments
 (0)