Skip to content

Commit c291ada

Browse files
authored
Merge pull request #83677 from DougGregor/c-interop-improvements-6.2
2 parents 7df1fe7 + 99eeda5 commit c291ada

27 files changed

+828
-72
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,8 @@ ERROR(conforms_to_ambiguous,none,
279279
"ambiguous reference to protocol '%0' in specified protocol conformance; module '%1' contains multiple protocols named '%0'", (StringRef, StringRef))
280280

281281
ERROR(conforms_to_not_protocol,none,
282-
"%0 %1 referenced in protocol conformance '%2' is not a protocol", (DescriptiveDeclKind, ValueDecl *, StringRef))
282+
"%kind0 referenced in protocol conformance '%1' is not a protocol",
283+
(const ValueDecl *, StringRef))
283284

284285
ERROR(failed_base_method_call_synthesis,none,
285286
"failed to synthesize call to the base method %0 of type %0",
@@ -290,6 +291,9 @@ ERROR(both_returns_retained_returns_unretained, none,
290291
"SWIFT_RETURNS_UNRETAINED",
291292
(const clang::NamedDecl *))
292293

294+
ERROR(redundant_conformance_protocol,none,
295+
"redundant conformance of %0 to protocol '%1'", (Type, StringRef))
296+
293297
ERROR(returns_retained_or_returns_unretained_for_non_cxx_frt_values, none,
294298
"%0 cannot be annotated with either SWIFT_RETURNS_RETAINED or "
295299
"SWIFT_RETURNS_UNRETAINED because it is not returning "

include/swift/Basic/LangOptions.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,6 @@ namespace swift {
353353
return CXXStdlib == PlatformDefaultCXXStdlib;
354354
}
355355

356-
bool CForeignReferenceTypes = false;
357-
358356
/// Imports getters and setters as computed properties.
359357
bool CxxInteropGettersSettersAsProperties = false;
360358

include/swift/Option/Options.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ def cxx_interoperability_mode :
871871
def experimental_c_foreign_reference_types :
872872
Flag<["-"], "experimental-c-foreign-reference-types">,
873873
Flags<[FrontendOption, HelpHidden, ModuleInterfaceOption]>,
874-
HelpText<"Enable experimental C foreign references types (with reference counting).">;
874+
HelpText<"Enable experimental C foreign references types. Deprecated, has no effect.">;
875875

876876
def experimental_hermetic_seal_at_link:
877877
Flag<["-"], "experimental-hermetic-seal-at-link">,

lib/ClangImporter/ClangImporter.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7867,8 +7867,9 @@ getRefParentDecls(const clang::RecordDecl *decl, ASTContext &ctx,
78677867
return matchingDecls;
78687868
}
78697869

7870-
static llvm::SmallVector<ValueDecl *, 1>
7871-
getValueDeclsForName(const clang::Decl *decl, ASTContext &ctx, StringRef name) {
7870+
llvm::SmallVector<ValueDecl *, 1>
7871+
importer::getValueDeclsForName(
7872+
const clang::Decl *decl, ASTContext &ctx, StringRef name) {
78727873
llvm::SmallVector<ValueDecl *, 1> results;
78737874
auto *clangMod = decl->getOwningModule();
78747875
if (clangMod && clangMod->isSubModule())
@@ -8212,6 +8213,9 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
82128213

82138214
auto cxxDecl = dyn_cast<clang::CXXRecordDecl>(decl);
82148215
if (!cxxDecl) {
8216+
if (hasNonCopyableAttr(decl))
8217+
return CxxRecordSemanticsKind::MoveOnly;
8218+
82158219
return CxxRecordSemanticsKind::Trivial;
82168220
}
82178221

lib/ClangImporter/ImportDecl.cpp

Lines changed: 165 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
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,
168169
bool 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+
65146539
Decl *
65156540
SwiftDeclConverter::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(
68396869
NominalTypeDecl *
68406870
SwiftDeclConverter::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+
92079340
void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
92089341
if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers))
92099342
return;

0 commit comments

Comments
 (0)