Skip to content

Commit 42c6ff6

Browse files
committed
[interop][SwiftToCxx] Gather initial struct layout information and emit struct stubs with storage in C++
This change extends the clang header printer to start emitting C++ classes for Swift struct types with the correct struct layout in them (size + alignment)
1 parent a7053e4 commit 42c6ff6

17 files changed

+295
-51
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===--- IRABIDetailsProvider.h - Get ABI details for decls -----*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_IRGEN_IRABIDETAILSPROVIDER_H
14+
#define SWIFT_IRGEN_IRABIDETAILSPROVIDER_H
15+
16+
#include "llvm/ADT/Optional.h"
17+
#include <stdint.h>
18+
#include <utility>
19+
20+
namespace swift {
21+
22+
class IRGenOptions;
23+
class ModuleDecl;
24+
class NominalTypeDecl;
25+
26+
class IRABIDetailsProviderImpl;
27+
28+
/// Provides access to the IRGen-based queries that can be performed on
29+
/// declarations to get their various ABI details.
30+
class IRABIDetailsProvider {
31+
public:
32+
IRABIDetailsProvider(ModuleDecl &mod, const IRGenOptions &opts);
33+
~IRABIDetailsProvider();
34+
35+
using SizeType = uint64_t;
36+
37+
struct SizeAndAlignment {
38+
SizeType size;
39+
SizeType alignment;
40+
};
41+
42+
/// Returns the size and alignment for the given type, or \c None if the type
43+
/// is not a fixed layout type.
44+
llvm::Optional<SizeAndAlignment>
45+
getTypeSizeAlignment(const NominalTypeDecl *TD);
46+
47+
private:
48+
std::unique_ptr<IRABIDetailsProviderImpl> impl;
49+
};
50+
51+
} // namespace swift
52+
53+
#endif

include/swift/PrintAsClang/PrintAsClang.h

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,24 @@
1818
#include "swift/AST/Identifier.h"
1919

2020
namespace swift {
21-
class ModuleDecl;
22-
class ValueDecl;
21+
class IRGenOptions;
22+
class ModuleDecl;
23+
class ValueDecl;
2324

24-
/// Print the exposed declarations in a module into a Clang header.
25-
///
26-
/// The Objective-C compatible declarations are printed into a block that
27-
/// ensures that those declarations are only usable when the header is
28-
/// compiled in Objective-C mode.
29-
/// The C++ compatible declarations are printed into a block that ensures
30-
/// that those declarations are only usable when the header is compiled in
31-
/// C++ mode.
32-
///
33-
/// Returns true on error.
34-
bool printAsClangHeader(raw_ostream &out, ModuleDecl *M,
35-
StringRef bridgingHeader,
36-
bool ExposePublicDeclsInClangHeader);
25+
/// Print the exposed declarations in a module into a Clang header.
26+
///
27+
/// The Objective-C compatible declarations are printed into a block that
28+
/// ensures that those declarations are only usable when the header is
29+
/// compiled in Objective-C mode.
30+
/// The C++ compatible declarations are printed into a block that ensures
31+
/// that those declarations are only usable when the header is compiled in
32+
/// C++ mode.
33+
///
34+
/// Returns true on error.
35+
bool printAsClangHeader(raw_ostream &out, ModuleDecl *M,
36+
StringRef bridgingHeader,
37+
bool ExposePublicDeclsInClangHeader,
38+
const IRGenOptions &irGenOpts);
3739
}
3840

3941
#endif

lib/FrontendTool/FrontendTool.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,14 @@ static bool writeSIL(SILModule &SM, const PrimarySpecificPaths &PSPs,
180180
/// \see swift::printAsClangHeader
181181
static bool printAsClangHeaderIfNeeded(StringRef outputPath, ModuleDecl *M,
182182
StringRef bridgingHeader,
183-
bool ExposePublicDeclsInClangHeader) {
183+
bool ExposePublicDeclsInClangHeader,
184+
const IRGenOptions &irGenOpts) {
184185
if (outputPath.empty())
185186
return false;
186187
return withOutputFile(
187188
M->getDiags(), outputPath, [&](raw_ostream &out) -> bool {
188189
return printAsClangHeader(out, M, bridgingHeader,
189-
ExposePublicDeclsInClangHeader);
190+
ExposePublicDeclsInClangHeader, irGenOpts);
190191
});
191192
}
192193

