[Importer] Ensure that we can see macro-expanded declarations in C++ namespaces

Lookup into C++ namespaces uses a different path from C++ record declarations.
Augment the C++ namespace lookup path to also account for the auxiliary
declarations introduced by peer macro expansions.
This commit is contained in:
Doug Gregor
2025-03-14 14:10:44 -07:00
parent e3618dd797
commit 84a4a8bedb
5 changed files with 95 additions and 29 deletions

View File

@@ -2750,8 +2750,24 @@ static void addNamespaceMembers(Decl *decl,
auto clangMember = found.get<clang::NamedDecl *>();
if (auto importedDecl =
ctx.getClangModuleLoader()->importDeclDirectly(clangMember)) {
if (addedMembers.insert(importedDecl).second)
if (addedMembers.insert(importedDecl).second) {
members.push_back(importedDecl);
// Handle macro-expanded declarations.
importedDecl->visitAuxiliaryDecls([&](Decl *decl) {
auto valueDecl = dyn_cast<ValueDecl>(decl);
if (!valueDecl)
return;
// Bail out if the auxiliary decl was not produced by a macro.
auto module = decl->getDeclContext()->getParentModule();
auto *sf = module->getSourceFileContainingLocation(decl->getLoc());
if (!sf || sf->Kind != SourceFileKind::MacroExpansion)
return;
members.push_back(valueDecl);
});
}
}
}
};

View File

@@ -5078,6 +5078,42 @@ ClangDirectLookupRequest::evaluate(Evaluator &evaluator,
return filteredDecls;
}
namespace {
/// Collects name lookup results into the given tiny vector, for use in the
/// various Clang importer lookup routines.
class CollectLookupResults {
DeclName name;
TinyPtrVector<ValueDecl *> &result;
public:
CollectLookupResults(DeclName name, TinyPtrVector<ValueDecl *> &result)
: name(name), result(result) { }
void add(ValueDecl *imported) {
result.push_back(imported);
// Expand any macros introduced by the Clang importer.
imported->visitAuxiliaryDecls([&](Decl *decl) {
auto valueDecl = dyn_cast<ValueDecl>(decl);
if (!valueDecl)
return;
// Bail out if the auxiliary decl was not produced by a macro.
auto module = decl->getDeclContext()->getParentModule();
auto *sf = module->getSourceFileContainingLocation(decl->getLoc());
if (!sf || sf->Kind != SourceFileKind::MacroExpansion)
return;
// Only produce results that match the requested name.
if (!valueDecl->getName().matchesRef(name))
return;
result.push_back(valueDecl);
});
}
};
}
TinyPtrVector<ValueDecl *> CXXNamespaceMemberLookup::evaluate(
Evaluator &evaluator, CXXNamespaceMemberLookupDescriptor desc) const {
EnumDecl *namespaceDecl = desc.namespaceDecl;
@@ -5087,6 +5123,8 @@ TinyPtrVector<ValueDecl *> CXXNamespaceMemberLookup::evaluate(
auto &ctx = namespaceDecl->getASTContext();
TinyPtrVector<ValueDecl *> result;
CollectLookupResults collector(name, result);
llvm::SmallPtrSet<clang::NamedDecl *, 8> importedDecls;
for (auto redecl : clangNamespaceDecl->redecls()) {
auto allResults = evaluateOrDefault(
@@ -5102,7 +5140,7 @@ TinyPtrVector<ValueDecl *> CXXNamespaceMemberLookup::evaluate(
continue;
if (auto import =
ctx.getClangModuleLoader()->importDeclDirectly(clangMember))
result.push_back(cast<ValueDecl>(import));
collector.add(cast<ValueDecl>(import));
}
}
@@ -6202,28 +6240,7 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
// The set of declarations we found.
TinyPtrVector<ValueDecl *> result;
auto addResult = [&result, name](ValueDecl *imported) {
result.push_back(imported);
// Expand any macros introduced by the Clang importer.
imported->visitAuxiliaryDecls([&](Decl *decl) {
auto valueDecl = dyn_cast<ValueDecl>(decl);
if (!valueDecl)
return;
// Bail out if the auxiliary decl was not produced by a macro.
auto module = decl->getDeclContext()->getParentModule();
auto *sf = module->getSourceFileContainingLocation(decl->getLoc());
if (!sf || sf->Kind != SourceFileKind::MacroExpansion)
return;
// Only produce results that match the requested name.
if (!valueDecl->getName().matchesRef(name))
return;
result.push_back(valueDecl);
});
};
CollectLookupResults collector(name, result);
// Find the results that are actually a member of "recordDecl".
ClangModuleLoader *clangModuleLoader = ctx.getClangModuleLoader();
@@ -6261,7 +6278,7 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
continue;
}
addResult(cast<ValueDecl>(imported));
collector.add(cast<ValueDecl>(imported));
}
if (inheritance) {
@@ -6280,7 +6297,7 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
if (!imported)
continue;
addResult(imported);
collector.add(imported);
}
}
@@ -6329,7 +6346,7 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
if (foundNameArities.count(getArity(foundInBase)))
continue;
addResult(foundInBase);
collector.add(foundInBase);
}
}
}

View File

@@ -329,6 +329,11 @@ void swift::performImportResolutionForClangMacroBuffer(
ImportResolver resolver(SF);
resolver.addImplicitImport(clangModule);
// FIXME: This is a hack that we shouldn't need, but be sure that we can
// see the Swift standard library.
if (auto stdlib = SF.getASTContext().getStdlibModule())
resolver.addImplicitImport(stdlib);
SF.setImports(resolver.getFinishedImports());
SF.setImportedUnderlyingModule(resolver.getUnderlyingClangModule());

View File

@@ -0,0 +1,28 @@
// REQUIRES: swift_feature_SafeInteropWrappers
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=upcoming-swift -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Namespace -source-filename=x | %FileCheck %s
// RUN: %target-swift-frontend -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers %t/namespace.swift -dump-macro-expansions -typecheck -verify
// CHECK: enum foo {
// CHECK: static func bar(_ p: UnsafeMutableBufferPointer<Float>)
//--- Inputs/module.modulemap
module Namespace {
header "namespace.h"
requires cplusplus
}
//--- Inputs/namespace.h
namespace foo {
__attribute__((swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(1), count: \"len\"))"))) void bar(float *p, int len);
}
//--- namespace.swift
import Namespace
func test(s: UnsafeMutableBufferPointer<Float>) {
foo.bar(s)
}

View File

@@ -2,11 +2,11 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUNx: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=upcoming-swift -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Method -source-filename=x | %FileCheck %s
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=upcoming-swift -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Method -source-filename=x | %FileCheck %s
// RUN: %target-swift-frontend -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers %t/method.swift -dump-macro-expansions -typecheck -verify
// CHECK: @_alwaysEmitIntoClient
// CHECK: public mutating func bar(_ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-SAME: public mutating func bar(_ p: UnsafeMutableBufferPointer<Float>)
//--- Inputs/module.modulemap
module Method {