Skip to content

Commit 0f8b97a

Browse files
committed
[cxx-interop] Import non-public inherited members
This patch is follow-up work from #78942 and concurrent with #79093. It imports non-public members, which were previously not being imported. Once #79093 (SWIFT_PRIVATE_FILEID) is merged in, these inherited members will be available within certain Swift extensions.
1 parent be73254 commit 0f8b97a

File tree

8 files changed

+340
-127
lines changed

8 files changed

+340
-127
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,18 @@ class ClangModuleLoader : public ModuleLoader {
202202
/// Imports a clang decl directly, rather than looking up its name.
203203
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;
204204

205-
/// Imports a clang decl from a base class, cloning it for \param newContext
206-
/// if it wasn't cloned for this specific context before.
207-
virtual ValueDecl *importBaseMemberDecl(ValueDecl *decl,
208-
DeclContext *newContext) = 0;
205+
/// Clones an imported \param decl from its base class to its derived class
206+
/// \param newContext where it is inherited. Its access level is determined
207+
/// with respect to \param inheritance, which signifies whether \param decl
208+
/// was inherited via C++ public/protected/private inheritance.
209+
///
210+
/// This function uses a cache so that it is idempotent; successive
211+
/// invocations will only generate one cloned ValueDecl (and all return
212+
/// a pointer to it). Returns a NULL pointer upon failure.
213+
virtual ValueDecl *
214+
importBaseMemberDecl(ValueDecl *decl,
215+
DeclContext *newContext,
216+
clang::AccessSpecifier inheritance) = 0;
209217

210218
/// Emits diagnostics for any declarations named name
211219
/// whose direct declaration context is a TU.

include/swift/ClangImporter/ClangImporter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,8 @@ class ClangImporter final : public ClangModuleLoader {
658658
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
659659

660660
ValueDecl *importBaseMemberDecl(ValueDecl *decl,
661-
DeclContext *newContext) override;
661+
DeclContext *newContext,
662+
clang::AccessSpecifier inheritance) override;
662663

663664
/// Emits diagnostics for any declarations named name
664665
/// whose direct declaration context is a TU.

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/Basic/Statistic.h"
2525
#include "swift/ClangImporter/ClangImporter.h"
2626
#include "clang/AST/Type.h"
27+
#include "clang/Basic/Specifiers.h"
2728
#include "llvm/ADT/Hashing.h"
2829
#include "llvm/ADT/TinyPtrVector.h"
2930

@@ -132,25 +133,33 @@ class CXXNamespaceMemberLookup
132133
};
133134

