Skip to content

Commit a914799

Browse files
committed
Make CxxValueSemantics request non-recursive
1 parent 2421cef commit a914799

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
@@ -8480,103 +8480,118 @@ CxxValueSemanticsKind
84808480
CxxValueSemantics::evaluate(Evaluator &evaluator,
84818481
CxxValueSemanticsDescriptor desc) const {
84828482

8483-
const auto *type = desc.type;
8483+
// A C++ type can be imported to Swift as Copyable or ~Copyable.
8484+
// We assume a type can be imported as Copyable unless:
8485+
// - There's no copy constructor
8486+
// - The type has a SWIFT_NONCOPYABLE annotation
8487+
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
8488+
// - It is one of the STL types in `STLConditionalParams`
8489+
8490+
const auto *type = desc.type->getUnqualifiedDesugaredType();
84848491
auto *importerImpl = desc.importerImpl;
84858492

8486-
auto desugared = type->getUnqualifiedDesugaredType();
8487-
const auto *recordType = desugared->getAs<clang::RecordType>();
8488-
if (!recordType)
8489-
return CxxValueSemanticsKind::Copyable;
8493+
llvm::SmallVector<clang::RecordDecl *, 4> stack;
8494+
// Keep track of Decls we've seen to avoid cycles
8495+
llvm::SmallDenseSet<clang::RecordDecl *, 4> seen;
84908496

8491-
auto recordDecl = recordType->getDecl();
8497+
auto maybePushToStack = [&](const clang::Type *type) {
8498+
auto recordDecl = type->getAsRecordDecl();
8499+
if (!recordDecl)
8500+
return;
84928501

8493-
// When a reference type is copied, the pointer’s value is copied rather than
8494-
// the object’s storage. This means reference types can be imported as
8495-
// copyable to Swift, even when they are non-copyable in C++.
8496-
if (recordHasReferenceSemantics(recordDecl, importerImpl))
8497-
return CxxValueSemanticsKind::Copyable;
8502+
if (seen.insert(recordDecl).second) {
8503+
// When a reference type is copied, the pointer’s value is copied rather
8504+
// than the object’s storage. This means reference types can be imported
8505+
// as copyable to Swift, even when they are non-copyable in C++.
8506+
if (recordHasReferenceSemantics(recordDecl, importerImpl))
8507+
return;
84988508

8499-
if (recordDecl->isInStdNamespace()) {
8500-
// Hack for a base type of std::optional from the Microsoft standard
8501-
// library.
8502-
if (recordDecl->getIdentifier() &&
8503-
recordDecl->getName() == "_Optional_construct_base")
8504-
return CxxValueSemanticsKind::Copyable;
8505-
}
8509+
if (recordDecl->isInStdNamespace()) {
8510+
// Hack for a base type of std::optional from the Microsoft standard
8511+
// library.
8512+
if (recordDecl->getIdentifier() &&
8513+
recordDecl->getName() == "_Optional_construct_base")
8514+
return;
8515+
}
8516+
stack.push_back(recordDecl);
8517+
}
8518+
};
85068519

8507-
if (!hasNonCopyableAttr(recordDecl)) {
8508-
auto injectedStlAnnotation =
8509-
recordDecl->isInStdNamespace()
8510-
? STLConditionalParams.find(recordDecl->getName())
8511-
: STLConditionalParams.end();
8512-
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
8513-
? injectedStlAnnotation->second
8514-
: std::vector<int>();
8515-
auto conditionalParams = getConditionalCopyableAttrParams(recordDecl);
8520+
maybePushToStack(type);
8521+
while (!stack.empty()) {
8522+
clang::RecordDecl *recordDecl = stack.back();
8523+
stack.pop_back();
85168524

8517-
if (!STLParams.empty() || !conditionalParams.empty()) {
8518-
HeaderLoc loc{recordDecl->getLocation()};
8519-
std::function checkArgValueSemantics =
8520-
[&](clang::TemplateArgument &arg,
8521-
StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8522-
if (arg.getKind() != clang::TemplateArgument::Type && importerImpl) {
8523-
importerImpl->diagnose(loc, diag::type_template_parameter_expected,
8524-
argToCheck);
8525-
return CxxValueSemanticsKind::Unknown;
8526-
}
8525+
if (!hasNonCopyableAttr(recordDecl)) {
8526+
auto injectedStlAnnotation =
8527+
recordDecl->isInStdNamespace()
8528+
? STLConditionalParams.find(recordDecl->getName())
8529+
: STLConditionalParams.end();
8530+
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
8531+
? injectedStlAnnotation->second
8532+
: std::vector<int>();
8533+
auto conditionalParams = getConditionalCopyableAttrParams(recordDecl);
8534+
8535+
if (!STLParams.empty() || !conditionalParams.empty()) {
8536+
HeaderLoc loc{recordDecl->getLocation()};
8537+
std::function checkArgValueSemantics =
8538+
[&](clang::TemplateArgument &arg,
8539+
StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
8540+
if (arg.getKind() != clang::TemplateArgument::Type) {
8541+
if (importerImpl)
8542+
importerImpl->diagnose(
8543+
loc, diag::type_template_parameter_expected, argToCheck);
8544+
return CxxValueSemanticsKind::Unknown;
8545+
}
8546+
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
8547+
// FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
8548+
return std::nullopt;
8549+
};
85278550

8528-
auto argValueSemantics = evaluateOrDefault(
8529-
evaluator,
8530-
CxxValueSemantics(
8531-
{arg.getAsType()->getUnqualifiedDesugaredType(), importerImpl}),
8532-
{});
8533-
if (argValueSemantics != CxxValueSemanticsKind::Copyable)
8534-
return argValueSemantics;
8535-
return std::nullopt;
8536-
};
8551+
checkConditionalParams<CxxValueSemanticsKind>(
8552+
recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
85378553

8538-
auto result = checkConditionalParams<CxxValueSemanticsKind>(
8539-
recordDecl, STLParams, conditionalParams, checkArgValueSemantics);
8540-
if (result.has_value())
8541-
return result.value();
8554+
if (importerImpl)
8555+
for (auto name : conditionalParams)
8556+
importerImpl->diagnose(loc, diag::unknown_template_parameter, name);
85428557

8543-
if (importerImpl)
8544-
for (auto name : conditionalParams)
8545-
importerImpl->diagnose(loc, diag::unknown_template_parameter, name);
8558+
continue;
8559+
}
8560+
}
85468561

8547-
return CxxValueSemanticsKind::Copyable;
8562+
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8563+
if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition()) {
8564+
if (hasNonCopyableAttr(recordDecl))
8565+
return CxxValueSemanticsKind::MoveOnly;
8566+
continue;
85488567
}
8549-
}
85508568

8551-
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
8552-
if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition()) {
8553-
if (hasNonCopyableAttr(recordDecl))
8554-
return CxxValueSemanticsKind::MoveOnly;
8555-
return CxxValueSemanticsKind::Copyable;
8556-
}
8569+
bool isCopyable = !hasNonCopyableAttr(cxxRecordDecl) &&
8570+
hasCopyTypeOperations(cxxRecordDecl);
8571+
bool isMovable = hasMoveTypeOperations(cxxRecordDecl);
85578572

8558-
bool isCopyable = !hasNonCopyableAttr(cxxRecordDecl) &&
8559-
hasCopyTypeOperations(cxxRecordDecl);
8560-
bool isMovable = hasMoveTypeOperations(cxxRecordDecl);
8573+
if (!hasDestroyTypeOperations(cxxRecordDecl) ||
8574+
(!isCopyable && !isMovable)) {
85618575

8562-
if (!hasDestroyTypeOperations(cxxRecordDecl) || (!isCopyable && !isMovable)) {
8576+
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
8577+
return CxxValueSemanticsKind::UnavailableConstructors;
85638578

8564-
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
8565-
return CxxValueSemanticsKind::UnavailableConstructors;
8579+
return CxxValueSemanticsKind::MissingLifetimeOperation;
8580+
}
85668581

8567-
return CxxValueSemanticsKind::MissingLifetimeOperation;
8568-
}
8582+
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
8583+
return CxxValueSemanticsKind::MoveOnly;
85698584

8570-
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
8571-
return CxxValueSemanticsKind::MoveOnly;
8585+
if (isCopyable)
8586+
continue;
85728587

8573-
if (isCopyable)
8574-
return CxxValueSemanticsKind::Copyable;
8588+
if (isMovable)
8589+
return CxxValueSemanticsKind::MoveOnly;
85758590

8576-
if (isMovable)
8577-
return CxxValueSemanticsKind::MoveOnly;
8591+
llvm_unreachable("Could not classify C++ type.");
8592+
}
85788593

8579-
llvm_unreachable("Could not classify C++ type.");
8594+
return CxxValueSemanticsKind::Copyable;
85808595
}
85818596

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

0 commit comments

Comments
 (0)