Skip to content

Commit bb16ee0

Browse files
authored
Merge pull request #16211 from slavapestov/fix-inlinable-vs-autolinking
Plumb through support for 'usable from inline' imports
2 parents a8d831f + db44012 commit bb16ee0

21 files changed

+196
-26
lines changed

include/swift/AST/Attr.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,9 @@ SIMPLE_DECL_ATTR(_frozen, Frozen,
372372
OnEnum |
373373
UserInaccessible,
374374
76)
375+
SIMPLE_DECL_ATTR(_usableFromInline, UsableFromInlineImport,
376+
OnImport | UserInaccessible,
377+
77)
375378

376379
#undef TYPE_ATTR
377380
#undef DECL_ATTR_ALIAS

include/swift/AST/Decl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,10 +1549,19 @@ class ImportDecl final : public Decl,
15491549
return static_cast<ImportKind>(Bits.ImportDecl.ImportKind);
15501550
}
15511551

1552+
// An exported import is visible to name lookup from other modules, and is
1553+
// autolinked when the containing module is autolinked.
15521554
bool isExported() const {
15531555
return getAttrs().hasAttribute<ExportedAttr>();
15541556
}
15551557

1558+
// A usable from inline import is autolinked but not visible to name lookup.
1559+
// This attribute is inferred when type checking inlinable and default
1560+
// argument bodies.
1561+
bool isUsableFromInline() const {
1562+
return getAttrs().hasAttribute<UsableFromInlineImportAttr>();
1563+
}
1564+
15561565
ModuleDecl *getModule() const { return Mod; }
15571566
void setModule(ModuleDecl *M) { Mod = M; }
15581567

