Skip to content

Commit f46ff7e

Browse files
Merge pull request #4954 from swiftwasm/main
[pull] swiftwasm from main
2 parents affb476 + 599874a commit f46ff7e

File tree

202 files changed

+660
-267
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

202 files changed

+660
-267
lines changed

include/swift/Frontend/FrontendOptions.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/Frontend/FrontendInputsAndOutputs.h"
2020
#include "swift/Frontend/InputFile.h"
2121
#include "llvm/ADT/Hashing.h"
22+
#include "llvm/ADT/Optional.h"
2223
#include "llvm/ADT/StringMap.h"
2324

2425
#include <string>
@@ -388,9 +389,16 @@ class FrontendOptions {
388389
/// '.../lib/swift', otherwise '.../lib/swift_static'.
389390
bool UseSharedResourceFolder = true;
390391

391-
/// Indicates whether to expose all public declarations in the generated clang
392+
enum class ClangHeaderExposeBehavior {
393+
/// Expose all public declarations in the generated header.
394+
AllPublic,
395+
/// Expose declarations only when they have expose attribute.
396+
HasExposeAttr
397+
};
398+
399+
/// Indicates which declarations should be exposed in the generated clang
392400
/// header.
393-
bool ExposePublicDeclsInClangHeader = false;
401+
llvm::Optional<ClangHeaderExposeBehavior> ClangHeaderExposedDecls;
394402

395403
/// Emit C++ bindings for the exposed Swift declarations in the generated
396404
/// clang header.

include/swift/Option/FrontendOptions.td

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,11 +1081,12 @@ def skip_import_in_public_interface:
10811081
HelpText<"Skip the import statement corresponding to a module name "
10821082
"when printing the public interface.">;
10831083

1084-
def clang_header_expose_public_decls:
1085-
Flag<["-"], "clang-header-expose-public-decls">,
1086-
HelpText<"Expose all public declarations in the generated clang header">,
1087-
Flags<[FrontendOption, HelpHidden]>;
1088-
1084+
def clang_header_expose_decls:
1085+
Joined<["-"], "clang-header-expose-decls=">,
1086+
HelpText<"Which declarations should be exposed in the generated clang header.">,
1087+
Flags<[FrontendOption, HelpHidden]>,
1088+
MetaVarName<"all-public|has-expose-attr">;
1089+
10891090
def weak_link_at_target :
10901091
Flag<["-"], "weak-link-at-target">,
10911092
HelpText<"Weakly link symbols for declarations that were introduced at the "

include/swift/SIL/SILDeclRef.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,12 @@ struct SILDeclRef {
556556

557557
bool isImplicit() const;
558558

559+
/// Whether the referenced function contains user code. This is generally true
560+
/// for a non-implicit decls, but may also be true for implicit decls if
561+
/// explicitly written code has been spliced into the body. This is the case
562+
/// for e.g a lazy variable getter.
563+
bool hasUserWrittenCode() const;
564+
559565
/// Return the scope in which the parent class of a method (i.e. class
560566
/// containing this declaration) can be subclassed, returning NotApplicable if
561567
/// this is not a method, there is no such class, or the class cannot be

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,13 @@ bool ArgsToFrontendOptionsConverter::convert(
284284
Opts.EnableIncrementalDependencyVerifier |= Args.hasArg(OPT_verify_incremental_dependencies);
285285
Opts.UseSharedResourceFolder = !Args.hasArg(OPT_use_static_resource_dir);
286286
Opts.DisableBuildingInterface = Args.hasArg(OPT_disable_building_interface);
287-
Opts.ExposePublicDeclsInClangHeader =
288-
Args.hasArg(OPT_clang_header_expose_public_decls);
287+
if (const Arg *A = Args.getLastArg(options::OPT_clang_header_expose_decls)) {
288+
Opts.ClangHeaderExposedDecls =
289+
llvm::StringSwitch<llvm::Optional<FrontendOptions::ClangHeaderExposeBehavior>>(A->getValue())
290+
.Case("all-public", FrontendOptions::ClangHeaderExposeBehavior::AllPublic)
291+
.Case("has-expose-attr", FrontendOptions::ClangHeaderExposeBehavior::HasExposeAttr)
292+
.Default(llvm::None);
293+
}
289294
Opts.EnableExperimentalCxxInteropInClangHeader =
290295
Args.hasArg(OPT_enable_experimental_cxx_interop_in_clang_header);
291296

lib/PrintAsClang/CMakeLists.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,37 @@
1+
set(datafiles
2+
_SwiftCxxInteroperability.h
3+
)
4+
5+
set(SWIFTLIB_DIR
6+
"${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib/swift")
7+
set(output_dir "${SWIFTLIB_DIR}/swiftToCxx")
8+
9+
add_custom_command(
10+
OUTPUT "${output_dir}"
11+
COMMAND ${CMAKE_COMMAND} "-E" "make_directory" "${output_dir}")
12+
13+
set (outputs)
14+
15+
foreach(input ${datafiles})
16+
set(source "${CMAKE_CURRENT_SOURCE_DIR}/${input}")
17+
set(dest "${output_dir}/${input}")
18+
add_custom_command(OUTPUT
19+
"${output_dir}/${input}"
20+
DEPENDS
21+
"${CMAKE_CURRENT_SOURCE_DIR}/${input}"
22+
COMMAND
23+
"${CMAKE_COMMAND}" "-E" "copy" "${source}" "${dest}")
24+
list(APPEND outputs "${output_dir}/${input}")
25+
endforeach()
26+
list(APPEND outputs "${output_dir}")
27+
28+
add_custom_target("copy_swiftToCxx_shims"
29+
DEPENDS "${output_dir}" "${outputs}"
30+
COMMENT "Copying Swift to C++ shims to ${output_dir}")
31+
32+
swift_install_in_component(FILES ${datafiles}
33+
DESTINATION "lib/swift/swiftToCxx"
34+
COMPONENT compiler)
135

236
add_swift_host_library(swiftPrintAsClang STATIC
337
ClangSyntaxPrinter.cpp
@@ -17,4 +51,7 @@ target_link_libraries(swiftPrintAsClang PRIVATE
1751
swiftIDE
1852
swiftIRGen)
1953

54+
add_dependencies(swiftPrintAsClang
55+
"copy_swiftToCxx_shims")
56+
2057
set_swift_llvm_is_available(swiftPrintAsClang)

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class ModuleWriter {
134134
llvm::raw_string_ostream outOfLineDefinitionsOS;
135135
DeclAndTypePrinter printer;
136136
OutputLanguageMode outputLangMode;
137+
bool dependsOnStdlib = false;
137138

138139
public:
139140
ModuleWriter(raw_ostream &os, raw_ostream &prologueOS,
@@ -149,6 +150,11 @@ class ModuleWriter {
149150

150151
PrimitiveTypeMapping &getTypeMapping() { return typeMapping; }
151152

153+
/// Returns true if a Stdlib dependency was seen during the emission of this module.
154+
bool isStdlibRequired() const {
155+
return dependsOnStdlib;
156+
}
157+
152158
/// Returns true if we added the decl's module to the import set, false if
153159
/// the decl is a local decl.
154160
///
@@ -159,8 +165,10 @@ class ModuleWriter {
159165

160166
if (otherModule == &M)
161167
return false;
162-
if (otherModule->isStdlibModule() ||
163-
otherModule->isBuiltinModule())
168+
if (otherModule->isStdlibModule()) {
169+
dependsOnStdlib = true;
170+
return true;
171+
} else if (otherModule->isBuiltinModule())
164172
return true;
165173
// Don't need a module for SIMD types in C.
166174
if (otherModule->getName() == M.getASTContext().Id_simd)
@@ -366,7 +374,8 @@ class ModuleWriter {
366374
return;
367375

368376
// Bridge, if necessary.
369-
TD = printer.getObjCTypeDecl(TD);
377+
if (outputLangMode != OutputLanguageMode::Cxx)
378+
TD = printer.getObjCTypeDecl(TD);
370379

371380
if (finder.needsDefinition() && isa<NominalTypeDecl>(TD)) {
372381
// We can delay individual members of classes; do so if necessary.
@@ -734,20 +743,22 @@ void swift::printModuleContentsAsObjC(
734743
.write();
735744
}
736745

737-
void swift::printModuleContentsAsCxx(
738-
raw_ostream &os, llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
746+
EmittedClangHeaderDependencyInfo swift::printModuleContentsAsCxx(
747+
raw_ostream &os,
739748
ModuleDecl &M, SwiftToClangInteropContext &interopContext,
740749
bool requiresExposedAttribute) {
741750
std::string moduleContentsBuf;
742751
llvm::raw_string_ostream moduleOS{moduleContentsBuf};
743752
std::string modulePrologueBuf;
744753
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
754+
EmittedClangHeaderDependencyInfo info;
745755

746756
// FIXME: Use getRequiredAccess once @expose is supported.
747-
ModuleWriter writer(moduleOS, prologueOS, imports, M, interopContext,
757+
ModuleWriter writer(moduleOS, prologueOS, info.imports, M, interopContext,
748758
AccessLevel::Public, requiresExposedAttribute,
749759
OutputLanguageMode::Cxx);
750760
writer.write();
761+
info.dependsOnStandardLibrary = writer.isStdlibRequired();
751762

752763
os << "#ifndef SWIFT_PRINTED_CORE\n";
753764
os << "#define SWIFT_PRINTED_CORE\n";
@@ -778,4 +789,5 @@ void swift::printModuleContentsAsCxx(
778789
ClangSyntaxPrinter(os).printNamespace(
779790
[&](raw_ostream &os) { M.ValueDecl::getName().print(os); },
780791
[&](raw_ostream &os) { os << moduleOS.str(); });
792+
return info;
781793
}

lib/PrintAsClang/ModuleContentsWriter.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,17 @@ void printModuleContentsAsObjC(raw_ostream &os,
3636
ModuleDecl &M,
3737
SwiftToClangInteropContext &interopContext);
3838

39-
/// Prints the declarations of \p M to \p os in C++ language mode and collects
40-
/// imports in \p imports along the way.
41-
void printModuleContentsAsCxx(raw_ostream &os,
42-
llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
39+
struct EmittedClangHeaderDependencyInfo {
40+
/// The set of imported modules used by this module.
41+
SmallPtrSet<ImportModuleTy, 8> imports;
42+
/// True if the printed module depends on types from the Stdlib module.
43+
bool dependsOnStandardLibrary = false;
44+
};
45+
46+
/// Prints the declarations of \p M to \p os in C++ language mode.
47+
///
48+
/// \returns Dependencies required by this module.
49+
EmittedClangHeaderDependencyInfo printModuleContentsAsCxx(raw_ostream &os,
4350
ModuleDecl &M,
4451
SwiftToClangInteropContext &interopContext,
4552
bool requiresExposedAttribute);

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,16 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
107107
out << "#include <stdlib.h>\n";
108108
out << "#include <new>\n";
109109
out << "#include <type_traits>\n";
110-
// FIXME: Look for the header in the SDK.
111110
out << "// Look for the C++ interop support header relative to clang's resource dir:\n";
112-
out << "// '<toolchain>/usr/lib/clang/<version>/include/../../../swift/shims'.\n";
113-
out << "#if __has_include(<../../../swift/shims/_SwiftCxxInteroperability.h>)\n";
114-
out << "#include <../../../swift/shims/_SwiftCxxInteroperability.h>\n";
115-
out << "// Alternatively, allow user to find the header using additional include path into 'swift'.\n";
116-
out << "#elif __has_include(<shims/_SwiftCxxInteroperability.h>)\n";
117-
out << "#include <shims/_SwiftCxxInteroperability.h>\n";
111+
out << "// '<toolchain>/usr/lib/clang/<version>/include/../../../swift/swiftToCxx'.\n";
112+
out << "#if __has_include(<../../../swift/swiftToCxx/_SwiftCxxInteroperability.h>)\n";
113+
out << "#include <../../../swift/swiftToCxx/_SwiftCxxInteroperability.h>\n";
114+
out << "#elif __has_include(<../../../../lib/swift/swiftToCxx/_SwiftCxxInteroperability.h>)\n";
115+
out << "// '<toolchain>/usr/local/lib/clang/<version>/include/../../../../lib/swift/swiftToCxx'.\n";
116+
out << "#include <../../../../lib/swift/swiftToCxx/_SwiftCxxInteroperability.h>\n";
117+
out << "// Alternatively, allow user to find the header using additional include path into '<toolchain>/lib/swift'.\n";
118+
out << "#elif __has_include(<swiftToCxx/_SwiftCxxInteroperability.h>)\n";
119+
out << "#include <swiftToCxx/_SwiftCxxInteroperability.h>\n";
118120
out << "#endif\n";
119121
},
120122
[&] {
@@ -495,16 +497,6 @@ static std::string computeMacroGuard(const ModuleDecl *M) {
495497
return (llvm::Twine(M->getNameStr().upper()) + "_SWIFT_H").str();
496498
}
497499

498-
static std::string getModuleContentsCxxString(
499-
ModuleDecl &M, SmallPtrSet<ImportModuleTy, 8> &imports,
500-
SwiftToClangInteropContext &interopContext, bool requiresExposedAttribute) {
501-
std::string moduleContentsBuf;
502-
llvm::raw_string_ostream moduleContents{moduleContentsBuf};
503-
printModuleContentsAsCxx(moduleContents, imports, M, interopContext,
504-
requiresExposedAttribute);
505-
return std::move(moduleContents.str());
506-
}
507-
508500
bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
509501
StringRef bridgingHeader,
510502
const FrontendOptions &frontendOpts,
@@ -524,18 +516,30 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
524516
emitObjCConditional(os, [&] { os << objcModuleContents.str(); });
525517
emitCxxConditional(os, [&] {
526518
// FIXME: Expose Swift with @expose by default.
527-
bool enableCxx = frontendOpts.ExposePublicDeclsInClangHeader ||
519+
bool enableCxx = frontendOpts.ClangHeaderExposedDecls.hasValue() ||
528520
frontendOpts.EnableExperimentalCxxInteropInClangHeader ||
529521
M->DeclContext::getASTContext().LangOpts.EnableCXXInterop;
530522
if (enableCxx) {
531-
SmallPtrSet<ImportModuleTy, 8> imports;
532-
auto contents = getModuleContentsCxxString(
533-
*M, imports, interopContext,
534-
/*requiresExposedAttribute=*/
535-
!frontendOpts.ExposePublicDeclsInClangHeader);
523+
bool requiresExplicitExpose = !frontendOpts.ClangHeaderExposedDecls.hasValue() ||
524+
*frontendOpts.ClangHeaderExposedDecls == FrontendOptions::ClangHeaderExposeBehavior::HasExposeAttr;
525+
// Default dependency behavior is used when the -clang-header-expose-decls flag is not specified.
526+
bool defaultDependencyBehavior = !frontendOpts.ClangHeaderExposedDecls.hasValue();
527+
528+
std::string moduleContentsBuf;
529+
llvm::raw_string_ostream moduleContents{moduleContentsBuf};
530+
auto deps = printModuleContentsAsCxx(moduleContents, *M, interopContext,
531+
/*requiresExposedAttribute=*/requiresExplicitExpose);
536532
// FIXME: In ObjC++ mode, we do not need to reimport duplicate modules.
537-
writeImports(os, imports, *M, bridgingHeader, /*useCxxImport=*/true);
538-
os << contents;
533+
writeImports(os, deps.imports, *M, bridgingHeader, /*useCxxImport=*/true);
534+
535+
// Embed the standard library directly.
536+
if (defaultDependencyBehavior && deps.dependsOnStandardLibrary) {
537+
assert(!M->isStdlibModule());
538+
SwiftToClangInteropContext interopContext(*M->getASTContext().getStdlibModule(), irGenOpts);
539+
printModuleContentsAsCxx(os, *M->getASTContext().getStdlibModule(), interopContext, /*requiresExposedAttribute=*/true);
540+
}
541+
542+
os << moduleContents.str();
539543
}
540544
});
541545
writeEpilogue(os);

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,74 @@ bool SILDeclRef::isImplicit() const {
284284
llvm_unreachable("Unhandled case in switch");
285285
}
286286

287+
bool SILDeclRef::hasUserWrittenCode() const {
288+
// Non-implicit decls generally have user-written code.
289+
if (!isImplicit()) {
290+
switch (kind) {
291+
case Kind::PropertyWrapperBackingInitializer: {
292+
// Only has user-written code if any of the property wrappers have
293+
// arguments to apply. Otherwise, it's just a forwarding initializer for
294+
// the wrappedValue.
295+
auto *var = cast<VarDecl>(getDecl());
296+
return llvm::any_of(var->getAttachedPropertyWrappers(), [&](auto *attr) {
297+
return attr->hasArgs();
298+
});
299+
}
300+
case Kind::PropertyWrapperInitFromProjectedValue:
301+
// Never has user-written code, is just a forwarding initializer.
302+
return false;
303+
default:
304+
// TODO: This checking is currently conservative, we ought to
305+
// exhaustively handle all the cases here, and use emitOrDelayFunction
306+
// in more cases to take advantage of it.
307+
return true;
308+
}
309+
llvm_unreachable("Unhandled case in switch!");
310+
}
311+
312+
// Implicit decls generally don't have user-written code, but some splice
313+
// user code into their body.
314+
switch (kind) {
315+
case Kind::Func: {
316+
// Lazy getters splice in the user-written initializer expr.
317+
if (auto *accessor = dyn_cast<AccessorDecl>(getFuncDecl())) {
318+
auto *storage = accessor->getStorage();
319+
if (accessor->isGetter() && !storage->isImplicit() &&
320+
storage->getAttrs().hasAttribute<LazyAttr>()) {
321+
return true;
322+
}
323+
}
324+
return false;
325+
}
326+
case Kind::StoredPropertyInitializer: {
327+
// Property wrapper initializers for the implicit backing storage can splice
328+
// in the user-written initializer on the original property.
329+
auto *var = cast<VarDecl>(getDecl());
330+
if (auto *originalProperty = var->getOriginalWrappedProperty()) {
331+
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType())
332+
return true;
333+
}
334+
return false;
335+
}
336+
case Kind::Allocator:
337+
case Kind::Initializer:
338+
case Kind::EnumElement:
339+
case Kind::Destroyer:
340+
case Kind::Deallocator:
341+
case Kind::GlobalAccessor:
342+
case Kind::DefaultArgGenerator:
343+
case Kind::IVarInitializer:
344+
case Kind::IVarDestroyer:
345+
case Kind::PropertyWrapperBackingInitializer:
346+
case Kind::PropertyWrapperInitFromProjectedValue:
347+
case Kind::EntryPoint:
348+
case Kind::AsyncEntryPoint:
349+
// Implicit decls for these don't splice in user-written code.
350+
return false;
351+
}
352+
llvm_unreachable("Unhandled case in switch!");
353+
}
354+
287355
namespace {
288356
enum class LinkageLimit {
289357
/// No limit.

lib/SILGen/SILGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ static void emitOrDelayFunction(SILGenModule &SGM,
11861186
// Implicit decls may be delayed if they can't be used externally.
11871187
auto linkage = constant.getLinkage(ForDefinition);
11881188
bool mayDelay = !forceEmission &&
1189-
(constant.isImplicit() &&
1189+
(!constant.hasUserWrittenCode() &&
11901190
!constant.isDynamicallyReplaceable() &&
11911191
!isPossiblyUsedExternally(linkage, SGM.M.isWholeModule()));
11921192

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,9 @@ Expr *swift::buildPropertyWrapperInitCall(
714714
ApplyExpr *innermostInit = nullptr;
715715

716716
// Projected-value initializers don't compose, so no need to iterate
717-
// over the wrapper attributes.
717+
// over the wrapper attributes. NOTE: If this ever changes, you'll need to
718+
// update SILDeclRef::hasUserWrittenCode to account for any spliced in
719+
// user-written code.
718720
if (initKind == PropertyWrapperInitKind::ProjectedValue) {
719721
auto typeExpr = TypeExpr::createImplicit(backingStorageType, ctx);
720722
auto *argList = ArgumentList::forImplicitSingle(ctx, ctx.Id_projectedValue,

0 commit comments

Comments
 (0)