Skip to content

Commit 3516448

Browse files
committed
Make CxxValueSemantics request non-recursive
1 parent 62b7fe5 commit 3516448

File tree

1 file changed

+91
-76
lines changed

1 file changed

+91
-76
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 91 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -8459,103 +8459,118 @@ CxxValueSemanticsKind
84598459
CxxValueSemantics::evaluate(Evaluator &evaluator,
84608460
CxxValueSemanticsDescriptor desc) const {
84618461

8462-
const auto *type = desc.type;
8462+
// A C++ type can be imported to Swift as Copyable or ~Copyable.
8463+
// We assume a type can be imported as Copyable unless:
8464+
// - There's no copy constructor
8465+
// - The type has a SWIFT_NONCOPYABLE annotation
8466+
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8467+
// - It is one of the STL types in `STLConditionalParams`
8468+
8469+
const auto *type = desc.type->getUnqualifiedDesugaredType();
84638470
auto *importerImpl = desc.importerImpl;
84648471

8465-
auto desugared = type->getUnqualifiedDesugaredType();
8466-
const auto *recordType = desugared->getAs<clang::RecordType>();
8467-
if (!recordType)
8468-
return CxxValueSemanticsKind::Copyable;
8472+
llvm::SmallVector<clang::RecordDecl *, 4> stack;
8473+
// Keep track of Decls we've seen to avoid cycles
8474+
llvm::SmallDenseSet<clang::RecordDecl *, 4> seen;
84698475

8470-
auto recordDecl = recordType->getDecl();
8476+
auto maybePushToStack = [&](const clang::Type *type) {
8477+
auto recordDecl = type->getAsRecordDecl();
8478+
if (!recordDecl)
8479+
return;
84718480

8472-
// When a reference type is copied, the pointer’s value is copied rather than
8473-
// the object’s storage. This means reference types can be imported as
8474-
// copyable to Swift, even when they are non-copyable in C++.
8475-
if (recordHasReferenceSemantics(recordDecl, importerImpl))
8476-
return CxxValueSemanticsKind::Copyable;
8481+
if (seen.insert(recordDecl).second) {
8482+
// When a reference type is copied, the pointer’s value is copied rather
8483+
// than the object’s storage. This means reference types can be imported
8484+
// as copyable to Swift, even when they are non-copyable in C++.
8485+
if (recordHasReferenceSemantics(recordDecl, importerImpl))
8486+
return;
84778487

8478-
if (recordDecl->isInStdNamespace()) {
8479-
// Hack for a base type of std::optional from the Microsoft standard
8480-
// library.
8481-
if (recordDecl->getIdentifier() &&
8482-
recordDecl->getName() == "_Optional_construct_base")
8483-
return CxxValueSemanticsKind::Copyable;
8484-
}
8488+
if (recordDecl->isInStdNamespace()) {
8489+
// Hack for a base type of std::optional from the Microsoft standard
8490+
// library.
8491+
if (recordDecl->getIdentifier() &&
8492+
recordDecl->getName() == "_Optional_construct_base")
8493+
return;
8494+
}
8495+
stack.push_back(recordDecl);
8496+
}
8497+
};
84858498

8486-
if (!hasNonCopyableAttr(recordDecl)) {
8487-
auto injectedStlAnnotation =
8488-
recordDecl->isInStdNamespace()
8489-
? STLConditionalParams.find(recordDecl->getName())
8490-
: STLConditionalParams.end();
8491-
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
8492-
? injectedStlAnnotation->second
8493-
: std::vector<int>();
8494-
auto conditionalParams = getConditionalCopyableAttrParams(recordDecl);
8499+
maybePushToStack(type);
8500+
while (!stack.empty()) {
8501+
clang::RecordDecl *recordDecl = stack.back();
8502+
stack.pop_back();
84958503

8496-
if (!STLParams.empty() || !conditionalParams.empty()) {
8497-
HeaderLoc loc{recordDecl->getLocation()};
8498-
std::function checkArgValueSemantics =
8499-
[&](clang::TemplateArgument &arg,
8500-
StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8501-
if (arg.getKind() != clang::TemplateArgument::Type && importerImpl) {
8502-
importerImpl->diagnose(loc, diag::type_template_parameter_expected,
8503-
argToCheck);
8504-
return CxxValueSemanticsKind::Unknown;
8505-
}
8504+
if (!hasNonCopyableAttr(recordDecl)) {
8505+
auto injectedStlAnnotation =
8506+
recordDecl->isInStdNamespace()
8507+
? STLConditionalParams.find(recordDecl->getName())
8508+
: STLConditionalParams.end();
8509+
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
8510+
? injectedStlAnnotation->second
8511+
: std::vector<int>();
8512+
auto conditionalParams = getConditionalCopyableAttrParams(recordDecl);
8513+
8514+
if (!STLParams.empty() || !conditionalParams.empty()) {
8515+
HeaderLoc loc{recordDecl->getLocation()};
8516+
std::function checkArgValueSemantics =
8517+
[&](clang::TemplateArgument &arg,
8518+
StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8519+
if (arg.getKind() != clang::TemplateArgument::Type) {
8520+
if (importerImpl)
8521+
importerImpl->diagnose(
8522+
loc, diag::type_template_parameter_expected, argToCheck);
8523+
return CxxValueSemanticsKind::Unknown;
8524+
}
8525+
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
8526+
// FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8527+
return std::nullopt;
8528+
};
85068529

8507-
auto argValueSemantics = evaluateOrDefault(
8508-
evaluator,
8509-
CxxValueSemantics(
8510-
{arg.getAsType()->getUnqualifiedDesugaredType(), importerImpl}),
8511-
{});
8512-
if (argValueSemantics != CxxValueSemanticsKind::Copyable)
8513-
return argValueSemantics;
8514-
return std::nullopt;
8515-
};
8530+
checkConditionalParams<CxxValueSemanticsKind>(
8531+
recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
85168532

8517-
auto result = checkConditionalParams<CxxValueSemanticsKind>(
8518-
recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
8519-
if (result.has_value())
8520-
return result.value();
8533+
if (importerImpl)
8534+
for (auto name : conditionalParams)
8535+
importerImpl->diagnose(loc, diag::unknown_template_parameter, name);
85218536

8522-
if (importerImpl)
8523-
for (auto name : conditionalParams)
8524-
importerImpl->diagnose(loc, diag::unknown_template_parameter, name);
8537+
continue;
8538+
}
8539+
}
85258540

8526-
return CxxValueSemanticsKind::Copyable;
8541+
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8542+
if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition()) {
8543+
if (hasNonCopyableAttr(recordDecl))
8544+
return CxxValueSemanticsKind::MoveOnly;
8545+
continue;
85278546
}
8528-
}
85298547

8530-
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8531-
if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition()) {
8532-
if (hasNonCopyableAttr(recordDecl))
8533-
return CxxValueSemanticsKind::MoveOnly;
8534-
return CxxValueSemanticsKind::Copyable;
8535-
}
8548+
bool isCopyable = !hasNonCopyableAttr(cxxRecordDecl) &&
8549+
hasCopyTypeOperations(cxxRecordDecl);
8550+
bool isMovable = hasMoveTypeOperations(cxxRecordDecl);
85368551

8537-
bool isCopyable = !hasNonCopyableAttr(cxxRecordDecl) &&
8538-
hasCopyTypeOperations(cxxRecordDecl);
8539-
bool isMovable = hasMoveTypeOperations(cxxRecordDecl);
8552+
if (!hasDestroyTypeOperations(cxxRecordDecl) ||
8553+
(!isCopyable && !isMovable)) {
85408554

8541-
if (!hasDestroyTypeOperations(cxxRecordDecl) || (!isCopyable && !isMovable)) {
8555+
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
8556+
return CxxValueSemanticsKind::UnavailableConstructors;
85428557

8543-
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
8544-
return CxxValueSemanticsKind::UnavailableConstructors;
8558+
return CxxValueSemanticsKind::MissingLifetimeOperation;
8559+
}
85458560

8546-
return CxxValueSemanticsKind::MissingLifetimeOperation;
8547-
}
8561+
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
8562+
return CxxValueSemanticsKind::MoveOnly;
85488563

8549-
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
8550-
return CxxValueSemanticsKind::MoveOnly;
8564+
if (isCopyable)
8565+
continue;
85518566

8552-
if (isCopyable)
8553-
return CxxValueSemanticsKind::Copyable;
8567+
if (isMovable)
8568+
return CxxValueSemanticsKind::MoveOnly;
85548569

8555-
if (isMovable)
8556-
return CxxValueSemanticsKind::MoveOnly;
8570+
llvm_unreachable("Could not classify C++ type.");
8571+
}
85578572

8558-
llvm_unreachable("Could not classify C++ type.");
8573+
return CxxValueSemanticsKind::Copyable;
85598574
}
85608575

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

0 commit comments

Comments
 (0)