134135
/// The input type for a record member lookup request.
136+
///
137+
/// These lookups may be requested recursively in the case of inheritance,
138+
/// for which we separately keep track of the derived class where we started
139+
/// looking (startDecl) and the access level for the current inheritance.
135140
struct ClangRecordMemberLookupDescriptor final {
136-
NominalTypeDecl *recordDecl;
137-
NominalTypeDecl *inheritingDecl;
138-
DeclName name;
141+
NominalTypeDecl *recordDecl; // Where we are currently looking
142+
NominalTypeDecl *inheritingDecl; // Where we started looking from
143+
DeclName name; // What we are looking for
144+
clang::AccessSpecifier inheritance; // public/protected/private inheritance
145+
// (clang::AS_none means no inheritance)
139146

140147
ClangRecordMemberLookupDescriptor(NominalTypeDecl *recordDecl, DeclName name)
141-
: recordDecl(recordDecl), inheritingDecl(recordDecl), name(name) {
148+
: recordDecl(recordDecl), inheritingDecl(recordDecl), name(name),
149+
inheritance(clang::AS_none) {
142150
assert(isa<clang::RecordDecl>(recordDecl->getClangDecl()));
143151
}
144152

145153
friend llvm::hash_code
146154
hash_value(const ClangRecordMemberLookupDescriptor &desc) {
147-
return llvm::hash_combine(desc.name, desc.recordDecl, desc.inheritingDecl);
155+
return llvm::hash_combine(desc.name, desc.recordDecl, desc.inheritingDecl, desc.inheritance);
148156
}
149157

150158
friend bool operator==(const ClangRecordMemberLookupDescriptor &lhs,
151159
const ClangRecordMemberLookupDescriptor &rhs) {
152160
return lhs.name == rhs.name && lhs.recordDecl == rhs.recordDecl &&
153-
lhs.inheritingDecl == rhs.inheritingDecl;
161+
lhs.inheritingDecl == rhs.inheritingDecl &&
162+
lhs.inheritance == rhs.inheritance;
154163
}
155164

156165
friend bool operator!=(const ClangRecordMemberLookupDescriptor &lhs,
@@ -163,11 +172,15 @@ struct ClangRecordMemberLookupDescriptor final {
163172

164173
// This private constructor should only be used in ClangRecordMemberLookup,
165174
// for recursively traversing base classes that inheritingDecl inherites from.
166-
ClangRecordMemberLookupDescriptor(NominalTypeDecl *recordDecl, DeclName name,
167-
NominalTypeDecl *inheritingDecl)
168-
: recordDecl(recordDecl), inheritingDecl(inheritingDecl), name(name) {
175+
ClangRecordMemberLookupDescriptor(NominalTypeDecl *recordDecl,
176+
DeclName name,
177+
NominalTypeDecl *inheritingDecl,
178+
clang::AccessSpecifier inheritance)
179+
: recordDecl(recordDecl), inheritingDecl(inheritingDecl), name(name),
180+
inheritance(inheritance) {
169181
assert(isa<clang::RecordDecl>(recordDecl->getClangDecl()));
170182
assert(isa<clang::CXXRecordDecl>(inheritingDecl->getClangDecl()));
183+
assert(inheritance != clang::AS_none && "");
171184
assert(recordDecl != inheritingDecl &&
172185
"recursive calls should lookup elsewhere");
173186
}

lib/ClangImporter/ClangImporter.cpp

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5938,9 +5938,6 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
59385938
bodyParams = ParameterList::createEmpty(ctx);
59395939
}
59405940

5941-
assert(baseClassVar->getFormalAccess() == AccessLevel::Public &&
5942-
"base class member must be public");
5943-
59445941
auto getterDecl = AccessorDecl::create(
59455942
ctx,
59465943
/*FuncLoc=*/SourceLoc(),
@@ -5953,7 +5950,7 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
59535950
: computedType,
59545951
declContext);
59555952
getterDecl->setIsTransparent(true);
5956-
getterDecl->setAccess(AccessLevel::Public);
5953+
getterDecl->copyFormalAccessFrom(computedVar);
59575954
getterDecl->setBodySynthesizer(useAddress
59585955
? synthesizeBaseClassFieldAddressGetterBody
59595956
: synthesizeBaseClassFieldGetterBody,
@@ -5988,7 +5985,7 @@ makeBaseClassMemberAccessors(DeclContext *declContext,
59885985
: TupleType::getEmpty(ctx),
59895986
declContext);
59905987
setterDecl->setIsTransparent(true);
5991-
setterDecl->setAccess(AccessLevel::Public);
5988+
setterDecl->copyFormalAccessFrom(computedVar);
59925989
setterDecl->setBodySynthesizer(useAddress
59935990
? synthesizeBaseClassFieldAddressSetterBody
59945991
: synthesizeBaseClassFieldSetterBody,
@@ -6041,8 +6038,17 @@ void cloneImportedAttributes(ValueDecl *fromDecl, ValueDecl* toDecl) {
60416038
}
60426039
}
60436040

6044-
static ValueDecl *
6045-
cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
6041+
static ValueDecl *cloneBaseMemberDecl(ValueDecl *decl,
6042+
DeclContext *newContext,
6043+
clang::AccessSpecifier inheritance) {
6044+
assert(inheritance != clang::AS_none &&
6045+
"public/protected/private inheritance was not specified");
6046+
static_assert(AccessLevel::Private < AccessLevel::Public &&
6047+
"std::min() relies on this ordering");
6048+
// Adjust access according to whichever is more restrictive, between what decl
6049+
// was declared with (in its base class) or what it is being inherited with.
6050+
AccessLevel access = std::min(decl->getFormalAccess(),
6051+
importer::convertClangAccess(inheritance));
60466052
ASTContext &context = decl->getASTContext();
60476053

60486054
if (auto fn = dyn_cast<FuncDecl>(decl)) {
@@ -6068,7 +6074,7 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
60686074
fn->getGenericParams(), fn->getParameters(),
60696075
fn->getResultInterfaceType(), newContext);
60706076
cloneImportedAttributes(decl, out);
6071-
out->copyFormalAccessFrom(fn);
6077+
out->setAccess(access);
60726078
out->setBodySynthesizer(synthesizeBaseClassMethodBody, fn);
60736079
out->setSelfAccessKind(fn->getSelfAccessKind());
60746080
return out;
@@ -6086,7 +6092,7 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
60866092
subscript->getStaticSpelling(), subscript->getSubscriptLoc(),
60876093
subscript->getIndices(), subscript->getNameLoc(), subscript->getElementInterfaceType(),
60886094
newContext, subscript->getGenericParams());
6089-
out->copyFormalAccessFrom(subscript);
6095+
out->setAccess(access);
60906096
out->setAccessors(SourceLoc(),
60916097
makeBaseClassMemberAccessors(newContext, out, subscript),
60926098
SourceLoc());
@@ -6110,7 +6116,7 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
61106116
out->setInterfaceType(var->getInterfaceType());
61116117
out->setIsObjC(var->isObjC());
61126118
out->setIsDynamic(var->isDynamic());
6113-
out->copyFormalAccessFrom(var);
6119+
out->setAccess(access);
61146120
out->getASTContext().evaluator.cacheOutput(HasStorageRequest{out}, false);
61156121
auto accessors = makeBaseClassMemberAccessors(newContext, out, var);
61166122
out->setAccessors(SourceLoc(), accessors, SourceLoc());
@@ -6136,7 +6142,7 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
61366142
typeAlias->getName(), typeAlias->getNameLoc(),
61376143
typeAlias->getGenericParams(), newContext);
61386144
out->setUnderlyingType(typeAlias->getUnderlyingType());
6139-
out->copyFormalAccessFrom(typeAlias);
6145+
out->setAccess(access);
61406146
return out;
61416147
}
61426148

@@ -6147,7 +6153,7 @@ cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
61476153
typeDecl->getLoc(), typeDecl->getLoc(), typeDecl->getName(),
61486154
typeDecl->getLoc(), nullptr, newContext);
61496155
out->setUnderlyingType(typeDecl->getInterfaceType());
6150-
out->copyFormalAccessFrom(typeDecl);
6156+
out->setAccess(access);
61516157
return out;
61526158
}
61536159

@@ -6159,7 +6165,7 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
61596165
NominalTypeDecl *recordDecl = desc.recordDecl;
61606166
NominalTypeDecl *inheritingDecl = desc.inheritingDecl;
61616167
DeclName name = desc.name;
6162-
6168+
clang::AccessSpecifier inheritance = desc.inheritance;
61636169
bool inheritedLookup = recordDecl != inheritingDecl;
61646170

61656171
auto &ctx = recordDecl->getASTContext();
@@ -6181,6 +6187,14 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
61816187
if (isa<clang::CXXConstructorDecl>(found) && isa<ClassDecl>(recordDecl))
61826188
continue;
61836189

6190+
// Skip this base class member if it is private.
6191+
//
6192+
// BUG: private base class members should be inherited but inaccessible.
6193+
// Skipping them here may affect accurate overload resolution in cases of
6194+
// multiple inheritance (which is currently buggy anyway).
6195+
if (inheritedLookup && found->getAccess() == clang::AS_private)
6196+
continue;
6197+
61846198
auto imported = clangModuleLoader->importDeclDirectly(found);
61856199
if (!imported)
61866200
continue;
@@ -6189,7 +6203,7 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
61896203
// by synthesizing getters and setters.
61906204
if (inheritedLookup) {
61916205
imported = clangModuleLoader->importBaseMemberDecl(
6192-
cast<ValueDecl>(imported), inheritingDecl);
6206+
cast<ValueDecl>(imported), inheritingDecl, inheritance);
61936207
if (!imported)
61946208
continue;
61956209
}
@@ -6207,8 +6221,18 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
62076221
namedMember->getName().getBaseName() != name)
62086222
continue;
62096223