include/swift/AST/Module.h

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,17 @@ class ModuleDecl : public DeclContext, public TypeDecl {
345345

346346
/// \sa getImportedModules
347347
enum class ImportFilter {
348+
// Everything.
348349
All,
350+
351+
// @_exported only.
349352
Public,
350-
Private
353+
354+
// Not @_exported only. Also includes @_usableFromInline.
355+
Private,
356+
357+
// @_usableFromInline and @_exported only.
358+
ForLinking
351359
};
352360

353361
/// Looks up which modules are imported by this module.
@@ -360,11 +368,16 @@ class ModuleDecl : public DeclContext, public TypeDecl {
360368
/// Looks up which modules are imported by this module, ignoring any that
361369
/// won't contain top-level decls.
362370
///
363-
/// This is a performance hack. Do not use for anything but name lookup.
364-
/// May go away in the future.
371+
/// This is a performance hack for the ClangImporter. Do not use for
372+
/// anything but name lookup. May go away in the future.
365373
void
366374
getImportedModulesForLookup(SmallVectorImpl<ImportedModule> &imports) const;
367375

376+
/// Extension of the above hack. Identical to getImportedModulesForLookup()
377+
/// for imported modules, otherwise also includes @usableFromInline imports.
378+
void
379+
getImportedModulesForLinking(SmallVectorImpl<ImportedModule> &imports) const;
380+
368381
/// Finds all top-level decls of this module.
369382
///
370383
/// This does a simple local lookup, not recursively looking through imports.
@@ -402,11 +415,16 @@ class ModuleDecl : public DeclContext, public TypeDecl {
402415
/// results, with the given access path.
403416
/// \param fn A callback of type bool(ImportedModule) or void(ImportedModule).
404417
/// Return \c false to abort iteration.
418+
/// \param includeLinkOnlyModules Include modules that are not visible to
419+
/// name lookup but must be linked in because inlinable code can
420+
/// reference their symbols.
405421
///
406422
/// \return True if the traversal ran to completion, false if it ended early
407423
/// due to the callback.
408424
bool forAllVisibleModules(AccessPathTy topLevelAccessPath,
409-
llvm::function_ref<bool(ImportedModule)> fn);
425+
llvm::function_ref<bool(ImportedModule)> fn,
426+
bool includeLinkOnlyModules = false);
427+
410428

411429
/// @}
412430

@@ -638,6 +656,12 @@ class FileUnit : public DeclContext {
638656
return getImportedModules(imports, ModuleDecl::ImportFilter::Public);
639657
}
640658

659+
/// \see ModuleDecl::getImportedModulesForLinking
660+
virtual void getImportedModulesForLinking(
661+
SmallVectorImpl<ModuleDecl::ImportedModule> &imports) const {
662+
return getImportedModules(imports, ModuleDecl::ImportFilter::ForLinking);
663+
}
664+
641665
/// Generates the list of libraries needed to link this file, based on its
642666
/// imports.
643667
virtual void
@@ -649,11 +673,15 @@ class FileUnit : public DeclContext {
649673
///
650674
/// \param fn A callback of type bool(ImportedModule) or void(ImportedModule).
651675
/// Return \c false to abort iteration.
676+
/// \param includeLinkOnlyModules Include modules that are not visible to
677+
/// name lookup but must be linked in because inlinable code can
678+
/// reference their symbols.
652679
///
653680
/// \return True if the traversal ran to completion, false if it ended early
654681
/// due to the callback.
655682
bool
656-
forAllVisibleModules(llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn);
683+
forAllVisibleModules(llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn,
684+
bool includeLinkOnlyModules = false);
657685

658686
/// @}
659687

@@ -732,13 +760,17 @@ class SourceFile final : public FileUnit {
732760
};
733761

734762
/// Possible attributes for imports in source files.
735-
enum class ImportFlags {
763+
enum class ImportFlags : uint8_t {
736764
/// The imported module is exposed to anyone who imports the parent module.
737765
Exported = 0x1,
738766

739767
/// This source file has access to testable declarations in the imported
740768
/// module.
741-
Testable = 0x2
769+
Testable = 0x2,
770+
771+
/// Modules that depend on the module containing this source file will
772+
/// autolink this dependency.
773+
UsableFromInline = 0x4,
742774
};
743775

744776
/// \see ImportFlags

include/swift/ClangImporter/ClangModule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ class ClangModuleUnit final : public LoadedFile {
9797
virtual void getImportedModulesForLookup(
9898
SmallVectorImpl<ModuleDecl::ImportedModule> &imports) const override;
9999

100+
virtual void getImportedModulesForLinking(
101+
SmallVectorImpl<ModuleDecl::ImportedModule> &imports) const override {
102+
// In C, anything that's linkable is visible to the source language.
103+
return getImportedModulesForLookup(imports);
104+
}
105+
100106
virtual void
101107
collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override;
102108

include/swift/Serialization/ModuleFile.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,27 +132,40 @@ class ModuleFile
132132
const StringRef RawPath;
133133

134134
private:
135-
unsigned IsExported : 1;
136135
const unsigned IsHeader : 1;
136+
const unsigned IsExported : 1;
137+
const unsigned IsUsableFromInline : 1;
137138
const unsigned IsScoped : 1;
138139

139-
Dependency(StringRef path, bool isHeader, bool exported, bool isScoped)
140-
: RawPath(path), IsExported(exported), IsHeader(isHeader),
141-
IsScoped(isScoped) {}
140+
Dependency(bool isHeader,
141+
StringRef path, bool exported,
142+
bool isUsableFromInline, bool isScoped)
143+
: RawPath(path),
144+
IsHeader(isHeader),
145+
IsExported(exported),
146+
IsUsableFromInline(isUsableFromInline),
147+
IsScoped(isScoped) {
148+
assert(!(IsExported && IsUsableFromInline));
149+
assert(!(IsHeader && IsScoped));
150+
}
142151

143152
public:
144-
Dependency(StringRef path, bool exported, bool isScoped)
145-
: Dependency(path, false, exported, isScoped) {}
153+
Dependency(StringRef path, bool exported, bool isUsableFromInline,
154+
bool isScoped)
155+
: Dependency(false, path, exported, isUsableFromInline, isScoped) {}
146156

147157
static Dependency forHeader(StringRef headerPath, bool exported) {
148-
return Dependency(headerPath, true, exported, false);
158+
return Dependency(true, headerPath, exported,
159+
/*isUsableFromInline=*/false,
160+
/*isScoped=*/false);
149161
}
150162

151163
bool isLoaded() const {
152164
return Import.second != nullptr;
153165
}
154166

155167
bool isExported() const { return IsExported; }
168+
bool isUsableFromInline() const { return IsUsableFromInline; }
156169
bool isHeader() const { return IsHeader; }
157170
bool isScoped() const { return IsScoped; }
158171

include/swift/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t VERSION_MINOR = 411; // Last change: copy_block_without_escaping
58+
const uint16_t VERSION_MINOR = 412; // Last change: @usableFromInline import
5959

6060
using DeclIDField = BCFixed<31>;
6161

@@ -595,6 +595,7 @@ namespace input_block {
595595
using ImportedModuleLayout = BCRecordLayout<
596596
IMPORTED_MODULE,
597597
BCFixed<1>, // exported?
598+
BCFixed<1>, // usable from inlinable functions?
598599
BCFixed<1>, // scoped?
599600
BCBlob // module name, with submodule path pieces separated by \0s.
600601
// If the 'scoped' flag is set, the final path piece is an access

lib/AST/Module.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,11 @@ SourceFile::getImportedModules(SmallVectorImpl<ModuleDecl::ImportedModule> &modu
974974
if (importPair.second.contains(ImportFlags::Exported))
975975
continue;
976976
break;
977+
case ModuleDecl::ImportFilter::ForLinking:
978+
if (!importPair.second.contains(ImportFlags::UsableFromInline) &&
979+
!importPair.second.contains(ImportFlags::Exported))
980+
continue;
981+
break;
977982
}
978983

979984
modules.push_back(importPair.first);
@@ -985,6 +990,11 @@ void ModuleDecl::getImportedModulesForLookup(
985990
FORWARD(getImportedModulesForLookup, (modules));
986991
}
987992

993+
void ModuleDecl::getImportedModulesForLinking(
994+
SmallVectorImpl<ImportedModule> &modules) const {
995+
FORWARD(getImportedModulesForLinking, (modules));
996+
}
997+
988998
bool ModuleDecl::isSameAccessPath(AccessPathTy lhs, AccessPathTy rhs) {
989999
using AccessPathElem = std::pair<Identifier, SourceLoc>;
9901000
if (lhs.size() != rhs.size())
@@ -1128,11 +1138,15 @@ bool ModuleDecl::isSystemModule() const {
11281138
}
11291139

11301140
bool ModuleDecl::forAllVisibleModules(AccessPathTy thisPath,
1131-
llvm::function_ref<bool(ImportedModule)> fn) {
1141+
llvm::function_ref<bool(ImportedModule)> fn,
1142+
bool includeLinkOnlyModules) {
11321143
llvm::SmallSet<ImportedModule, 32, ModuleDecl::OrderImportedModules> visited;
11331144
SmallVector<ImportedModule, 32> stack;
11341145

1135-
getImportedModules(stack, ModuleDecl::ImportFilter::Public);
1146+
if (includeLinkOnlyModules)
1147+
getImportedModules(stack, ModuleDecl::ImportFilter::ForLinking);
1148+
else
1149+
getImportedModules(stack, ModuleDecl::ImportFilter::Public);
11361150

11371151
// Make sure the top-level module is first; we want pre-order-ish traversal.
11381152
stack.push_back(ImportedModule(thisPath, this));
@@ -1158,15 +1172,20 @@ bool ModuleDecl::forAllVisibleModules(AccessPathTy thisPath,
11581172
if (!fn(next))
11591173
return false;
11601174

1161-
next.second->getImportedModulesForLookup(stack);
1175+
if (includeLinkOnlyModules)
1176+
next.second->getImportedModulesForLinking(stack);
1177+
else
1178+
next.second->getImportedModulesForLookup(stack);
11621179
}
11631180

11641181
return true;
11651182
}
11661183

11671184
bool FileUnit::forAllVisibleModules(
1168-
llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn) {
1169-
if (!getParentModule()->forAllVisibleModules(ModuleDecl::AccessPathTy(), fn))
1185+
llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn,
1186+
bool includeLinkOnlyModules) {
1187+
if (!getParentModule()->forAllVisibleModules(ModuleDecl::AccessPathTy(), fn,
1188+
includeLinkOnlyModules))
11701189
return false;
11711190

11721191
if (auto SF = dyn_cast<SourceFile>(this)) {
@@ -1175,7 +1194,8 @@ bool FileUnit::forAllVisibleModules(
11751194
SmallVector<ModuleDecl::ImportedModule, 4> imports;
11761195
SF->getImportedModules(imports, ModuleDecl::ImportFilter::Private);
11771196
for (auto importPair : imports)
1178-
if (!importPair.second->forAllVisibleModules(importPair.first, fn))
1197+
if (!importPair.second->forAllVisibleModules(importPair.first, fn,
1198+
includeLinkOnlyModules))
11791199
return false;
11801200
}
11811201

@@ -1198,7 +1218,8 @@ SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const
11981218

11991219
next->collectLinkLibraries(callback);
12001220
return true;
1201-
});
1221+
},
1222+
/*includeLinkOnlyModules=*/true);
12021223
}
12031224

12041225
bool ModuleDecl::walk(ASTWalker &Walker) {

lib/ClangImporter/ClangImporter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3049,6 +3049,7 @@ void ClangModuleUnit::getImportedModules(
30493049
imports.push_back({ModuleDecl::AccessPathTy(), owner.getStdlibModule()});
30503050
break;
30513051
case ModuleDecl::ImportFilter::Public:
3052+
case ModuleDecl::ImportFilter::ForLinking:
30523053
break;
30533054
}
30543055

@@ -3058,6 +3059,7 @@ void ClangModuleUnit::getImportedModules(
30583059
switch (filter) {
30593060
case ModuleDecl::ImportFilter::All:
30603061
case ModuleDecl::ImportFilter::Public:
3062+
case ModuleDecl::ImportFilter::ForLinking:
30613063
imported.append(owner.ImportedHeaderExports.begin(),
30623064
owner.ImportedHeaderExports.end());
30633065
break;
@@ -3106,6 +3108,7 @@ void ClangModuleUnit::getImportedModules(
31063108
}
31073109

31083110
case ModuleDecl::ImportFilter::Public:
3111+
case ModuleDecl::ImportFilter::ForLinking:
31093112
break;
31103113
}
31113114
}

lib/Sema/NameBinding.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ void NameBinder::addImport(
235235
ImportOptions options;
236236
if (ID->isExported())
237237
options |= SourceFile::ImportFlags::Exported;
238+
if (ID->isUsableFromInline())
239+
options |= SourceFile::ImportFlags::UsableFromInline;
238240
if (testableAttr)
239241
options |= SourceFile::ImportFlags::Testable;
240242
imports.push_back({ { ID->getDeclPath(), M }, options });

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
112112
IGNORED_ATTR(UIApplicationMain)
113113
IGNORED_ATTR(UnsafeNoObjCTaggedPointer)
114114
IGNORED_ATTR(UsableFromInline)
115+
IGNORED_ATTR(UsableFromInlineImport)
115116
IGNORED_ATTR(WeakLinked)
116117
#undef IGNORED_ATTR
117118

@@ -840,6 +841,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
840841
IGNORED_ATTR(SynthesizedProtocol)
841842
IGNORED_ATTR(Testable)
842843
IGNORED_ATTR(Transparent)
844+
IGNORED_ATTR(UsableFromInlineImport)
843845
IGNORED_ATTR(WarnUnqualifiedAccess)
844846
IGNORED_ATTR(WeakLinked)
845847
#undef IGNORED_ATTR

lib/Sema/TypeCheckDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5775,6 +5775,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
57755775
UNINTERESTING_ATTR(ClangImporterSynthesizedType)
57765776
UNINTERESTING_ATTR(WeakLinked)
57775777
UNINTERESTING_ATTR(Frozen)
5778+
UNINTERESTING_ATTR(UsableFromInlineImport)
5779+
57785780
#undef UNINTERESTING_ATTR
57795781

57805782
void visitAvailableAttr(AvailableAttr *attr) {

lib/Serialization/ModuleFile.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,10 +1140,12 @@ ModuleFile::ModuleFile(
11401140
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
11411141
switch (kind) {
11421142
case input_block::IMPORTED_MODULE: {
1143-
bool exported, scoped;
1143+
bool exported, usableFromInline, scoped;
11441144
input_block::ImportedModuleLayout::readRecord(scratch,
1145-
exported, scoped);
1146-
Dependencies.push_back({blobData, exported, scoped});
1145+
exported,
1146+
usableFromInline,
1147+
scoped);
1148+
Dependencies.push_back({blobData, exported, usableFromInline, scoped});
11471149
break;
11481150
}
11491151
case input_block::LINK_LIBRARY: {
@@ -1598,6 +1600,13 @@ void ModuleFile::getImportedModules(
15981600
continue;
15991601

16001602
break;
1603+
1604+
case ModuleDecl::ImportFilter::ForLinking:
1605+
// Only include @_exported and @usableFromInline imports.
1606+
if (!dep.isExported() && !dep.isUsableFromInline())
1607+
continue;
1608+
1609+
break;
16011610
}
16021611

16031612
assert(dep.isLoaded());
@@ -1666,6 +1675,9 @@ void ModuleFile::getImportDecls(SmallVectorImpl<Decl *> &Results) {
16661675
if (Dep.isExported())
16671676
ID->getAttrs().add(
16681677
new (Ctx) ExportedAttr(/*IsImplicit=*/false));
1678+
if (Dep.isUsableFromInline())
1679+
ID->getAttrs().add(
1680+
new (Ctx) UsableFromInlineImportAttr(/*IsImplicit=*/true));
16691681
ImportDecls.push_back(ID);
16701682
}
16711683
Bits.ComputedImportDecls = true;

0 commit comments

Comments
 (0)