@@ -859,7 +860,7 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs(
859860
hadAnyError |= printAsClangHeaderIfNeeded(
860861
Invocation.getClangHeaderOutputPathForAtMostOnePrimary(),
861862
Instance.getMainModule(), BridgingHeaderPathForPrint,
862-
opts.ExposePublicDeclsInClangHeader);
863+
opts.ExposePublicDeclsInClangHeader, Invocation.getIRGenOptions());
863864
}
864865

865866
// Only want the header if there's been any errors, ie. there's not much

lib/IRGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ add_swift_host_library(swiftIRGen STATIC
4040
GenTuple.cpp
4141
GenType.cpp
4242
GenValueWitness.cpp
43+
IRABIDetailsProvider.cpp
4344
IRGen.cpp
4445
IRGenDebugInfo.cpp
4546
IRGenFunction.cpp

lib/IRGen/IRABIDetailsProvider.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===--- IRABIDetailsProvider.cpp - Get ABI details for decls ---*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/IRGen/IRABIDetailsProvider.h"
14+
#include "FixedTypeInfo.h"
15+
#include "GenType.h"
16+
#include "IRGen.h"
17+
#include "IRGenModule.h"
18+
19+
#include "swift/AST/ASTContext.h"
20+
#include "swift/AST/IRGenOptions.h"
21+
#include "swift/AST/Types.h"
22+
#include "swift/SIL/SILModule.h"
23+
24+
using namespace swift;
25+
using namespace irgen;
26+
27+
namespace swift {
28+
29+
class IRABIDetailsProviderImpl {
30+
public:
31+
IRABIDetailsProviderImpl(ModuleDecl &mod, const IRGenOptions &opts)
32+
: typeConverter(mod),
33+
silMod(SILModule::createEmptyModule(&mod, typeConverter, silOpts)),
34+
IRGen(opts, *silMod), IGM(IRGen, IRGen.createTargetMachine()) {}
35+
36+
llvm::Optional<IRABIDetailsProvider::SizeAndAlignment>
37+
getTypeSizeAlignment(const NominalTypeDecl *TD) {
38+
auto *TI = &IGM.getTypeInfoForUnlowered(TD->getDeclaredTypeInContext());
39+
auto *fixedTI = dyn_cast<FixedTypeInfo>(TI);
40+
if (!fixedTI)
41+
return None;
42+
return IRABIDetailsProvider::SizeAndAlignment{
43+
fixedTI->getFixedSize().getValue(),
44+
fixedTI->getFixedAlignment().getValue()};
45+
}
46+
47+
private:
48+
Lowering::TypeConverter typeConverter;
49+
// Default silOptions are sufficient, as we don't need to generated SIL.
50+
SILOptions silOpts;
51+
std::unique_ptr<SILModule> silMod;
52+
IRGenerator IRGen;
53+
IRGenModule IGM;
54+
};
55+
56+
} // namespace swift
57+
58+
IRABIDetailsProvider::IRABIDetailsProvider(ModuleDecl &mod,
59+
const IRGenOptions &opts)
60+
: impl(std::make_unique<IRABIDetailsProviderImpl>(mod, opts)) {}
61+
62+
IRABIDetailsProvider::~IRABIDetailsProvider() {}
63+
64+
llvm::Optional<IRABIDetailsProvider::SizeAndAlignment>
65+
IRABIDetailsProvider::getTypeSizeAlignment(const NominalTypeDecl *TD) {
66+
return impl->getTypeSizeAlignment(TD);
67+
}

lib/PrintAsClang/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ add_swift_host_library(swiftPrintAsClang STATIC
66
PrimitiveTypeMapping.cpp
77
PrintAsClang.cpp
88
PrintClangFunction.cpp
9-
PrintClangValueType.cpp)
9+
PrintClangValueType.cpp
10+
SwiftToClangInteropContext.cpp)
1011
target_link_libraries(swiftPrintAsClang PRIVATE
1112
swiftAST
1213
swiftClangImporter
1314
swiftFrontend
14-
swiftIDE)
15+
swiftIDE
16+
swiftIRGen)
1517