6224+
auto memberClangDecl = namedMember->getClangDecl();
6225+
6226+
// Skip this base class if this is a case of nested private inheritance.
6227+
//
6228+
// BUG: private base class members should be inherited but inaccessible.
6229+
// Skipping them here may affect accurate overload resolution in cases of
6230+
// multiple inheritance (which is currently buggy anyway).
6231+
if (memberClangDecl->getAccess() == clang::AS_private)
6232+
continue;
6233+
62106234
if (auto imported = clangModuleLoader->importBaseMemberDecl(
6211-
namedMember, inheritingDecl))
6235+
namedMember, inheritingDecl, inheritance))
62126236
result.push_back(cast<ValueDecl>(imported));
62136237
}
62146238
}
@@ -6226,7 +6250,15 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
62266250
foundNameArities.insert(getArity(valueDecl));
62276251

62286252
for (auto base : cxxRecord->bases()) {
6229-
if (base.getAccessSpecifier() != clang::AccessSpecifier::AS_public)
6253+
clang::AccessSpecifier baseInheritance = base.getAccessSpecifier();
6254+
// Skip this base class if this is a case of nested private inheritance.
6255+
//
6256+
// BUG: members of private base classes should actually be imported but
6257+
// inaccessible. Skipping them here may affect accurate overload
6258+
// resolution in cases of multiple inheritance (which is currently buggy
6259+
// anyway).
6260+
if (inheritance != clang::AS_none &&
6261+
baseInheritance == clang::AS_private)
62306262
continue;
62316263

62326264
clang::QualType baseType = base.getType();
@@ -6242,12 +6274,19 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
62426274
if (cast<ValueDecl>(import)->getName() == name)
62436275
continue;
62446276

6277+
if (inheritance != clang::AS_none)
6278+
// For nested inheritance, clamp inheritance to least permissive level
6279+
// which is the largest numerical value for clang::AccessSpecifier
6280+
baseInheritance = std::max(inheritance, baseInheritance);
6281+
static_assert(clang::AS_private > clang::AS_protected &&
6282+
clang::AS_protected > clang::AS_public &&
6283+
"using std::max() relies on this ordering");
6284+
62456285
// Add Clang members that are imported lazily.
62466286
auto baseResults = evaluateOrDefault(
62476287
ctx.evaluator,
6248-
ClangRecordMemberLookup(
6249-
{cast<NominalTypeDecl>(import), name, inheritingDecl}),
6250-
{});
6288+
ClangRecordMemberLookup({cast<NominalTypeDecl>(import), name,
6289+
inheritingDecl, baseInheritance}), {});
62516290

