Skip to content

Commit 791194b

Browse files
committed
Simplify CxxValueSemanticsKind
1 parent de52134 commit 791194b

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
@@ -5382,10 +5382,9 @@ static const llvm::StringMap<std::vector<int>> STLConditionalParams{
53825382

53835383
template <typename Kind>
53845384
static bool checkConditionalParams(
5385-
clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
5385+
const clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
53865386
const std::vector<int> &STLParams, std::set<StringRef> &conditionalParams,
5387-
std::function<void(const clang::Type *)> &maybePushToStack) {
5388-
HeaderLoc loc{recordDecl->getLocation()};
5387+
llvm::function_ref<void(const clang::Type *)> maybePushToStack) {
53895388
bool foundErrors = false;
53905389
auto specDecl = cast<clang::ClassTemplateSpecializationDecl>(recordDecl);
53915390
SmallVector<std::pair<unsigned, StringRef>, 4> argumentsToCheck;
@@ -5416,7 +5415,8 @@ static bool checkConditionalParams(
54165415
for (auto nonPackArg : nonPackArgs) {
54175416
if (nonPackArg.getKind() != clang::TemplateArgument::Type) {
54185417
if (impl)
5419-
impl->diagnose(loc, diag::type_template_parameter_expected,
5418+
impl->diagnose(HeaderLoc(recordDecl->getLocation()),
5419+
diag::type_template_parameter_expected,
54205420
argToCheck.second);
54215421
foundErrors = true;
54225422
} else {
@@ -5427,7 +5427,7 @@ static bool checkConditionalParams(
54275427
}
54285428
if (hasInjectedSTLAnnotation)
54295429
break;
5430-
clang::DeclContext *dc = specDecl;
5430+
const clang::DeclContext *dc = specDecl;
54315431
specDecl = nullptr;
54325432
while ((dc = dc->getParent())) {
54335433
specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
@@ -5474,19 +5474,33 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
54745474
CxxEscapability
54755475
ClangTypeEscapability::evaluate(Evaluator &evaluator,
54765476
EscapabilityLookupDescriptor desc) const {
5477+
5478+
// Escapability inference rules:
5479+
// - array and vector types have the same escapability as their element type
5480+
// - pointer and reference types are currently imported as escapable
5481+
// (importing them as non-escapable broke backward compatibility)
5482+
// - a record type is escapable or non-escapable if it is explicitly annotated
5483+
// as such
5484+
// - a record type is escapable if it is annotated with SWIFT_ESCAPABLE_IF()
5485+
// and none of the annotation arguments are non-escapable
5486+
// - in all other cases, the record has unknown escapability (e.g. no
5487+
// escapability annotations, malformed escapability annotations)
5488+
54775489
bool hasUnknown = false;
54785490
auto desugared = desc.type->getUnqualifiedDesugaredType();
54795491
if (const auto *recordType = desugared->getAs<clang::RecordType>()) {
54805492
auto recordDecl = recordType->getDecl();
5493+
// If the root type has a SWIFT_ESCAPABLE annotation, we import the type as
5494+
// Escapable without entering the loop
54815495
if (hasEscapableAttr(recordDecl))
54825496
return CxxEscapability::Escapable;
54835497
}
54845498

54855499
llvm::SmallVector<const clang::Type *, 4> stack;
5486-
// Keep track of Decls we've seen to avoid cycles
5500+
// Keep track of Types we've seen to avoid cycles
54875501
llvm::SmallDenseSet<const clang::Type *, 4> seen;
54885502

5489-
std::function maybePushToStack = [&](const clang::Type *type) {
5503+
auto maybePushToStack = [&](const clang::Type *type) {
54905504
auto desugared = type->getUnqualifiedDesugaredType();
54915505
if (seen.insert(desugared).second)
54925506
stack.push_back(desugared);
@@ -5524,6 +5538,10 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55245538

55255539
continue;
55265540
}
5541+
// The `annotationOnly` flag used to control which types we infered
5542+
// escapability for. Currently, this flag is always set to true, meaning
5543+
// that any type without an annotation (CxxRecordDecls, aggregates, decls
5544+
// lacking definition, etc.) will raise `hasUnknown`.
55275545
if (desc.annotationOnly) {
55285546
hasUnknown = true;
55295547
continue;
@@ -5539,8 +5557,7 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55395557
maybePushToStack(field->getType()->getUnqualifiedDesugaredType());
55405558
continue;
55415559
}
5542-
}
5543-
if (type->isArrayType()) {
5560+
} else if (type->isArrayType()) {
55445561
auto elemTy = cast<clang::ArrayType>(type)
55455562
->getElementType()
55465563
->getUnqualifiedDesugaredType();
@@ -8446,21 +8463,25 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
84468463
// We assume a type can be imported as Copyable unless:
84478464
// - There's no copy constructor
84488465
// - The type has a SWIFT_NONCOPYABLE annotation
8449-
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8450-
// - It is one of the STL types in `STLConditionalParams`
8466+
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of
8467+
// T is ~Copyable
8468+
// - It is one of the STL types in `STLConditionalParams`, and at least one of
8469+
// its revelant types is ~Copyable
84518470

84528471
const auto *type = desc.type->getUnqualifiedDesugaredType();
84538472
auto *importerImpl = desc.importerImpl;
84548473

8455-
llvm::SmallVector<clang::RecordDecl *, 4> stack;
8474+
bool hasUnknown = false;
8475+
llvm::SmallVector<const clang::RecordDecl *, 4> stack;
84568476
// Keep track of Decls we've seen to avoid cycles
8457-
llvm::SmallDenseSet<clang::RecordDecl *, 4> seen;
8477+
llvm::SmallDenseSet<const clang::RecordDecl *, 4> seen;
84588478

8459-
std::function maybePushToStack = [&](const clang::Type *type) {
8460-
auto recordDecl = type->getAsRecordDecl();
8461-
if (!recordDecl)
8479+
auto maybePushToStack = [&](const clang::Type *type) {
8480+
auto recordType = type->getAs<clang::RecordType>();
8481+
if (!recordType)
84628482
return;
84638483

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

84828503
maybePushToStack(type);
84838504
while (!stack.empty()) {
8484-
clang::RecordDecl *recordDecl = stack.back();
8505+
const clang::RecordDecl *recordDecl = stack.back();
84858506
stack.pop_back();
84868507

84878508
if (!hasNonCopyableAttr(recordDecl)) {
@@ -8495,22 +8516,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
84958516
auto conditionalParams = getConditionalCopyableAttrParams(recordDecl);
84968517

84978518
if (!STLParams.empty() || !conditionalParams.empty()) {
8498-
HeaderLoc loc{recordDecl->getLocation()};
8499-
std::function checkArgValueSemantics =
8500-
[&](clang::TemplateArgument &arg,
8501-
StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8502-
if (arg.getKind() != clang::TemplateArgument::Type) {
8503-
if (importerImpl)
8504-
importerImpl->diagnose(
8505-
loc, diag::type_template_parameter_expected, argToCheck);
8506-
return std::nullopt;
8507-
}
8508-
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
8509-
// FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8510-
return std::nullopt;
8511-
};
8512-
8513-
checkConditionalParams<CxxValueSemanticsKind>(
8519+
hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
85148520
recordDecl, importerImpl, STLParams, conditionalParams,
85158521
maybePushToStack);
85168522

@@ -8525,7 +8531,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85258531
}
85268532

85278533
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8528-
if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition()) {
8534+
if (!cxxRecordDecl || !recordDecl->isCompleteDefinition()) {
85298535
if (hasNonCopyableAttr(recordDecl))
85308536
return CxxValueSemanticsKind::MoveOnly;
85318537
continue;
@@ -8539,9 +8545,11 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85398545
(!isCopyable && !isMovable)) {
85408546

85418547
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
8542-
return CxxValueSemanticsKind::UnavailableConstructors;
8543-
8544-
return CxxValueSemanticsKind::MissingLifetimeOperation;
8548+
importerImpl->addImportDiagnostic(
8549+
cxxRecordDecl, Diagnostic(diag::record_unsupported_default_args),
8550+
cxxRecordDecl->getLocation());
8551+
hasUnknown = true;
8552+
continue;
85458553
}
85468554

85478555
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
@@ -8556,7 +8564,8 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85568564
llvm_unreachable("Could not classify C++ type.");
85578565
}
85588566

8559-
return CxxValueSemanticsKind::Copyable;
8567+
return hasUnknown ? CxxValueSemanticsKind::Unknown
8568+
: CxxValueSemanticsKind::Copyable;
85608569
}
85618570

85628571
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
@@ -2103,11 +2103,11 @@ namespace {
21032103
return importer::recordHasReferenceSemantics(decl, &Impl);
21042104
}
21052105

2106-
bool recordHasMoveOnlySemantics(const clang::RecordDecl *decl) {
2106+
bool recordIsCopyable(const clang::RecordDecl *decl) {
21072107
auto semanticsKind = evaluateOrDefault(
21082108
Impl.SwiftContext.evaluator,
21092109
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
2110-
return semanticsKind == CxxValueSemanticsKind::MoveOnly;
2110+
return semanticsKind == CxxValueSemanticsKind::Copyable;
21112111
}
21122112

21132113
void markReturnsUnsafeNonescapable(AbstractFunctionDecl *fd) {
@@ -2286,7 +2286,7 @@ namespace {
22862286
loc, ArrayRef<InheritedEntry>(), nullptr, dc);
22872287
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
22882288

2289-
if (recordHasMoveOnlySemantics(decl)) {
2289+
if (!recordIsCopyable(decl)) {
22902290
if (decl->isInStdNamespace() && decl->getName() == "promise") {
22912291
// Do not import std::promise.
22922292
return nullptr;
@@ -3170,8 +3170,7 @@ namespace {
31703170
auto valueSemanticsKind = evaluateOrDefault(
31713171
Impl.SwiftContext.evaluator,
31723172
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
3173-
if (valueSemanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation ||
3174-
valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
3173+
if (valueSemanticsKind == CxxValueSemanticsKind::Unknown) {
31753174

31763175
HeaderLoc loc(decl->getLocation());
31773176
if (hasUnsafeAPIAttr(decl))
@@ -3184,12 +3183,6 @@ namespace {
31843183
Impl.diagnose(loc, diag::api_pattern_attr_ignored, "import_iterator",
31853184
decl->getNameAsString());
31863185

3187-
if (valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
3188-
Impl.addImportDiagnostic(
3189-
decl, Diagnostic(diag::record_unsupported_default_args),
3190-
decl->getLocation());
3191-
}
3192-
31933186
Impl.addImportDiagnostic(
31943187
decl,
31953188
Diagnostic(diag::record_not_automatically_importable,
@@ -3426,7 +3419,7 @@ namespace {
34263419
auto semanticsKind = evaluateOrDefault(
34273420
Impl.SwiftContext.evaluator,
34283421
CxxValueSemantics({parent->getTypeForDecl(), &Impl}), {});
3429-
if (semanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation)
3422+
if (semanticsKind == CxxValueSemanticsKind::Unknown)
34303423
return nullptr;
34313424
}
34323425

lib/ClangImporter/SwiftDeclSynthesizer.cpp

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

3077-
if (valueSemanticsKind != CxxValueSemanticsKind::Copyable &&
3078-
valueSemanticsKind != CxxValueSemanticsKind::MoveOnly)
3077+
if (valueSemanticsKind == CxxValueSemanticsKind::Unknown)
30793078
return nullptr;
30803079

30813080
auto cxxRecordSemanticsKind = evaluateOrDefault(

0 commit comments

Comments
 (0)