mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Simplify CxxValueSemanticsKind
This commit is contained in:
@@ -575,15 +575,7 @@ SourceLoc extractNearestSourceLoc(EscapabilityLookupDescriptor desc);
|
||||
// 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 {
|
||||
Unknown,
|
||||
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,
|
||||
};
|
||||
enum class CxxValueSemanticsKind { Unknown, Copyable, MoveOnly };
|
||||
|
||||
struct CxxValueSemanticsDescriptor final {
|
||||
const clang::Type *type;
|
||||
|
||||
@@ -5382,10 +5382,9 @@ static const llvm::StringMap<std::vector<int>> STLConditionalParams{
|
||||
|
||||
template <typename Kind>
|
||||
static bool checkConditionalParams(
|
||||
clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
|
||||
const clang::RecordDecl *recordDecl, ClangImporter::Implementation *impl,
|
||||
const std::vector<int> &STLParams, std::set<StringRef> &conditionalParams,
|
||||
std::function<void(const clang::Type *)> &maybePushToStack) {
|
||||
HeaderLoc loc{recordDecl->getLocation()};
|
||||
llvm::function_ref<void(const clang::Type *)> maybePushToStack) {
|
||||
bool foundErrors = false;
|
||||
auto specDecl = cast<clang::ClassTemplateSpecializationDecl>(recordDecl);
|
||||
SmallVector<std::pair<unsigned, StringRef>, 4> argumentsToCheck;
|
||||
@@ -5416,7 +5415,8 @@ static bool checkConditionalParams(
|
||||
for (auto nonPackArg : nonPackArgs) {
|
||||
if (nonPackArg.getKind() != clang::TemplateArgument::Type) {
|
||||
if (impl)
|
||||
impl->diagnose(loc, diag::type_template_parameter_expected,
|
||||
impl->diagnose(HeaderLoc(recordDecl->getLocation()),
|
||||
diag::type_template_parameter_expected,
|
||||
argToCheck.second);
|
||||
foundErrors = true;
|
||||
} else {
|
||||
@@ -5427,7 +5427,7 @@ static bool checkConditionalParams(
|
||||
}
|
||||
if (hasInjectedSTLAnnotation)
|
||||
break;
|
||||
clang::DeclContext *dc = specDecl;
|
||||
const clang::DeclContext *dc = specDecl;
|
||||
specDecl = nullptr;
|
||||
while ((dc = dc->getParent())) {
|
||||
specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
|
||||
@@ -5474,19 +5474,33 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
|
||||
CxxEscapability
|
||||
ClangTypeEscapability::evaluate(Evaluator &evaluator,
|
||||
EscapabilityLookupDescriptor desc) const {
|
||||
|
||||
// Escapability inference rules:
|
||||
// - array and vector types have the same escapability as their element type
|
||||
// - pointer and reference types are currently imported as escapable
|
||||
// (importing them as non-escapable broke backward compatibility)
|
||||
// - a record type is escapable or non-escapable if it is explicitly annotated
|
||||
// as such
|
||||
// - a record type is escapable if it is annotated with SWIFT_ESCAPABLE_IF()
|
||||
// and none of the annotation arguments are non-escapable
|
||||
// - in all other cases, the record has unknown escapability (e.g. no
|
||||
// escapability annotations, malformed escapability annotations)
|
||||
|
||||
bool hasUnknown = false;
|
||||
auto desugared = desc.type->getUnqualifiedDesugaredType();
|
||||
if (const auto *recordType = desugared->getAs<clang::RecordType>()) {
|
||||
auto recordDecl = recordType->getDecl();
|
||||
// If the root type has a SWIFT_ESCAPABLE annotation, we import the type as
|
||||
// Escapable without entering the loop
|
||||
if (hasEscapableAttr(recordDecl))
|
||||
return CxxEscapability::Escapable;
|
||||
}
|
||||
|
||||
llvm::SmallVector<const clang::Type *, 4> stack;
|
||||
// Keep track of Decls we've seen to avoid cycles
|
||||
// Keep track of Types we've seen to avoid cycles
|
||||
llvm::SmallDenseSet<const clang::Type *, 4> seen;
|
||||
|
||||
std::function maybePushToStack = [&](const clang::Type *type) {
|
||||
auto maybePushToStack = [&](const clang::Type *type) {
|
||||
auto desugared = type->getUnqualifiedDesugaredType();
|
||||
if (seen.insert(desugared).second)
|
||||
stack.push_back(desugared);
|
||||
@@ -5524,6 +5538,10 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
|
||||
|
||||
continue;
|
||||
}
|
||||
// The `annotationOnly` flag used to control which types we infered
|
||||
// escapability for. Currently, this flag is always set to true, meaning
|
||||
// that any type without an annotation (CxxRecordDecls, aggregates, decls
|
||||
// lacking definition, etc.) will raise `hasUnknown`.
|
||||
if (desc.annotationOnly) {
|
||||
hasUnknown = true;
|
||||
continue;
|
||||
@@ -5539,8 +5557,7 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
|
||||
maybePushToStack(field->getType()->getUnqualifiedDesugaredType());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (type->isArrayType()) {
|
||||
} else if (type->isArrayType()) {
|
||||
auto elemTy = cast<clang::ArrayType>(type)
|
||||
->getElementType()
|
||||
->getUnqualifiedDesugaredType();
|
||||
@@ -8446,21 +8463,25 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
|
||||
// We assume a type can be imported as Copyable unless:
|
||||
// - There's no copy constructor
|
||||
// - The type has a SWIFT_NONCOPYABLE annotation
|
||||
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of T is ~Copyable
|
||||
// - It is one of the STL types in `STLConditionalParams`
|
||||
// - The type has a SWIFT_COPYABLE_IF(T...) annotation, where at least one of
|
||||
// T is ~Copyable
|
||||
// - It is one of the STL types in `STLConditionalParams`, and at least one of
|
||||
// its revelant types is ~Copyable
|
||||
|
||||
const auto *type = desc.type->getUnqualifiedDesugaredType();
|
||||
auto *importerImpl = desc.importerImpl;
|
||||
|
||||
llvm::SmallVector<clang::RecordDecl *, 4> stack;
|
||||
bool hasUnknown = false;
|
||||
llvm::SmallVector<const clang::RecordDecl *, 4> stack;
|
||||
// Keep track of Decls we've seen to avoid cycles
|
||||
llvm::SmallDenseSet<clang::RecordDecl *, 4> seen;
|
||||
llvm::SmallDenseSet<const clang::RecordDecl *, 4> seen;
|
||||
|
||||
std::function maybePushToStack = [&](const clang::Type *type) {
|
||||
auto recordDecl = type->getAsRecordDecl();
|
||||
if (!recordDecl)
|
||||
auto maybePushToStack = [&](const clang::Type *type) {
|
||||
auto recordType = type->getAs<clang::RecordType>();
|
||||
if (!recordType)
|
||||
return;
|
||||
|
||||
auto recordDecl = recordType->getDecl();
|
||||
if (seen.insert(recordDecl).second) {
|
||||
// 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
|
||||
@@ -8481,7 +8502,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
|
||||
|
||||
maybePushToStack(type);
|
||||
while (!stack.empty()) {
|
||||
clang::RecordDecl *recordDecl = stack.back();
|
||||
const clang::RecordDecl *recordDecl = stack.back();
|
||||
stack.pop_back();
|
||||
|
||||
if (!hasNonCopyableAttr(recordDecl)) {
|
||||
@@ -8495,22 +8516,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
|
||||
auto conditionalParams = getConditionalCopyableAttrParams(recordDecl);
|
||||
|
||||
if (!STLParams.empty() || !conditionalParams.empty()) {
|
||||
HeaderLoc loc{recordDecl->getLocation()};
|
||||
std::function checkArgValueSemantics =
|
||||
[&](clang::TemplateArgument &arg,
|
||||
StringRef argToCheck) -> std::optional<CxxValueSemanticsKind> {
|
||||
if (arg.getKind() != clang::TemplateArgument::Type) {
|
||||
if (importerImpl)
|
||||
importerImpl->diagnose(
|
||||
loc, diag::type_template_parameter_expected, argToCheck);
|
||||
return std::nullopt;
|
||||
}
|
||||
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
|
||||
// FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
checkConditionalParams<CxxValueSemanticsKind>(
|
||||
hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
|
||||
recordDecl, importerImpl, STLParams, conditionalParams,
|
||||
maybePushToStack);
|
||||
|
||||
@@ -8525,7 +8531,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
|
||||
}
|
||||
|
||||
const auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
|
||||
if (!cxxRecordDecl || !cxxRecordDecl->isCompleteDefinition()) {
|
||||
if (!cxxRecordDecl || !recordDecl->isCompleteDefinition()) {
|
||||
if (hasNonCopyableAttr(recordDecl))
|
||||
return CxxValueSemanticsKind::MoveOnly;
|
||||
continue;
|
||||
@@ -8539,9 +8545,11 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
|
||||
(!isCopyable && !isMovable)) {
|
||||
|
||||
if (hasConstructorWithUnsupportedDefaultArgs(cxxRecordDecl))
|
||||
return CxxValueSemanticsKind::UnavailableConstructors;
|
||||
|
||||
return CxxValueSemanticsKind::MissingLifetimeOperation;
|
||||
importerImpl->addImportDiagnostic(
|
||||
cxxRecordDecl, Diagnostic(diag::record_unsupported_default_args),
|
||||
cxxRecordDecl->getLocation());
|
||||
hasUnknown = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasNonCopyableAttr(cxxRecordDecl) && isMovable)
|
||||
@@ -8556,7 +8564,8 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
|
||||
llvm_unreachable("Could not classify C++ type.");
|
||||
}
|
||||
|
||||
return CxxValueSemanticsKind::Copyable;
|
||||
return hasUnknown ? CxxValueSemanticsKind::Unknown
|
||||
: CxxValueSemanticsKind::Copyable;
|
||||
}
|
||||
|
||||
void swift::simple_display(llvm::raw_ostream &out,
|
||||
|
||||
@@ -2103,11 +2103,11 @@ namespace {
|
||||
return importer::recordHasReferenceSemantics(decl, &Impl);
|
||||
}
|
||||
|
||||
bool recordHasMoveOnlySemantics(const clang::RecordDecl *decl) {
|
||||
bool recordIsCopyable(const clang::RecordDecl *decl) {
|
||||
auto semanticsKind = evaluateOrDefault(
|
||||
Impl.SwiftContext.evaluator,
|
||||
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
|
||||
return semanticsKind == CxxValueSemanticsKind::MoveOnly;
|
||||
return semanticsKind == CxxValueSemanticsKind::Copyable;
|
||||
}
|
||||
|
||||
void markReturnsUnsafeNonescapable(AbstractFunctionDecl *fd) {
|
||||
@@ -2286,7 +2286,7 @@ namespace {
|
||||
loc, ArrayRef<InheritedEntry>(), nullptr, dc);
|
||||
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
|
||||
|
||||
if (recordHasMoveOnlySemantics(decl)) {
|
||||
if (!recordIsCopyable(decl)) {
|
||||
if (decl->isInStdNamespace() && decl->getName() == "promise") {
|
||||
// Do not import std::promise.
|
||||
return nullptr;
|
||||
@@ -3170,8 +3170,7 @@ namespace {
|
||||
auto valueSemanticsKind = evaluateOrDefault(
|
||||
Impl.SwiftContext.evaluator,
|
||||
CxxValueSemantics({decl->getTypeForDecl(), &Impl}), {});
|
||||
if (valueSemanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation ||
|
||||
valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
|
||||
if (valueSemanticsKind == CxxValueSemanticsKind::Unknown) {
|
||||
|
||||
HeaderLoc loc(decl->getLocation());
|
||||
if (hasUnsafeAPIAttr(decl))
|
||||
@@ -3184,12 +3183,6 @@ namespace {
|
||||
Impl.diagnose(loc, diag::api_pattern_attr_ignored, "import_iterator",
|
||||
decl->getNameAsString());
|
||||
|
||||
if (valueSemanticsKind == CxxValueSemanticsKind::UnavailableConstructors) {
|
||||
Impl.addImportDiagnostic(
|
||||
decl, Diagnostic(diag::record_unsupported_default_args),
|
||||
decl->getLocation());
|
||||
}
|
||||
|
||||
Impl.addImportDiagnostic(
|
||||
decl,
|
||||
Diagnostic(diag::record_not_automatically_importable,
|
||||
@@ -3426,7 +3419,7 @@ namespace {
|
||||
auto semanticsKind = evaluateOrDefault(
|
||||
Impl.SwiftContext.evaluator,
|
||||
CxxValueSemantics({parent->getTypeForDecl(), &Impl}), {});
|
||||
if (semanticsKind == CxxValueSemanticsKind::MissingLifetimeOperation)
|
||||
if (semanticsKind == CxxValueSemanticsKind::Unknown)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -3074,8 +3074,7 @@ FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy(
|
||||
ctx.evaluator,
|
||||
CxxValueSemantics({clangType->getTypeForDecl(), &ImporterImpl}), {});
|
||||
|
||||
if (valueSemanticsKind != CxxValueSemanticsKind::Copyable &&
|
||||
valueSemanticsKind != CxxValueSemanticsKind::MoveOnly)
|
||||
if (valueSemanticsKind == CxxValueSemanticsKind::Unknown)
|
||||
return nullptr;
|
||||
|
||||
auto cxxRecordSemanticsKind = evaluateOrDefault(
|
||||
|
||||
Reference in New Issue
Block a user