@@ -5467,112 +5467,103 @@ getConditionalCopyableAttrParams(const clang::RecordDecl *decl) {
54675467CxxEscapability
54685468ClangTypeEscapability::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
55785569void 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
0 commit comments