Skip to content

Commit 245c53b

Browse files
committed
Make ClangTypeEscapability request non-recursive
1 parent a914799 commit 245c53b

File tree

2 files changed

+89
-98
lines changed

2 files changed

+89
-98
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 87 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -5488,112 +5488,103 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
54885488
CxxEscapability
54895489
ClangTypeEscapability::evaluate(Evaluator &evaluator,
54905490
EscapabilityLookupDescriptor desc) const {
5491-
bool hadUnknown = false;
5492-
auto evaluateEscapability = [&](const clang::Type *type) {
5493-
auto escapability = evaluateOrDefault(
5494-
evaluator,
5495-
ClangTypeEscapability({type, desc.impl, desc.annotationOnly}),
5496-
CxxEscapability::Unknown);
5497-
if (escapability == CxxEscapability::Unknown)
5498-
hadUnknown = true;
5499-
return escapability;
5500-
};
5501-
5491+
bool hasUnknown = false;
55025492
auto desugared = desc.type->getUnqualifiedDesugaredType();
55035493
if (const auto *recordType = desugared->getAs<clang::RecordType>()) {
55045494
auto recordDecl = recordType->getDecl();
5505-
if (hasNonEscapableAttr(recordDecl))
5506-
return CxxEscapability::NonEscapable;
55075495
if (hasEscapableAttr(recordDecl))
55085496
return CxxEscapability::Escapable;
5509-
auto injectedStlAnnotation =
5510-
recordDecl->isInStdNamespace()
5511-
? STLConditionalParams.find(recordDecl->getName())
5512-
: STLConditionalParams.end();
5513-
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
5514-
? injectedStlAnnotation->second
5515-
: std::vector<int>();
5516-
auto conditionalParams = getConditionalEscapableAttrParams(recordDecl);
5517-
5518-
if (!STLParams.empty() || !conditionalParams.empty()) {
5519-
HeaderLoc loc{recordDecl->getLocation()};
5520-
std::function checkArgEscapability =
5521-
[&](clang::TemplateArgument &arg,
5522-
StringRef argToCheck) -> std::optional<CxxEscapability> {
5523-
if (arg.getKind() != clang::TemplateArgument::Type && desc.impl) {
5524-
desc.impl->diagnose(loc, diag::type_template_parameter_expected,
5525-
argToCheck);
5526-
return CxxEscapability::Unknown;
5527-
}
5497+
}
55285498

5529-
auto argEscapability = evaluateEscapability(
5530-
arg.getAsType()->getUnqualifiedDesugaredType());
5531-
if (argEscapability == CxxEscapability::NonEscapable)
5532-
return CxxEscapability::NonEscapable;
5533-
return std::nullopt;
5534-
};
5535-
5536-
auto result = checkConditionalParams<CxxEscapability>(
5537-
recordDecl, STLParams, conditionalParams, checkArgEscapability);
5538-
if (result.has_value())
5539-
return result.value();
5540-
5541-
if (desc.impl)
5542-
for (auto name : conditionalParams)
5543-
desc.impl->diagnose(loc, diag::unknown_template_parameter, name);
5544-
5545-
return hadUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
5546-
}
5547-
if (desc.annotationOnly)
5548-
return CxxEscapability::Unknown;
5549-
auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
5550-
if (recordDecl->getDefinition() &&
5551-
(!cxxRecordDecl || cxxRecordDecl->isAggregate())) {
5552-
if (cxxRecordDecl) {
5553-
for (auto base : cxxRecordDecl->bases()) {
5554-
auto baseEscapability = evaluateEscapability(
5555-
base.getType()->getUnqualifiedDesugaredType());
5556-
if (baseEscapability == CxxEscapability::NonEscapable)
5557-
return CxxEscapability::NonEscapable;
5558-
}
5559-
}
5499+
llvm::SmallVector<const clang::Type *, 4> stack;
5500+
// Keep track of Decls we've seen to avoid cycles
5501+
llvm::SmallDenseSet<const clang::Type *, 4> seen;
5502+
5503+
auto maybePushToStack = [&](const clang::Type *type) {
5504+
auto desugared = type->getUnqualifiedDesugaredType();
5505+
if (seen.insert(desugared).second)
5506+
stack.push_back(desugared);
5507+
};
5508+
5509+
maybePushToStack(desc.type);
5510+
while (!stack.empty()) {
5511+
auto type = stack.back();
5512+
stack.pop_back();
5513+
if (const auto *recordType = type->getAs<clang::RecordType>()) {
5514+
auto recordDecl = recordType->getDecl();
5515+
if (hasNonEscapableAttr(recordDecl))
5516+
return CxxEscapability::NonEscapable;
5517+
if (hasEscapableAttr(recordDecl))
5518+
continue;
5519+
auto injectedStlAnnotation =
5520+
recordDecl->isInStdNamespace()
5521+
? STLConditionalParams.find(recordDecl->getName())
5522+
: STLConditionalParams.end();
5523+
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
5524+
? injectedStlAnnotation->second
5525+
: std::vector<int>();
5526+
auto conditionalParams = getConditionalEscapableAttrParams(recordDecl);
5527+
5528+
if (!STLParams.empty() || !conditionalParams.empty()) {
5529+
HeaderLoc loc{recordDecl->getLocation()};
5530+
std::function checkArgEscapability =
5531+
[&](clang::TemplateArgument &arg,
5532+
StringRef argToCheck) -> std::optional<CxxEscapability> {
5533+
if (arg.getKind() != clang::TemplateArgument::Type) {
5534+
if (desc.impl)
5535+
desc.impl->diagnose(loc, diag::type_template_parameter_expected,
5536+
argToCheck);
5537+
hasUnknown = true;
5538+
return std::nullopt;
5539+
}
5540+
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
5541+
// FIXME don't return anything
5542+
return std::nullopt;
5543+
};
5544+
5545+
checkConditionalParams<CxxEscapability>(
5546+
recordDecl, STLParams, conditionalParams, checkArgEscapability);
5547+
5548+
if (desc.impl)
5549+
for (auto name : conditionalParams)
5550+
desc.impl->diagnose(loc, diag::unknown_template_parameter, name);
55605551

5561-
for (auto field : recordDecl->fields()) {
5562-
auto fieldEscapability = evaluateEscapability(
5563-
field->getType()->getUnqualifiedDesugaredType());
5564-
if (fieldEscapability == CxxEscapability::NonEscapable)
5565-
return CxxEscapability::NonEscapable;
5552+
continue;
5553+
}
5554+
if (desc.annotationOnly) {
5555+
hasUnknown = true;
5556+
continue;
55665557
}
5558+
auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
5559+
if (recordDecl->getDefinition() &&
5560+
(!cxxRecordDecl || cxxRecordDecl->isAggregate())) {
5561+
if (cxxRecordDecl) {
5562+
// TODO llvm::foreach ?
5563+
for (auto base : cxxRecordDecl->bases())
5564+
maybePushToStack(base.getType()->getUnqualifiedDesugaredType());
5565+
}
55675566

5568-
return hadUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
5567+
for (auto field : recordDecl->fields())
5568+
maybePushToStack(field->getType()->getUnqualifiedDesugaredType());
5569+
continue;
5570+
}
5571+
}
5572+
if (type->isArrayType()) {
5573+
auto elemTy = cast<clang::ArrayType>(type)
5574+
->getElementType()
5575+
->getUnqualifiedDesugaredType();
5576+
maybePushToStack(elemTy);
5577+
} else if (const auto *vecTy = type->getAs<clang::VectorType>()) {
5578+
maybePushToStack(vecTy->getElementType()->getUnqualifiedDesugaredType());
5579+
} else if (type->isAnyPointerType() || type->isBlockPointerType() ||
5580+
type->isMemberPointerType() || type->isReferenceType()) {
5581+
if (desc.annotationOnly)
5582+
hasUnknown = true;
5583+
else
5584+
return CxxEscapability::NonEscapable;
55695585
}
55705586
}
5571-
if (desugared->isArrayType()) {
5572-
auto elemTy = cast<clang::ArrayType>(desugared)
5573-
->getElementType()
5574-
->getUnqualifiedDesugaredType();
5575-
return evaluateOrDefault(
5576-
evaluator,
5577-
ClangTypeEscapability({elemTy, desc.impl, desc.annotationOnly}),
5578-
CxxEscapability::Unknown);
5579-
}
5580-
if (const auto *vecTy = desugared->getAs<clang::VectorType>()) {
5581-
return evaluateOrDefault(
5582-
evaluator,
5583-
ClangTypeEscapability(
5584-
{vecTy->getElementType()->getUnqualifiedDesugaredType(), desc.impl,
5585-
desc.annotationOnly}),
5586-
CxxEscapability::Unknown);
5587-
}
5588-
5589-
// Base cases
5590-
if (desugared->isAnyPointerType() || desugared->isBlockPointerType() ||
5591-
desugared->isMemberPointerType() || desugared->isReferenceType())
5592-
return desc.annotationOnly ? CxxEscapability::Unknown
5593-
: CxxEscapability::NonEscapable;
5594-
if (desugared->isScalarType())
5595-
return CxxEscapability::Escapable;
5596-
return CxxEscapability::Unknown;
5587+
return hasUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
55975588
}
55985589

55995590
void swift::simple_display(llvm::raw_ostream &out,
@@ -8541,7 +8532,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85418532
if (importerImpl)
85428533
importerImpl->diagnose(
85438534
loc, diag::type_template_parameter_expected, argToCheck);
8544-
return CxxValueSemanticsKind::Unknown;
8535+
return std::nullopt;
85458536
}
85468537
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
85478538
// FIXME: return std::nullopt for now, while we don't refactor ClangTypeEscapability request

test/Interop/Cxx/class/nonescapable-errors.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,10 @@ public func noAnnotations() -> View {
193193
// CHECK-NO-LIFETIMES: nonescapable.h:56:39: error: template parameter 'Missing' does not exist
194194
i2()
195195
// CHECK: nonescapable.h:62:33: error: template parameter 'S' expected to be a type parameter
196-
// CHECK: nonescapable.h:80:41: error: a function with a ~Escapable result needs a parameter to depend on
197-
// CHECK: note: '@_lifetime(immortal)' can be used to indicate that values produced
198196
// CHECK-NO-LIFETIMES: nonescapable.h:62:33: error: template parameter 'S' expected to be a type parameter
199197
j1()
198+
// CHECK: nonescapable.h:80:41: error: a function with a ~Escapable result needs a parameter to depend on
199+
// CHECK: note: '@_lifetime(immortal)' can be used to indicate that values produced
200200
// CHECK-NO-LIFETIMES: nonescapable.h:80:41: error: a function cannot return a ~Escapable result
201201
j2()
202202
// CHECK: nonescapable.h:81:41: error: a function with a ~Escapable result needs a parameter to depend on

0 commit comments

Comments
 (0)