Skip to content

Commit ccf11e0

Browse files
slavapestovjrose-apple
authored andcommitted
Merge pull request swiftlang#16211 from slavapestov/fix-inlinable-vs-autolinking
Plumb through support for 'usable from inline' imports (cherry picked from commit bb16ee0)
1 parent f0132e0 commit ccf11e0

21 files changed

+197
-26
lines changed

include/swift/AST/Attr.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ SIMPLE_DECL_ATTR(_weakLinked, WeakLinked,
348348

349349
SIMPLE_DECL_ATTR(_frozen, Frozen, OnEnum | UserInaccessible, 76)
350350

351+
SIMPLE_DECL_ATTR(_usableFromInline, UsableFromInlineImport,
352+
OnImport | UserInaccessible,
353+
77)
354+
351355
#undef TYPE_ATTR
352356
#undef DECL_ATTR_ALIAS
353357
#undef CONTEXTUAL_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
@@ -353,9 +353,17 @@ class ModuleDecl : public DeclContext, public TypeDecl {
353353

354354
/// \sa getImportedModules
355355
enum class ImportFilter {
356+
// Everything.
356357
All,
358+
359+
// @_exported only.
357360
Public,
358-
Private
361+
362+
// Not @_exported only. Also includes @_usableFromInline.
363+
Private,
364+
365+
// @_usableFromInline and @_exported only.
366+
ForLinking
359367
};
360368

361369
/// Looks up which modules are imported by this module.
@@ -368,11 +376,16 @@ class ModuleDecl : public DeclContext, public TypeDecl {
368376
/// Looks up which modules are imported by this module, ignoring any that
369377
/// won't contain top-level decls.
370378
///
371-
/// This is a performance hack. Do not use for anything but name lookup.
372-
/// May go away in the future.
379+
/// This is a performance hack for the ClangImporter. Do not use for
380+
/// anything but name lookup. May go away in the future.
373381
void
374382
getImportedModulesForLookup(SmallVectorImpl<ImportedModule> &imports) const;
375383

384+
/// Extension of the above hack. Identical to getImportedModulesForLookup()
385+
/// for imported modules, otherwise also includes @usableFromInline imports.
386+
void
387+
getImportedModulesForLinking(SmallVectorImpl<ImportedModule> &imports) const;
388+
376389
/// Finds all top-level decls of this module.
377390
///
378391
/// This does a simple local lookup, not recursively looking through imports.
@@ -410,11 +423,16 @@ class ModuleDecl : public DeclContext, public TypeDecl {
410423
/// results, with the given access path.
411424
/// \param fn A callback of type bool(ImportedModule) or void(ImportedModule).
412425
/// Return \c false to abort iteration.
426+
/// \param includeLinkOnlyModules Include modules that are not visible to
427+
/// name lookup but must be linked in because inlinable code can
428+
/// reference their symbols.
413429
///
414430
/// \return True if the traversal ran to completion, false if it ended early
415431
/// due to the callback.
416432
bool forAllVisibleModules(AccessPathTy topLevelAccessPath,
417-
llvm::function_ref<bool(ImportedModule)> fn);
433+
llvm::function_ref<bool(ImportedModule)> fn,
434+
bool includeLinkOnlyModules = false);
435+
418436

419437
/// @}
420438

@@ -646,6 +664,12 @@ class FileUnit : public DeclContext {
646664
return getImportedModules(imports, ModuleDecl::ImportFilter::Public);
647665
}
648666

667+
/// \see ModuleDecl::getImportedModulesForLinking
668+
virtual void getImportedModulesForLinking(
669+
SmallVectorImpl<ModuleDecl::ImportedModule> &imports) const {
670+
return getImportedModules(imports, ModuleDecl::ImportFilter::ForLinking);
671+
}
672+
649673
/// Generates the list of libraries needed to link this file, based on its
650674
/// imports.
651675
virtual void
@@ -657,11 +681,15 @@ class FileUnit : public DeclContext {
657681
///
658682
/// \param fn A callback of type bool(ImportedModule) or void(ImportedModule).
659683
/// Return \c false to abort iteration.
684+
/// \param includeLinkOnlyModules Include modules that are not visible to
685+
/// name lookup but must be linked in because inlinable code can
686+
/// reference their symbols.
660687
///
661688
/// \return True if the traversal ran to completion, false if it ended early
662689
/// due to the callback.
663690
bool
664-
forAllVisibleModules(llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn);
691+
forAllVisibleModules(llvm::function_ref<bool(ModuleDecl::ImportedModule)> fn,
692+
bool includeLinkOnlyModules = false);
665693

666694
/// @}
667695

@@ -740,13 +768,17 @@ class SourceFile final : public FileUnit {
740768
};
741769

742770
/// Possible attributes for imports in source files.
743-
enum class ImportFlags {
771+
enum class ImportFlags : uint8_t {
744772
/// The imported module is exposed to anyone who imports the parent module.
745773
Exported = 0x1,
746774

747775
/// This source file has access to testable declarations in the imported
748776
/// module.
749-
Testable = 0x2
777+
Testable = 0x2,
778+
779+
/// Modules that depend on the module containing this source file will
780+
/// autolink this dependency.
781+
UsableFromInline = 0x4,
750782
};
751783

752784
/// \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 = 409; // Last change: standalone requirement subs
58+
const uint16_t VERSION_MINOR = 410; // Last change: @usableFromInline import
5959

6060
using DeclIDField = BCFixed<31>;
6161

@@ -590,6 +590,7 @@ namespace input_block {
590590
using ImportedModuleLayout = BCRecordLayout<
591591
IMPORTED_MODULE,
592592
BCFixed<1>, // exported?
593+
BCFixed<1>, // usable from inlinable functions?
593594
BCFixed<1>, // scoped?
594595
BCBlob // module name, with submodule path pieces separated by \0s.
595596
// 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
@@ -3052,6 +3052,7 @@ void ClangModuleUnit::getImportedModules(
30523052
imports.push_back({ModuleDecl::AccessPathTy(), owner.getStdlibModule()});
30533053
break;
30543054
case ModuleDecl::ImportFilter::Public:
3055+
case ModuleDecl::ImportFilter::ForLinking:
30553056
break;
30563057
}
30573058

@@ -3061,6 +3062,7 @@ void ClangModuleUnit::getImportedModules(
30613062
switch (filter) {
30623063
case ModuleDecl::ImportFilter::All:
30633064
case ModuleDecl::ImportFilter::Public:
3065+
case ModuleDecl::ImportFilter::ForLinking:
30643066
imported.append(owner.ImportedHeaderExports.begin(),
30653067
owner.ImportedHeaderExports.end());
30663068
break;
@@ -3109,6 +3111,7 @@ void ClangModuleUnit::getImportedModules(
31093111
}
31103112

31113113
case ModuleDecl::ImportFilter::Public:
3114+
case ModuleDecl::ImportFilter::ForLinking:
31123115
break;
31133116
}
31143117
}

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

@@ -844,6 +845,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
844845
IGNORED_ATTR(SynthesizedProtocol)
845846
IGNORED_ATTR(Testable)
846847
IGNORED_ATTR(Transparent)
848+
IGNORED_ATTR(UsableFromInlineImport)
847849
IGNORED_ATTR(WarnUnqualifiedAccess)
848850
IGNORED_ATTR(WeakLinked)
849851
#undef IGNORED_ATTR

lib/Sema/TypeCheckDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5779,6 +5779,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
57795779
UNINTERESTING_ATTR(ClangImporterSynthesizedType)
57805780
UNINTERESTING_ATTR(WeakLinked)
57815781
UNINTERESTING_ATTR(Frozen)
5782+
UNINTERESTING_ATTR(UsableFromInlineImport)
5783+
57825784
#undef UNINTERESTING_ATTR
57835785

57845786
void visitAvailableAttr(AvailableAttr *attr) {

lib/Serialization/ModuleFile.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,10 +1136,12 @@ ModuleFile::ModuleFile(
11361136
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
11371137
switch (kind) {
11381138
case input_block::IMPORTED_MODULE: {
1139-
bool exported, scoped;
1139+
bool exported, usableFromInline, scoped;
11401140
input_block::ImportedModuleLayout::readRecord(scratch,
1141-
exported, scoped);
1142-
Dependencies.push_back({blobData, exported, scoped});
1141+
exported,
1142+
usableFromInline,
1143+
scoped);
1144+
Dependencies.push_back({blobData, exported, usableFromInline, scoped});
11431145
break;
11441146
}
11451147
case input_block::LINK_LIBRARY: {
@@ -1601,6 +1603,13 @@ void ModuleFile::getImportedModules(
16011603
continue;
16021604

16031605
break;
1606+
1607+
case ModuleDecl::ImportFilter::ForLinking:
1608+
// Only include @_exported and @usableFromInline imports.
1609+
if (!dep.isExported() && !dep.isUsableFromInline())
1610+
continue;
1611+
1612+
break;
16041613
}
16051614

16061615
assert(dep.isLoaded());
@@ -1669,6 +1678,9 @@ void ModuleFile::getImportDecls(SmallVectorImpl<Decl *> &Results) {
16691678
if (Dep.isExported())
16701679
ID->getAttrs().add(
16711680
new (Ctx) ExportedAttr(/*IsImplicit=*/false));
1681+
if (Dep.isUsableFromInline())
1682+
ID->getAttrs().add(
1683+
new (Ctx) UsableFromInlineImportAttr(/*IsImplicit=*/true));
16721684
ImportDecls.push_back(ID);
16731685
}
16741686
Bits.ComputedImportDecls = true;

0 commit comments

Comments
 (0)