1618
set_swift_llvm_is_available(swiftPrintAsClang)

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ class DeclAndTypePrinter::Implementation
332332
if (outputLang != OutputLanguageMode::Cxx)
333333
return;
334334
// FIXME: Print struct's availability.
335-
ClangValueTypePrinter printer(os);
335+
ClangValueTypePrinter printer(os, owningPrinter.interopContext);
336336
printer.printStructDecl(SD);
337337
}
338338

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ namespace swift {
2727

2828
class PrimitiveTypeMapping;
2929
class ValueDecl;
30+
class SwiftToClangInteropContext;
3031

3132
/// Responsible for printing a Swift Decl or Type in Objective-C, to be
3233
/// included in a Swift module's ObjC compatibility header.
@@ -43,6 +44,7 @@ class DeclAndTypePrinter {
4344
raw_ostream &prologueOS;
4445
const DelayedMemberSet &delayedMembers;
4546
PrimitiveTypeMapping &typeMapping;
47+
SwiftToClangInteropContext &interopContext;
4648
AccessLevel minRequiredAccess;
4749
OutputLanguageMode outputLang;
4850

@@ -56,11 +58,12 @@ class DeclAndTypePrinter {
5658
public:
5759
DeclAndTypePrinter(ModuleDecl &mod, raw_ostream &out, raw_ostream &prologueOS,
5860
DelayedMemberSet &delayed,
59-
PrimitiveTypeMapping &typeMapping, AccessLevel access,
60-
OutputLanguageMode outputLang)
61+
PrimitiveTypeMapping &typeMapping,
62+
SwiftToClangInteropContext &interopContext,
63+
AccessLevel access, OutputLanguageMode outputLang)
6164
: M(mod), os(out), prologueOS(prologueOS), delayedMembers(delayed),
62-
typeMapping(typeMapping), minRequiredAccess(access),
63-
outputLang(outputLang) {}
65+
typeMapping(typeMapping), interopContext(interopContext),
66+
minRequiredAccess(access), outputLang(outputLang) {}
6467

6568
/// Returns true if \p VD should be included in a compatibility header for
6669
/// the options the printer was constructed with.

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ class ModuleWriter {
131131
public:
132132
ModuleWriter(raw_ostream &os, raw_ostream &prologueOS,
133133
llvm::SmallPtrSetImpl<ImportModuleTy> &imports, ModuleDecl &mod,
134-
AccessLevel access, OutputLanguageMode outputLang)
134+
SwiftToClangInteropContext &interopContext, AccessLevel access,
135+
OutputLanguageMode outputLang)
135136
: os(os), imports(imports), M(mod),
136-
printer(M, os, prologueOS, delayedMembers, typeMapping, access,
137-
outputLang),
137+
printer(M, os, prologueOS, delayedMembers, typeMapping, interopContext,
138+
access, outputLang),
138139
outputLangMode(outputLang) {}
139140

140141
/// Returns true if we added the decl's module to the import set, false if
@@ -638,26 +639,25 @@ static AccessLevel getRequiredAccess(const ModuleDecl &M) {
638639
return M.isExternallyConsumed() ? AccessLevel::Public : AccessLevel::Internal;
639640
}
640641

641-
void
642-
swift::printModuleContentsAsObjC(raw_ostream &os,
643-
llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
644-
ModuleDecl &M) {
642+
void swift::printModuleContentsAsObjC(
643+
raw_ostream &os, llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
644+
ModuleDecl &M, SwiftToClangInteropContext &interopContext) {
645645
llvm::raw_null_ostream prologueOS;
646-
ModuleWriter(os, prologueOS, imports, M, getRequiredAccess(M),
646+
ModuleWriter(os, prologueOS, imports, M, interopContext, getRequiredAccess(M),
647647
OutputLanguageMode::ObjC)
648648
.write();
649649
}
650650

651651
void swift::printModuleContentsAsCxx(
652652
raw_ostream &os, llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
653-
ModuleDecl &M) {
653+
ModuleDecl &M, SwiftToClangInteropContext &interopContext) {
654654
std::string moduleContentsBuf;
655655
llvm::raw_string_ostream moduleOS{moduleContentsBuf};
656656
std::string modulePrologueBuf;
657657
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
658658

659-
ModuleWriter(moduleOS, prologueOS, imports, M, getRequiredAccess(M),
660-
OutputLanguageMode::Cxx)
659+
ModuleWriter(moduleOS, prologueOS, imports, M, interopContext,
660+
getRequiredAccess(M), OutputLanguageMode::Cxx)
661661
.write();
662662

663663
// FIXME: refactor.

lib/PrintAsClang/ModuleContentsWriter.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,23 @@ namespace clang {
2424

2525
namespace swift {
2626
class ModuleDecl;
27+
class SwiftToClangInteropContext;
2728

2829
using ImportModuleTy = PointerUnion<ModuleDecl*, const clang::Module*>;
2930

3031
/// Prints the declarations of \p M to \p os and collecting imports in
3132
/// \p imports along the way.
3233
void printModuleContentsAsObjC(raw_ostream &os,
3334
llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
34-
ModuleDecl &M);
35+
ModuleDecl &M,
36+
SwiftToClangInteropContext &interopContext);
3537

3638
/// Prints the declarations of \p M to \p os in C++ language mode and collects
3739
/// imports in \p imports along the way.
3840
void printModuleContentsAsCxx(raw_ostream &os,
3941
llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
40-
ModuleDecl &M);
42+
ModuleDecl &M,
43+
SwiftToClangInteropContext &interopContext);
4144

4245
} // end namespace swift
4346

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "swift/PrintAsClang/PrintAsClang.h"
1414

1515
#include "ModuleContentsWriter.h"
16+
#include "SwiftToClangInteropContext.h"
1617

1718
#include "swift/AST/ASTContext.h"
1819
#include "swift/AST/Module.h"
@@ -458,23 +459,28 @@ static std::string computeMacroGuard(const ModuleDecl *M) {
458459
return (llvm::Twine(M->getNameStr().upper()) + "_SWIFT_H").str();
459460
}
460461

461-
static std::string getModuleContentsCxxString(ModuleDecl &M) {
462+
static std::string
463+
getModuleContentsCxxString(ModuleDecl &M,
464+
SwiftToClangInteropContext &interopContext) {
462465
SmallPtrSet<ImportModuleTy, 8> imports;
463466
std::string moduleContentsBuf;
464467
llvm::raw_string_ostream moduleContents{moduleContentsBuf};
465-
printModuleContentsAsCxx(moduleContents, imports, M);
468+
printModuleContentsAsCxx(moduleContents, imports, M, interopContext);
466469
return moduleContents.str();
467470
}
468471

469472
bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
470473
StringRef bridgingHeader,
471-
bool ExposePublicDeclsInClangHeader) {
474+
bool ExposePublicDeclsInClangHeader,
475+
const IRGenOptions &irGenOpts) {
472476
llvm::PrettyStackTraceString trace("While generating Clang header");
473477

478+
SwiftToClangInteropContext interopContext(*M, irGenOpts);
479+
474480
SmallPtrSet<ImportModuleTy, 8> imports;
475481
std::string objcModuleContentsBuf;
476482
llvm::raw_string_ostream objcModuleContents{objcModuleContentsBuf};
477-
printModuleContentsAsObjC(objcModuleContents, imports, *M);
483+
printModuleContentsAsObjC(objcModuleContents, imports, *M, interopContext);
478484
writePrologue(os, M->getASTContext(), computeMacroGuard(M));
479485
emitObjCConditional(os,
480486
[&] { writeImports(os, imports, *M, bridgingHeader); });
@@ -483,7 +489,7 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
483489
emitCxxConditional(os, [&] {
484490
// FIXME: Expose Swift with @expose by default.
485491
if (ExposePublicDeclsInClangHeader) {
486-
os << getModuleContentsCxxString(*M);
492+
os << getModuleContentsCxxString(*M, interopContext);
487493
}
488494
});
489495
writeEpilogue(os);

0 commit comments

Comments
 (0)