7474
7575#include " llvm/ADT/STLExtras.h"
7676#include " llvm/ADT/SmallBitVector.h"
77+ #include " llvm/ADT/SmallSet.h"
7778#include " llvm/ADT/SmallString.h"
7879#include " llvm/ADT/Statistic.h"
7980#include " llvm/ADT/StringExtras.h"
@@ -168,10 +169,6 @@ void ClangImporter::Implementation::makeComputed(AbstractStorageDecl *storage,
168169bool importer::recordHasReferenceSemantics (
169170 const clang::RecordDecl *decl,
170171 ClangImporter::Implementation *importerImpl) {
171- if (!isa<clang::CXXRecordDecl>(decl) &&
172- !importerImpl->SwiftContext .LangOpts .CForeignReferenceTypes )
173- return false ;
174-
175172 // At this point decl might not be fully imported into Swift yet, which
176173 // means we might not have asked Clang to generate its implicit members, such
177174 // as copy or move constructors. This would cause CxxRecordSemanticsRequest to
@@ -2670,6 +2667,9 @@ namespace {
26702667 }
26712668 }
26722669
2670+ // If we need it, add an explicit "deinit" to this type.
2671+ synthesizer.addExplicitDeinitIfRequired (result, decl);
2672+
26732673 result->setMemberLoader (&Impl, 0 );
26742674 return result;
26752675 }
@@ -3136,12 +3136,11 @@ namespace {
31363136 }
31373137 }
31383138
3139- if (auto *ntd = dyn_cast<NominalTypeDecl>(result))
3140- addExplicitProtocolConformances (ntd, decl);
3141-
31423139 return result;
31433140 }
31443141
3142+ using ProtocolSet = llvm::SmallSet<ProtocolDecl *, 4 >;
3143+
31453144 void
31463145 addExplicitProtocolConformances (NominalTypeDecl *decl,
31473146 const clang::CXXRecordDecl *clangDecl) {
@@ -3156,59 +3155,71 @@ namespace {
31563155 if (!clangDecl->hasAttrs ())
31573156 return ;
31583157
3159- SmallVector<ValueDecl *, 1 > results;
3160- auto conformsToAttr =
3161- llvm::find_if (clangDecl->getAttrs (), [](auto *attr) {
3162- if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
3163- return swiftAttr->getAttribute ().starts_with (" conforms_to:" );
3164- return false ;
3165- });
3166- if (conformsToAttr == clangDecl->getAttrs ().end ())
3167- return ;
3158+ ProtocolSet alreadyAdded;
3159+ llvm::for_each (clangDecl->getAttrs (), [&](auto *attr) {
3160+ if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
3161+ if (swiftAttr->getAttribute ().starts_with (" conforms_to:" ))
3162+ addExplicitProtocolConformance (decl, swiftAttr, alreadyAdded);
3163+ }
3164+ });
3165+ }
31683166
3169- auto conformsToValue = cast<clang::SwiftAttrAttr>(*conformsToAttr)
3170- ->getAttribute ()
3167+ void addExplicitProtocolConformance (NominalTypeDecl *decl,
3168+ clang::SwiftAttrAttr *conformsToAttr,
3169+ ProtocolSet &alreadyAdded) {
3170+ auto conformsToValue = conformsToAttr->getAttribute ()
31713171 .drop_front (StringRef (" conforms_to:" ).size ())
31723172 .str ();
31733173 auto names = StringRef (conformsToValue).split (' .' );
31743174 auto moduleName = names.first ;
31753175 auto protocolName = names.second ;
31763176 if (protocolName.empty ()) {
3177- HeaderLoc attrLoc ((* conformsToAttr) ->getLocation ());
3177+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
31783178 Impl.diagnose (attrLoc, diag::conforms_to_missing_dot, conformsToValue);
31793179 return ;
31803180 }
31813181
31823182 auto *mod = Impl.SwiftContext .getModuleByIdentifier (
31833183 Impl.SwiftContext .getIdentifier (moduleName));
31843184 if (!mod) {
3185- HeaderLoc attrLoc ((* conformsToAttr) ->getLocation ());
3185+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
31863186 Impl.diagnose (attrLoc, diag::cannot_find_conforms_to_module,
31873187 conformsToValue, moduleName);
31883188 return ;
31893189 }
3190+
3191+ SmallVector<ValueDecl *, 1 > results;
31903192 mod->lookupValue (Impl.SwiftContext .getIdentifier (protocolName),
31913193 NLKind::UnqualifiedLookup, results);
31923194 if (results.empty ()) {
3193- HeaderLoc attrLoc ((* conformsToAttr) ->getLocation ());
3195+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
31943196 Impl.diagnose (attrLoc, diag::cannot_find_conforms_to, protocolName,
31953197 moduleName);
31963198 return ;
3197- } else if (results.size () != 1 ) {
3198- HeaderLoc attrLoc ((*conformsToAttr)->getLocation ());
3199+ }
3200+
3201+ if (results.size () != 1 ) {
3202+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
31993203 Impl.diagnose (attrLoc, diag::conforms_to_ambiguous, protocolName,
32003204 moduleName);
32013205 return ;
32023206 }
32033207
32043208 auto result = results.front ();
32053209 if (auto protocol = dyn_cast<ProtocolDecl>(result)) {
3210+ auto [_, inserted] = alreadyAdded.insert (protocol);
3211+ if (!inserted) {
3212+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
3213+ Impl.diagnose (attrLoc, diag::redundant_conformance_protocol,
3214+ decl->getDeclaredInterfaceType (), conformsToValue);
3215+ }
3216+
32063217 decl->getAttrs ().add (
32073218 new (Impl.SwiftContext ) SynthesizedProtocolAttr (protocol, &Impl, false ));
32083219 } else {
3209- HeaderLoc attrLoc ((* conformsToAttr)->getLocation ());
3210- Impl.diagnose (attrLoc, diag::conforms_to_not_protocol,
3211- result-> getDescriptiveKind (), result, conformsToValue);
3220+ HeaderLoc attrLoc ((conformsToAttr)->getLocation ());
3221+ Impl.diagnose (attrLoc, diag::conforms_to_not_protocol, result,
3222+ conformsToValue);
32123223 }
32133224 }
32143225
@@ -6511,6 +6522,20 @@ static bool conformsToProtocolInOriginalModule(NominalTypeDecl *nominal,
65116522 return false ;
65126523}
65136524
6525+ // / Determine whether the given nominal type was imported with an OptionSet
6526+ // / conformance.
6527+ static bool isImportedOptionSet (NominalTypeDecl *nominal) {
6528+ for (auto attr : nominal->getAttrs ()) {
6529+ if (auto synthesizedAttr = dyn_cast<SynthesizedProtocolAttr>(attr)) {
6530+ if (synthesizedAttr->getProtocol ()->isSpecificProtocol (
6531+ KnownProtocolKind::OptionSet))
6532+ return true ;
6533+ }
6534+ }
6535+
6536+ return false ;
6537+ }
6538+
65146539Decl *
65156540SwiftDeclConverter::importSwiftNewtype (const clang::TypedefNameDecl *decl,
65166541 clang::SwiftNewTypeAttr *newtypeAttr,
@@ -6585,6 +6610,11 @@ SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl,
65856610 addKnown (KnownProtocolKind::RawRepresentable);
65866611 addKnown (KnownProtocolKind::SwiftNewtypeWrapper);
65876612
6613+ // If this type was also imported as an OptionSet, include those typealiases.
6614+ if (isImportedOptionSet (structDecl)) {
6615+ Impl.addOptionSetTypealiases (structDecl);
6616+ }
6617+
65886618 // Local function to add a known protocol only when the
65896619 // underlying type conforms to it.
65906620 auto computedNominal = computedPropertyUnderlyingType->getAnyNominal ();
@@ -6839,8 +6869,6 @@ Decl *SwiftDeclConverter::importEnumCaseAlias(
68396869NominalTypeDecl *
68406870SwiftDeclConverter::importAsOptionSetType (DeclContext *dc, Identifier name,
68416871 const clang::EnumDecl *decl) {
6842- ASTContext &ctx = Impl.SwiftContext ;
6843-
68446872 auto Loc = Impl.importSourceLoc (decl->getLocation ());
68456873
68466874 // Create a struct with the underlying type as a field.
@@ -6859,10 +6887,7 @@ SwiftDeclConverter::importAsOptionSetType(DeclContext *dc, Identifier name,
68596887
68606888 synthesizer.makeStructRawValued (structDecl, underlyingType,
68616889 {KnownProtocolKind::OptionSet});
6862- auto selfType = structDecl->getDeclaredInterfaceType ();
6863- Impl.addSynthesizedTypealias (structDecl, ctx.Id_Element , selfType);
6864- Impl.addSynthesizedTypealias (structDecl, ctx.Id_ArrayLiteralElement ,
6865- selfType);
6890+ Impl.addOptionSetTypealiases (structDecl);
68666891 return structDecl;
68676892}
68686893
@@ -8760,6 +8785,7 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
87608785
87618786 std::optional<const clang::SwiftAttrAttr *> seenMainActorAttr;
87628787 const clang::SwiftAttrAttr *seenMutabilityAttr = nullptr ;
8788+ llvm::SmallSet<ProtocolDecl *, 4 > conformancesSeen;
87638789
87648790 auto importAttrsFromDecl = [&](const clang::NamedDecl *ClangDecl) {
87658791 //
@@ -8875,6 +8901,11 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
88758901 continue ;
88768902 }
88778903
8904+ if (swiftAttr->getAttribute ().starts_with (" conforms_to:" )) {
8905+ if (auto nominal = dyn_cast<NominalTypeDecl>(MappedDecl))
8906+ addExplicitProtocolConformance (nominal, swiftAttr, conformancesSeen);
8907+ }
8908+
88788909 importNontrivialAttribute (MappedDecl, swiftAttr->getAttribute ());
88798910 }
88808911
@@ -8937,6 +8968,14 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
89378968 }
89388969 }
89398970
8971+ // Import explicit conformances from C++ base classes.
8972+ if (auto nominal = dyn_cast<NominalTypeDecl>(MappedDecl)) {
8973+ if (auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(ClangDecl)) {
8974+ addExplicitProtocolConformancesFromBases (
8975+ nominal, cxxRecordDecl, /* isBase=*/ false );
8976+ }
8977+ }
8978+
89408979 // Now that we've collected all @Sendable and @_nonSendable attributes, we
89418980 // can see if we should synthesize a Sendable conformance.
89428981 if (auto nominal = dyn_cast<NominalTypeDecl>(MappedDecl)) {
@@ -9204,6 +9243,100 @@ static bool SwiftifiableCAT(const clang::ASTContext &ctx,
92049243 : SwiftifiableCountedByPointerType (swiftType));
92059244}
92069245
9246+ void ClangImporter::Implementation::addExplicitProtocolConformance (
9247+ NominalTypeDecl *decl,
9248+ clang::SwiftAttrAttr *conformsToAttr,
9249+ llvm::SmallSet<ProtocolDecl *, 4 > &alreadyAdded) {
9250+ auto conformsToValue = conformsToAttr->getAttribute ()
9251+ .drop_front (StringRef (" conforms_to:" ).size ())
9252+ .str ();
9253+ auto names = StringRef (conformsToValue).split (' .' );
9254+ auto moduleName = names.first ;
9255+ auto protocolName = names.second ;
9256+ if (protocolName.empty ()) {
9257+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
9258+ diagnose (attrLoc, diag::conforms_to_missing_dot, conformsToValue);
9259+ return ;
9260+ }
9261+
9262+ auto *mod = SwiftContext.getModuleByIdentifier (
9263+ SwiftContext.getIdentifier (moduleName));
9264+ if (!mod) {
9265+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
9266+ diagnose (attrLoc, diag::cannot_find_conforms_to_module,
9267+ conformsToValue, moduleName);
9268+ return ;
9269+ }
9270+
9271+ SmallVector<ValueDecl *, 1 > results;
9272+ mod->lookupValue (SwiftContext.getIdentifier (protocolName),
9273+ NLKind::UnqualifiedLookup, results);
9274+ if (results.empty ()) {
9275+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
9276+ diagnose (attrLoc, diag::cannot_find_conforms_to, protocolName,
9277+ moduleName);
9278+ return ;
9279+ }
9280+
9281+ if (results.size () != 1 ) {
9282+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
9283+ diagnose (attrLoc, diag::conforms_to_ambiguous, protocolName,
9284+ moduleName);
9285+ return ;
9286+ }
9287+
9288+ auto result = results.front ();
9289+ if (auto protocol = dyn_cast<ProtocolDecl>(result)) {
9290+ auto [_, inserted] = alreadyAdded.insert (protocol);
9291+ if (!inserted) {
9292+ HeaderLoc attrLoc (conformsToAttr->getLocation ());
9293+ diagnose (attrLoc, diag::redundant_conformance_protocol,
9294+ decl->getDeclaredInterfaceType (), conformsToValue);
9295+ }
9296+
9297+ decl->getAttrs ().add (
9298+ new (SwiftContext) SynthesizedProtocolAttr (protocol, this , false ));
9299+ } else {
9300+ HeaderLoc attrLoc ((conformsToAttr)->getLocation ());
9301+ diagnose (attrLoc, diag::conforms_to_not_protocol, result,
9302+ conformsToValue);
9303+ }
9304+ }
9305+
9306+ void ClangImporter::Implementation::addExplicitProtocolConformancesFromBases (
9307+ NominalTypeDecl *nominal,
9308+ const clang::CXXRecordDecl *cxxRecordDecl,
9309+ bool isBase) {
9310+ if (cxxRecordDecl->isCompleteDefinition ()) {
9311+ // Propagate conforms_to attribute from public base classes.
9312+ for (auto base : cxxRecordDecl->bases ()) {
9313+ if (base.getAccessSpecifier () != clang::AccessSpecifier::AS_public)
9314+ continue ;
9315+ if (auto *baseClangDecl = base.getType ()->getAsCXXRecordDecl ())
9316+ addExplicitProtocolConformancesFromBases (nominal, baseClangDecl,
9317+ /* isBase=*/ true );
9318+ }
9319+ }
9320+
9321+ if (isBase && cxxRecordDecl->hasAttrs ()) {
9322+ llvm::SmallSet<ProtocolDecl *, 4 > alreadyAdded;
9323+ llvm::for_each (cxxRecordDecl->getAttrs (), [&](auto *attr) {
9324+ if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
9325+ if (swiftAttr->getAttribute ().starts_with (" conforms_to:" ))
9326+ addExplicitProtocolConformance (nominal, swiftAttr, alreadyAdded);
9327+ }
9328+ });
9329+ }
9330+ }
9331+
9332+ void ClangImporter::Implementation::addOptionSetTypealiases (
9333+ NominalTypeDecl *nominal) {
9334+ auto selfType = nominal->getDeclaredInterfaceType ();
9335+ addSynthesizedTypealias (nominal, SwiftContext.Id_Element , selfType);
9336+ addSynthesizedTypealias (nominal, SwiftContext.Id_ArrayLiteralElement ,
9337+ selfType);
9338+ }
9339+
92079340void ClangImporter::Implementation::swiftify (AbstractFunctionDecl *MappedDecl) {
92089341 if (!SwiftContext.LangOpts .hasFeature (Feature::SafeInteropWrappers))
92099342 return ;
0 commit comments