Skip to content

Commit 5dfb766

Browse files
committed
Make ClangTypeEscapability request non-recursive
1 parent 3516448 commit 5dfb766

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
@@ -5467,112 +5467,103 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
54675467
CxxEscapability
54685468
ClangTypeEscapability::evaluate(Evaluator &evaluator,
54695469
EscapabilityLookupDescriptor desc) const {
5470-
bool hadUnknown = false;
5471-
auto evaluateEscapability = [&](const clang::Type *type) {
5472-
auto escapability = evaluateOrDefault(
5473-
evaluator,
5474-
ClangTypeEscapability({type, desc.impl, desc.annotationOnly}),
5475-
CxxEscapability::Unknown);
5476-
if (escapability == CxxEscapability::Unknown)
5477-
hadUnknown = true;
5478-
return escapability;
5479-
};
5480-
5470+
bool hasUnknown = false;
54815471
auto desugared = desc.type->getUnqualifiedDesugaredType();
54825472
if (const auto *recordType = desugared->getAs<clang::RecordType>()) {
54835473
auto recordDecl = recordType->getDecl();
5484-
if (hasNonEscapableAttr(recordDecl))
5485-
return CxxEscapability::NonEscapable;
54865474
if (hasEscapableAttr(recordDecl))
54875475
return CxxEscapability::Escapable;
5488-
auto injectedStlAnnotation =
5489-
recordDecl->isInStdNamespace()
5490-
? STLConditionalParams.find(recordDecl->getName())
5491-
: STLConditionalParams.end();
5492-
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
5493-
? injectedStlAnnotation->second
5494-
: std::vector<int>();
5495-
auto conditionalParams = getConditionalEscapableAttrParams(recordDecl);
5496-
5497-
if (!STLParams.empty() || !conditionalParams.empty()) {
5498-
HeaderLoc loc{recordDecl->getLocation()};
5499-
std::function checkArgEscapability =
5500-
[&](clang::TemplateArgument &arg,
5501-
StringRef argToCheck) -> std::optional<CxxEscapability> {
5502-
if (arg.getKind() != clang::TemplateArgument::Type && desc.impl) {
5503-
desc.impl->diagnose(loc, diag::type_template_parameter_expected,
5504-
argToCheck);
5505-
return CxxEscapability::Unknown;
5506-
}
5476+
}
55075477

5508-
auto argEscapability = evaluateEscapability(
5509-
arg.getAsType()->getUnqualifiedDesugaredType());
5510-
if (argEscapability == CxxEscapability::NonEscapable)
5511-
return CxxEscapability::NonEscapable;
5512-
return std::nullopt;
5513-
};
5514-
5515-
auto result = checkConditionalParams<CxxEscapability>(
5516-
recordDecl, STLParams, conditionalParams, checkArgEscapability);
5517-
if (result.has_value())
5518-
return result.value();
5519-
5520-
if (desc.impl)
5521-
for (auto name : conditionalParams)
5522-
desc.impl->diagnose(loc, diag::unknown_template_parameter, name);
5523-
5524-
return hadUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
5525-
}
5526-
if (desc.annotationOnly)
5527-
return CxxEscapability::Unknown;
5528-
auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
5529-
if (recordDecl->getDefinition() &&
5530-
(!cxxRecordDecl || cxxRecordDecl->isAggregate())) {
5531-
if (cxxRecordDecl) {
5532-
for (auto base : cxxRecordDecl->bases()) {
5533-
auto baseEscapability = evaluateEscapability(
5534-
base.getType()->getUnqualifiedDesugaredType());
5535-
if (baseEscapability == CxxEscapability::NonEscapable)
5536-
return CxxEscapability::NonEscapable;
5537-
}
5538-
}
5478+
llvm::SmallVector<const clang::Type *, 4> stack;
5479+
// Keep track of Decls we've seen to avoid cycles
5480+
llvm::SmallDenseSet<const clang::Type *, 4> seen;
5481+
5482+
auto maybePushToStack = [&](const clang::Type *type) {
5483+
auto desugared = type->getUnqualifiedDesugaredType();
5484+
if (seen.insert(desugared).second)
5485+
stack.push_back(desugared);
5486+
};
5487+
5488+
maybePushToStack(desc.type);
5489+
while (!stack.empty()) {
5490+
auto type = stack.back();
5491+
stack.pop_back();
5492+
if (const auto *recordType = type->getAs<clang::RecordType>()) {
5493+
auto recordDecl = recordType->getDecl();
5494+
if (hasNonEscapableAttr(recordDecl))
5495+
return CxxEscapability::NonEscapable;
5496+
if (hasEscapableAttr(recordDecl))
5497+
continue;
5498+
auto injectedStlAnnotation =
5499+
recordDecl->isInStdNamespace()
5500+
? STLConditionalParams.find(recordDecl->getName())
5501+
: STLConditionalParams.end();
5502+
auto STLParams = injectedStlAnnotation != STLConditionalParams.end()
5503+
? injectedStlAnnotation->second
5504+
: std::vector<int>();
5505+
auto conditionalParams = getConditionalEscapableAttrParams(recordDecl);
5506+
5507+
if (!STLParams.empty() || !conditionalParams.empty()) {
5508+
HeaderLoc loc{recordDecl->getLocation()};
5509+
std::function checkArgEscapability =
5510+
[&](clang::TemplateArgument &arg,
5511+
StringRef argToCheck) -> std::optional<CxxEscapability> {
5512+
if (arg.getKind() != clang::TemplateArgument::Type) {
5513+
if (desc.impl)
5514+
desc.impl->diagnose(loc, diag::type_template_parameter_expected,
5515+
argToCheck);
5516+
hasUnknown = true;
5517+
return std::nullopt;
5518+
}
5519+
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
5520+
// FIXME don't return anything
5521+
return std::nullopt;
5522+
};
5523+
5524+
checkConditionalParams<CxxEscapability>(
5525+
recordDecl, STLParams, conditionalParams, checkArgEscapability);
5526+
5527+
if (desc.impl)
5528+
for (auto name : conditionalParams)
5529+
desc.impl->diagnose(loc, diag::unknown_template_parameter, name);
55395530

5540-
for (auto field : recordDecl->fields()) {
5541-
auto fieldEscapability = evaluateEscapability(
5542-
field->getType()->getUnqualifiedDesugaredType());
5543-
if (fieldEscapability == CxxEscapability::NonEscapable)
5544-
return CxxEscapability::NonEscapable;
5531+
continue;
5532+
}
5533+
if (desc.annotationOnly) {
5534+
hasUnknown = true;
5535+
continue;
55455536
}
5537+
auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(recordDecl);
5538+
if (recordDecl->getDefinition() &&
5539+
(!cxxRecordDecl || cxxRecordDecl->isAggregate())) {
5540+
if (cxxRecordDecl) {
5541+
// TODO llvm::foreach ?
5542+
for (auto base : cxxRecordDecl->bases())
5543+
maybePushToStack(base.getType()->getUnqualifiedDesugaredType());
5544+
}
55465545

5547-
return hadUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
5546+
for (auto field : recordDecl->fields())
5547+
maybePushToStack(field->getType()->getUnqualifiedDesugaredType());
5548+
continue;
5549+
}
5550+
}
5551+
if (type->isArrayType()) {
5552+
auto elemTy = cast<clang::ArrayType>(type)
5553+
->getElementType()
5554+
->getUnqualifiedDesugaredType();
5555+
maybePushToStack(elemTy);
5556+
} else if (const auto *vecTy = type->getAs<clang::VectorType>()) {
5557+
maybePushToStack(vecTy->getElementType()->getUnqualifiedDesugaredType());
5558+
} else if (type->isAnyPointerType() || type->isBlockPointerType() ||
5559+
type->isMemberPointerType() || type->isReferenceType()) {
5560+
if (desc.annotationOnly)
5561+
hasUnknown = true;
5562+
else
5563+
return CxxEscapability::NonEscapable;
55485564
}
55495565
}
5550-
if (desugared->isArrayType()) {
5551-
auto elemTy = cast<clang::ArrayType>(desugared)
5552-
->getElementType()
5553-
->getUnqualifiedDesugaredType();
5554-
return evaluateOrDefault(
5555-
evaluator,
5556-
ClangTypeEscapability({elemTy, desc.impl, desc.annotationOnly}),
5557-
CxxEscapability::Unknown);
5558-
}
5559-
if (const auto *vecTy = desugared->getAs<clang::VectorType>()) {
5560-
return evaluateOrDefault(
5561-
evaluator,
5562-
ClangTypeEscapability(
5563-
{vecTy->getElementType()->getUnqualifiedDesugaredType(), desc.impl,
5564-
desc.annotationOnly}),
5565-
CxxEscapability::Unknown);
5566-
}
5567-
5568-
// Base cases
5569-
if (desugared->isAnyPointerType() || desugared->isBlockPointerType() ||
5570-
desugared->isMemberPointerType() || desugared->isReferenceType())
5571-
return desc.annotationOnly ? CxxEscapability::Unknown
5572-
: CxxEscapability::NonEscapable;
5573-
if (desugared->isScalarType())
5574-
return CxxEscapability::Escapable;
5575-
return CxxEscapability::Unknown;
5566+
return hasUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
55765567
}
55775568

55785569
void swift::simple_display(llvm::raw_ostream &out,
@@ -8520,7 +8511,7 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85208511
if (importerImpl)
85218512
importerImpl->diagnose(
85228513
loc, diag::type_template_parameter_expected, argToCheck);
8523-
return CxxValueSemanticsKind::Unknown;
8514+
return std::nullopt;
85248515
}
85258516
maybePushToStack(arg.getAsType()->getUnqualifiedDesugaredType());
85268517
// 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)