62526291
for (auto foundInBase : baseResults) {
62536292
// Do not add duplicate entry with the same arity,
@@ -7507,18 +7546,13 @@ Decl *ClangImporter::importDeclDirectly(const clang::NamedDecl *decl) {
75077546
return Impl.importDecl(decl, Impl.CurrentVersion);
75087547
}
75097548

7510-
ValueDecl *ClangImporter::Implementation::importBaseMemberDecl(
7511-
ValueDecl *decl, DeclContext *newContext) {
7512-
// Do not clone private C++ decls.
7513-
if (decl->getFormalAccess() < AccessLevel::Public)
7514-
return nullptr;
7515-
7549+
ValueDecl *ClangImporter::Implementation::importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext, clang::AccessSpecifier inheritance) {
75167550
// Make sure we don't clone the decl again for this class, as that would
75177551
// result in multiple definitions of the same symbol.
75187552
std::pair<ValueDecl *, DeclContext *> key = {decl, newContext};
75197553
auto known = clonedBaseMembers.find(key);
75207554
if (known == clonedBaseMembers.end()) {
7521-
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext);
7555+
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext, inheritance);
75227556
known = clonedBaseMembers.insert({key, cloned}).first;
75237557
}
75247558

@@ -7536,8 +7570,9 @@ size_t ClangImporter::Implementation::getImportedBaseMemberDeclArity(
75367570
}
75377571

75387572
ValueDecl *ClangImporter::importBaseMemberDecl(ValueDecl *decl,
7539-
DeclContext *newContext) {
7540-
return Impl.importBaseMemberDecl(decl, newContext);
7573+
DeclContext *newContext,
7574+
clang::AccessSpecifier inheritance) {
7575+
return Impl.importBaseMemberDecl(decl, newContext, inheritance);
75417576
}
75427577

75437578
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {

0 commit comments

Comments
 (0)