Skip to content

Commit d2b562a

Browse files
authored
Merge pull request #76756 from tshortli/member-import-visibility-cxx
SE-0444: Fix interactions with Cxx interop
2 parents 6066418 + b11bb1c commit d2b562a

File tree

14 files changed

+149
-18
lines changed

14 files changed

+149
-18
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class ClangModuleLoader : public ModuleLoader {
147147
virtual void dumpSwiftLookupTables() const = 0;
148148

149149
/// Returns the module that contains imports and declarations from all loaded
150-
/// Objective-C header files.
150+
/// header files.
151151
virtual ModuleDecl *getImportedHeaderModule() const = 0;
152152

153153
/// Retrieves the Swift wrapper for the given Clang module, creating

include/swift/AST/Decl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,12 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
979979
LLVM_READONLY
980980
ModuleDecl *getModuleContext() const;
981981

982+
/// Retrieve the module in which this declaration would be found by name
983+
/// lookup queries. The result can differ from that of `getModuleContext()`
984+
/// when the decl was imported via Cxx interop.
985+
LLVM_READONLY
986+
ModuleDecl *getModuleContextForNameLookup() const;
987+
982988
/// getASTContext - Return the ASTContext that this decl lives in.
983989
LLVM_READONLY
984990
ASTContext &getASTContext() const {

include/swift/AST/Module.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,9 @@ class ModuleDecl
614614
void findDeclaredCrossImportOverlaysTransitive(
615615
SmallVectorImpl<ModuleDecl *> &overlays);
616616

617+
/// Returns true if this module is the Clang header import module.
618+
bool isClangHeaderImportModule() const;
619+
617620
/// Convenience accessor for clients that know what kind of file they're
618621
/// dealing with.
619622
SourceFile &getMainSourceFile() const;

lib/AST/Decl.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,42 @@ ModuleDecl *Decl::getModuleContext() const {
770770
return getDeclContext()->getParentModule();
771771
}
772772

773+
/// If `decl` is an imported Cxx decl, returns the actual module that the decl
774+
/// was imported from. This is necessary to compensate for the way that
775+
/// Cxx `namespace` declarations are imported. Since namespaces can span
776+
/// multiple Clang modules, the corresponding decls and all of their members get
777+
/// associated with the Clang imported header module (named `__ObjC`). This
778+
/// utility reaches through the Clang AST to find the actual module that members
779+
/// of namespaces originated from.
780+
static ModuleDecl *getModuleContextForNameLookupForCxxDecl(const Decl *decl) {
781+
auto &ctx = decl->getASTContext();
782+
if (!ctx.LangOpts.EnableCXXInterop)
783+
return nullptr;
784+
785+
if (!decl->hasClangNode())
786+
return nullptr;
787+
788+
auto parentModule = decl->getModuleContext();
789+
790+
// We only need to look for the real parent module when the existing parent
791+
// is the imported header module.
792+
if (!parentModule->isClangHeaderImportModule())
793+
return nullptr;
794+
795+
auto clangModule = decl->getClangDecl()->getOwningModule();
796+
if (!clangModule)
797+
return nullptr;
798+
799+
return ctx.getClangModuleLoader()->getWrapperForModule(clangModule);
800+
}
801+
802+
ModuleDecl *Decl::getModuleContextForNameLookup() const {
803+
if (auto parentModule = getModuleContextForNameLookupForCxxDecl(this))
804+
return parentModule;
805+
806+
return getModuleContext();
807+
}
808+
773809
/// Retrieve the diagnostic engine for diagnostics emission.
774810
DiagnosticEngine &Decl::getDiags() const {
775811
return getASTContext().Diags;
@@ -3946,7 +3982,7 @@ ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const {
39463982
std::optional<AttributedImport<ImportedModule>>
39473983
ValueDecl::findImport(const DeclContext *fromDC) const {
39483984
// If the type is from the current module, there's no import.
3949-
auto module = getModuleContext();
3985+
auto module = getModuleContextForNameLookup();
39503986
if (module == fromDC->getParentModule())
39513987
return std::nullopt;
39523988

lib/AST/Module.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,6 +2471,14 @@ bool ModuleDecl::getRequiredBystandersIfCrossImportOverlay(
24712471
return false;
24722472
}
24732473

2474+
bool ModuleDecl::isClangHeaderImportModule() const {
2475+
auto importer = getASTContext().getClangModuleLoader();
2476+
if (!importer)
2477+
return false;
2478+
2479+
return this == importer->getImportedHeaderModule();
2480+
}
2481+
24742482
namespace {
24752483
struct OverlayFileContents {
24762484
struct Module {

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2504,7 +2504,7 @@ bool DeclContext::lookupQualified(Type type,
25042504
}
25052505

25062506
bool DeclContext::isDeclImported(const Decl *decl) const {
2507-
auto declModule = decl->getDeclContext()->getParentModule();
2507+
auto declModule = decl->getModuleContextForNameLookup();
25082508
return getASTContext().getImportCache().isImportedBy(declModule, this);
25092509
}
25102510

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,7 @@ writeImports(raw_ostream &out, llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
404404
if (bridgingHeader.empty())
405405
return import != &M && import->getName() == M.getName();
406406

407-
auto importer = static_cast<ClangImporter *>(
408-
import->getASTContext().getClangModuleLoader());
409-
return import == importer->getImportedHeaderModule();
407+
return import->isClangHeaderImportModule();
410408
};
411409

412410
clang::FileSystemOptions fileSystemOptions;

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ class MissingImportFixItCache {
809809
static void diagnoseMissingImportForMember(const ValueDecl *decl,
810810
SourceFile *sf, SourceLoc loc) {
811811
auto &ctx = sf->getASTContext();
812-
auto definingModule = decl->getModuleContext();
812+
auto definingModule = decl->getModuleContextForNameLookup();
813813
ctx.Diags.diagnose(loc, diag::candidate_from_missing_import,
814814
decl->getDescriptiveKind(), decl->getName(),
815815
definingModule);
@@ -823,7 +823,7 @@ diagnoseAndFixMissingImportForMember(const ValueDecl *decl, SourceFile *sf,
823823
diagnoseMissingImportForMember(decl, sf, loc);
824824

825825
auto &ctx = sf->getASTContext();
826-
auto definingModule = decl->getModuleContext();
826+
auto definingModule = decl->getModuleContextForNameLookup();
827827
SourceLoc bestLoc = ctx.Diags.getBestAddImportFixItLoc(decl, sf);
828828
if (!bestLoc.isValid())
829829
return;
@@ -874,9 +874,18 @@ diagnoseAndFixMissingImportForMember(const ValueDecl *decl, SourceFile *sf,
874874
bool swift::maybeDiagnoseMissingImportForMember(const ValueDecl *decl,
875875
const DeclContext *dc,
876876
SourceLoc loc) {
877-
if (decl->findImport(dc))
877+
if (dc->isDeclImported(decl))
878878
return false;
879879

880+
if (dc->getASTContext().LangOpts.EnableCXXInterop) {
881+
// With Cxx interop enabled, there are some declarations that always belong
882+
// to the Clang header import module which should always be implicitly
883+
// visible. However, that module is not implicitly imported in source files
884+
// so we need to special case it here and avoid diagnosing.
885+
if (decl->getModuleContextForNameLookup()->isClangHeaderImportModule())
886+
return false;
887+
}
888+
880889
auto sf = dc->getParentSourceFile();
881890
if (!sf)
882891
return false;

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -744,11 +744,7 @@ IdentifierID Serializer::addContainingModuleRef(const DeclContext *DC,
744744
return CURRENT_MODULE_ID;
745745
if (M == this->M->getASTContext().TheBuiltinModule)
746746
return BUILTIN_MODULE_ID;
747-
748-
auto clangImporter =
749-
static_cast<ClangImporter *>(
750-
this->M->getASTContext().getClangModuleLoader());
751-
if (M == clangImporter->getImportedHeaderModule())
747+
if (M->isClangHeaderImportModule())
752748
return OBJC_HEADER_MODULE_ID;
753749

754750
auto exportedModuleName = file->getExportedModuleName();
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef TEST_INTEROP_CXX_CLASS_INPUTS_MEMBERS_DIRECT_H
2+
#define TEST_INTEROP_CXX_CLASS_INPUTS_MEMBERS_DIRECT_H
3+
4+
#include <members-transitive.h>
5+
6+
namespace DirectNamespace { }
7+
8+
namespace CommonNamespace {
9+
10+
struct DirectStruct {
11+
int memberVar;
12+
};
13+
14+
} // namespace CommonNamespace
15+
16+
CommonNamespace::TransitiveStruct returnsTransitiveStruct() {
17+
return CommonNamespace::TransitiveStruct{};
18+
}
19+
20+
TopLevelTransitiveStruct returnsTopLevelTransitiveStruct() {
21+
return TopLevelTransitiveStruct{};
22+
}
23+
24+
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_MEMBERS_DIRECT_H

0 commit comments

Comments
 (0)