@@ -5455,28 +5455,34 @@ static bool checkConditionalParams(
54555455}
54565456
54575457static std::set<StringRef>
5458- getConditionalAttrParams (const clang::RecordDecl *decl , StringRef attrName) {
5458+ getConditionalAttrParams (clang::SwiftAttrAttr *swiftAttr , StringRef attrName) {
54595459 std::set<StringRef> result;
5460- if (!decl->hasAttrs ())
5461- return result;
5462- for (auto attr : decl->getAttrs ()) {
5463- if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
5464- StringRef params = swiftAttr->getAttribute ();
5465- if (params.consume_front (attrName)) {
5466- auto commaPos = params.find (' ,' );
5467- StringRef nextParam = params.take_front (commaPos);
5468- while (!nextParam.empty () && commaPos != StringRef::npos) {
5469- result.insert (nextParam.trim ());
5470- params = params.drop_front (nextParam.size () + 1 );
5471- commaPos = params.find (' ,' );
5472- nextParam = params.take_front (commaPos);
5473- }
5474- }
5460+ StringRef params = swiftAttr->getAttribute ();
5461+ if (params.consume_front (attrName)) {
5462+ auto commaPos = params.find (' ,' );
5463+ StringRef nextParam = params.take_front (commaPos);
5464+ while (!nextParam.empty () && commaPos != StringRef::npos) {
5465+ result.insert (nextParam.trim ());
5466+ params = params.drop_front (nextParam.size () + 1 );
5467+ commaPos = params.find (' ,' );
5468+ nextParam = params.take_front (commaPos);
54755469 }
54765470 }
54775471 return result;
54785472}
54795473
5474+ static std::set<StringRef>
5475+ getConditionalAttrParams (const clang::NamedDecl *decl, StringRef attrName) {
5476+ if (decl->hasAttrs ()) {
5477+ for (auto attr : decl->getAttrs ()) {
5478+ if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
5479+ return getConditionalAttrParams (swiftAttr, attrName);
5480+ }
5481+ }
5482+
5483+ return {};
5484+ }
5485+
54805486static std::set<StringRef>
54815487getConditionalEscapableAttrParams (const clang::RecordDecl *decl) {
54825488 return getConditionalAttrParams (decl, " escapable_if:" );
@@ -5509,15 +5515,6 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55095515 // escapability annotations, malformed escapability annotations)
55105516
55115517 bool hasUnknown = false ;
5512- auto desugared = desc.type ->getUnqualifiedDesugaredType ();
5513- if (const auto *recordType = desugared->getAs <clang::RecordType>()) {
5514- auto recordDecl = recordType->getDecl ();
5515- // If the root type has a SWIFT_ESCAPABLE annotation, we import the type as
5516- // Escapable without entering the loop
5517- if (hasEscapableAttr (recordDecl))
5518- return CxxEscapability::Escapable;
5519- }
5520-
55215518 llvm::SmallVector<const clang::Type *, 4 > stack;
55225519 // Keep track of Types we've seen to avoid cycles
55235520 llvm::SmallDenseSet<const clang::Type *, 4 > seen;
@@ -5551,13 +5548,6 @@ ClangTypeEscapability::evaluate(Evaluator &evaluator,
55515548 hasUnknown &= checkConditionalParams<CxxEscapability>(
55525549 recordDecl, desc.impl , STLParams, conditionalParams,
55535550 maybePushToStack);
5554-
5555- if (desc.impl ) {
5556- HeaderLoc loc{recordDecl->getLocation ()};
5557- for (auto name : conditionalParams)
5558- desc.impl ->diagnose (loc, diag::unknown_template_parameter, name);
5559- }
5560-
55615551 continue ;
55625552 }
55635553 // Only try to infer escapability if the record doesn't have any
@@ -8534,16 +8524,12 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85348524 auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
85358525
85368526 if (!STLParams.empty () || !conditionalParams.empty ()) {
8537- hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
8538- recordDecl, importerImpl, STLParams, conditionalParams,
8539- maybePushToStack);
8540-
8541- if (importerImpl) {
8542- HeaderLoc loc{recordDecl->getLocation ()};
8543- for (auto name : conditionalParams)
8544- importerImpl->diagnose (loc, diag::unknown_template_parameter, name);
8527+ if (isa<clang::ClassTemplateSpecializationDecl>(recordDecl) &&
8528+ importerImpl) {
8529+ hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
8530+ recordDecl, importerImpl, STLParams, conditionalParams,
8531+ maybePushToStack);
85458532 }
8546-
85478533 continue ;
85488534 }
85498535 }
@@ -8577,7 +8563,8 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85778563 if (!hasDestroyTypeOperations (cxxRecordDecl) ||
85788564 (!isCopyable && !isMovable)) {
85798565
8580- if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8566+ if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl) &&
8567+ importerImpl)
85818568 importerImpl->addImportDiagnostic (
85828569 cxxRecordDecl, Diagnostic (diag::record_unsupported_default_args),
85838570 cxxRecordDecl->getLocation ());
@@ -9204,6 +9191,85 @@ swift::importer::getCxxRefConventionWithAttrs(const clang::Decl *decl) {
92049191 return std::nullopt ;
92059192}
92069193
9194+ static const std::vector<std::vector<std::pair<StringRef, StringRef>>>
9195+ ConflictingSwiftAttrs = {
9196+ {{" Escapable" , " SWIFT_ESCAPABLE" },
9197+ {" ~Escapable" , " SWIFT_NONESCAPABLE" },
9198+ {" escapable_if:" , " SWIFT_ESCAPABLE_IF" }},
9199+ {{" ~Copyable" , " SWIFT_NONCOPYABLE" },
9200+ {" copyable_if:" , " SWIFT_COPYABLE_IF" }},
9201+ {{" mutating" , " SWIFT_MUTATING" }, {" nonmutating" , " 'nonmutating'" }}};
9202+
9203+ static bool isConditionalAttr (StringRef attrName) {
9204+ return attrName == " escapable_if:" || attrName == " copyable_if:" ;
9205+ }
9206+
9207+ void ClangImporter::Implementation::validateSwiftAttributes (
9208+ const clang::NamedDecl *decl) {
9209+ if (!decl->hasAttrs ())
9210+ return ;
9211+
9212+ for (const auto &groupOfAttrs : ConflictingSwiftAttrs) {
9213+ // stores this decl's attributes, grouped by annotation kind
9214+ llvm::StringMap<std::vector<clang::SwiftAttrAttr *>> found;
9215+ unsigned count = 0 ;
9216+ for (auto [attrName, annotationName] : groupOfAttrs) {
9217+ for (auto attr : decl->getAttrs ()) {
9218+ auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr);
9219+ if (swiftAttr && swiftAttr->getAttribute ().starts_with (attrName)) {
9220+ found[annotationName].push_back (swiftAttr);
9221+ count += 1 ;
9222+
9223+ // in the common case, we validate at most one conditional attribute
9224+ if (isConditionalAttr (attrName)) {
9225+ auto specDecl =
9226+ dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
9227+ if (!specDecl) {
9228+ diagnose (HeaderLoc{swiftAttr->getLocation ()},
9229+ diag::invalid_conditional_attr, annotationName);
9230+ continue ;
9231+ }
9232+ auto conditionalParams =
9233+ getConditionalAttrParams (swiftAttr, attrName);
9234+ while (specDecl && !conditionalParams.empty ()) {
9235+ auto templateDecl = specDecl->getSpecializedTemplate ();
9236+ for (auto [idx, param] :
9237+ llvm::enumerate (*templateDecl->getTemplateParameters ()))
9238+ conditionalParams.erase (param->getName ());
9239+
9240+ const clang::DeclContext *dc = specDecl;
9241+ specDecl = nullptr ;
9242+ while ((dc = dc->getParent ())) {
9243+ specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
9244+ if (specDecl)
9245+ break ;
9246+ }
9247+ }
9248+ for (auto name : conditionalParams)
9249+ diagnose (HeaderLoc{decl->getLocation ()},
9250+ diag::unknown_template_parameter, name);
9251+ }
9252+ }
9253+ }
9254+ }
9255+
9256+ if (count > 1 ) {
9257+ if (found.size () == 1 )
9258+ diagnose (HeaderLoc{decl->getLocation ()}, diag::repeating_swift_attrs,
9259+ found.begin ()->getKey (), decl);
9260+ else
9261+ diagnose (HeaderLoc{decl->getLocation ()}, diag::conflicting_swift_attrs,
9262+ decl);
9263+
9264+ for (auto &[annotationName, attrs] : found) {
9265+ for (auto attr : attrs)
9266+ diagnose (HeaderLoc{attr->getLocation ()}, diag::annotation_here,
9267+ annotationName);
9268+ }
9269+ }
9270+ }
9271+ }
9272+
92079273NominalType *swift::stripInlineNamespaces (NominalType *outer,
92089274 NominalType *inner) {
92099275 if (!outer || !inner || inner == outer)
0 commit comments