@@ -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
@@ -8593,16 +8583,12 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
85938583 auto conditionalParams = getConditionalCopyableAttrParams (recordDecl);
85948584
85958585 if (!STLParams.empty () || !conditionalParams.empty ()) {
8596- hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
8597- recordDecl, importerImpl, STLParams, conditionalParams,
8598- maybePushToStack);
8599-
8600- if (importerImpl) {
8601- HeaderLoc loc{recordDecl->getLocation ()};
8602- for (auto name : conditionalParams)
8603- importerImpl->diagnose (loc, diag::unknown_template_parameter, name);
8586+ if (isa<clang::ClassTemplateSpecializationDecl>(recordDecl) &&
8587+ importerImpl) {
8588+ hasUnknown &= checkConditionalParams<CxxValueSemanticsKind>(
8589+ recordDecl, importerImpl, STLParams, conditionalParams,
8590+ maybePushToStack);
86048591 }
8605-
86068592 continue ;
86078593 }
86088594 }
@@ -8636,7 +8622,8 @@ CxxValueSemantics::evaluate(Evaluator &evaluator,
86368622 if (!hasDestroyTypeOperations (cxxRecordDecl) ||
86378623 (!isCopyable && !isMovable)) {
86388624
8639- if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl))
8625+ if (hasConstructorWithUnsupportedDefaultArgs (cxxRecordDecl) &&
8626+ importerImpl)
86408627 importerImpl->addImportDiagnostic (
86418628 cxxRecordDecl, Diagnostic (diag::record_unsupported_default_args),
86428629 cxxRecordDecl->getLocation ());
@@ -9263,6 +9250,85 @@ swift::importer::getCxxRefConventionWithAttrs(const clang::Decl *decl) {
92639250 return std::nullopt ;
92649251}
92659252
9253+ static const std::vector<std::vector<std::pair<StringRef, StringRef>>>
9254+ ConflictingSwiftAttrs = {
9255+ {{" Escapable" , " SWIFT_ESCAPABLE" },
9256+ {" ~Escapable" , " SWIFT_NONESCAPABLE" },
9257+ {" escapable_if:" , " SWIFT_ESCAPABLE_IF" }},
9258+ {{" ~Copyable" , " SWIFT_NONCOPYABLE" },
9259+ {" copyable_if:" , " SWIFT_COPYABLE_IF" }},
9260+ {{" mutating" , " SWIFT_MUTATING" }, {" nonmutating" , " 'nonmutating'" }}};
9261+
9262+ static bool isConditionalAttr (StringRef attrName) {
9263+ return attrName == " escapable_if:" || attrName == " copyable_if:" ;
9264+ }
9265+
9266+ void ClangImporter::Implementation::validateSwiftAttributes (
9267+ const clang::NamedDecl *decl) {
9268+ if (!decl->hasAttrs ())
9269+ return ;
9270+
9271+ for (const auto &groupOfAttrs : ConflictingSwiftAttrs) {
9272+ // stores this decl's attributes, grouped by annotation kind
9273+ llvm::StringMap<std::vector<clang::SwiftAttrAttr *>> found;
9274+ unsigned count = 0 ;
9275+ for (auto [attrName, annotationName] : groupOfAttrs) {
9276+ for (auto attr : decl->getAttrs ()) {
9277+ auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr);
9278+ if (swiftAttr && swiftAttr->getAttribute ().starts_with (attrName)) {
9279+ found[annotationName].push_back (swiftAttr);
9280+ count += 1 ;
9281+
9282+ // in the common case, we validate at most one conditional attribute
9283+ if (isConditionalAttr (attrName)) {
9284+ auto specDecl =
9285+ dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
9286+ if (!specDecl) {
9287+ diagnose (HeaderLoc{swiftAttr->getLocation ()},
9288+ diag::invalid_conditional_attr, annotationName);
9289+ continue ;
9290+ }
9291+ auto conditionalParams =
9292+ getConditionalAttrParams (swiftAttr, attrName);
9293+ while (specDecl && !conditionalParams.empty ()) {
9294+ auto templateDecl = specDecl->getSpecializedTemplate ();
9295+ for (auto [idx, param] :
9296+ llvm::enumerate (*templateDecl->getTemplateParameters ()))
9297+ conditionalParams.erase (param->getName ());
9298+
9299+ const clang::DeclContext *dc = specDecl;
9300+ specDecl = nullptr ;
9301+ while ((dc = dc->getParent ())) {
9302+ specDecl = dyn_cast<clang::ClassTemplateSpecializationDecl>(dc);
9303+ if (specDecl)
9304+ break ;
9305+ }
9306+ }
9307+ for (auto name : conditionalParams)
9308+ diagnose (HeaderLoc{decl->getLocation ()},
9309+ diag::unknown_template_parameter, name);
9310+ }
9311+ }
9312+ }
9313+ }
9314+
9315+ if (count > 1 ) {
9316+ if (found.size () == 1 )
9317+ diagnose (HeaderLoc{decl->getLocation ()}, diag::repeating_swift_attrs,
9318+ found.begin ()->getKey (), decl);
9319+ else
9320+ diagnose (HeaderLoc{decl->getLocation ()}, diag::conflicting_swift_attrs,
9321+ decl);
9322+
9323+ for (auto &[annotationName, attrs] : found) {
9324+ for (auto attr : attrs)
9325+ diagnose (HeaderLoc{attr->getLocation ()}, diag::annotation_here,
9326+ annotationName);
9327+ }
9328+ }
9329+ }
9330+ }
9331+
92669332NominalType *swift::stripInlineNamespaces (NominalType *outer,
92679333 NominalType *inner) {
92689334 if (!outer || !inner || inner == outer)
0 commit comments