From 80bc75ab9b973758b8be78c24eac2a3397f1c3dd Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Sun, 20 Mar 2022 20:22:02 -0700 Subject: [PATCH] [cxx-interop] Emit C++ declarations only when '-clang-header-expose-public-decl' is enabled This fix also ensures that we only emit C++ functions for now --- include/swift/Frontend/FrontendOptions.h | 4 ++++ include/swift/Option/FrontendOptions.td | 5 +++++ include/swift/PrintAsClang/PrintAsClang.h | 9 +++++---- lib/Frontend/ArgsToFrontendOptionsConverter.cpp | 2 ++ lib/FrontendTool/FrontendTool.cpp | 15 +++++++++------ lib/PrintAsClang/ModuleContentsWriter.cpp | 10 ++++++++-- lib/PrintAsClang/PrintAsClang.cpp | 5 +++-- .../SwiftToCxx/functions/cdecl-execution.cpp | 2 +- test/Interop/SwiftToCxx/functions/cdecl.swift | 2 +- .../functions/function-availability.swift | 2 +- .../functions/swift-functions-execution.cpp | 2 +- .../SwiftToCxx/functions/swift-functions.swift | 2 +- .../SwiftToCxx/module/module-to-namespace.swift | 2 +- test/PrintAsCxx/empty.swift | 2 +- 14 files changed, 43 insertions(+), 21 deletions(-) diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 9248cc4700b..340c3269e06 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -378,6 +378,10 @@ public: /// '.../lib/swift', otherwise '.../lib/swift_static'. bool UseSharedResourceFolder = true; + /// Indicates whether to expose all public declarations in the generated clang + /// header. + bool ExposePublicDeclsInClangHeader = false; + /// \return true if the given action only parses without doing other compilation steps. static bool shouldActionOnlyParse(ActionType); diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 3edff91a9aa..4f1f9d2fef0 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -1031,4 +1031,9 @@ def skip_import_in_public_interface: HelpText<"Skip the import statement corresponding to a module name " "when printing the public interface.">; +def clang_header_expose_public_decls: + Flag<["-"], "clang-header-expose-public-decls">, + HelpText<"Expose all public declarations in the generated clang header">, + Flags<[FrontendOption, HelpHidden]>; + } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/include/swift/PrintAsClang/PrintAsClang.h b/include/swift/PrintAsClang/PrintAsClang.h index a52699b330d..b7077a0828d 100644 --- a/include/swift/PrintAsClang/PrintAsClang.h +++ b/include/swift/PrintAsClang/PrintAsClang.h @@ -26,13 +26,14 @@ namespace swift { /// The Objective-C compatible declarations are printed into a block that /// ensures that those declarations are only usable when the header is /// compiled in Objective-C mode. - /// The C++ compatible declarations are printed into a block that ensures - /// that those declarations are only usable when the header is compiled in - /// C++ mode. + /// The C++ compatible declarations are printed into a block that ensures + /// that those declarations are only usable when the header is compiled in + /// C++ mode. /// /// Returns true on error. bool printAsClangHeader(raw_ostream &out, ModuleDecl *M, - StringRef bridgingHeader); + StringRef bridgingHeader, + bool ExposePublicDeclsInClangHeader); } #endif diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 02071f42c0c..db6f96ebaa6 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -274,6 +274,8 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.EnableIncrementalDependencyVerifier |= Args.hasArg(OPT_verify_incremental_dependencies); Opts.UseSharedResourceFolder = !Args.hasArg(OPT_use_static_resource_dir); Opts.DisableBuildingInterface = Args.hasArg(OPT_disable_building_interface); + Opts.ExposePublicDeclsInClangHeader = + Args.hasArg(OPT_clang_header_expose_public_decls); computeImportObjCHeaderOptions(); computeImplicitImportModuleNames(OPT_import_module, /*isTestable=*/false); diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 9317a20864f..8da6eb7f2a9 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -179,13 +179,15 @@ static bool writeSIL(SILModule &SM, const PrimarySpecificPaths &PSPs, /// /// \see swift::printAsClangHeader static bool printAsClangHeaderIfNeeded(StringRef outputPath, ModuleDecl *M, - StringRef bridgingHeader) { + StringRef bridgingHeader, + bool ExposePublicDeclsInClangHeader) { if (outputPath.empty()) return false; - return withOutputFile(M->getDiags(), outputPath, - [&](raw_ostream &out) -> bool { - return printAsClangHeader(out, M, bridgingHeader); - }); + return withOutputFile( + M->getDiags(), outputPath, [&](raw_ostream &out) -> bool { + return printAsClangHeader(out, M, bridgingHeader, + ExposePublicDeclsInClangHeader); + }); } /// Prints the stable module interface for \p M to \p outputPath. @@ -826,7 +828,8 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs( } hadAnyError |= printAsClangHeaderIfNeeded( Invocation.getClangHeaderOutputPathForAtMostOnePrimary(), - Instance.getMainModule(), BridgingHeaderPathForPrint); + Instance.getMainModule(), BridgingHeaderPathForPrint, + opts.ExposePublicDeclsInClangHeader); } // Only want the header if there's been any errors, ie. there's not much diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp index e7d2caaa4df..682a712cbcb 100644 --- a/lib/PrintAsClang/ModuleContentsWriter.cpp +++ b/lib/PrintAsClang/ModuleContentsWriter.cpp @@ -124,13 +124,15 @@ class ModuleWriter { std::vector declsToWrite; DelayedMemberSet delayedMembers; DeclAndTypePrinter printer; + OutputLanguageMode outputLangMode; public: ModuleWriter(raw_ostream &os, raw_ostream &prologueOS, llvm::SmallPtrSetImpl &imports, ModuleDecl &mod, AccessLevel access, OutputLanguageMode outputLang) : os(os), imports(imports), M(mod), - printer(M, os, prologueOS, delayedMembers, access, outputLang) {} + printer(M, os, prologueOS, delayedMembers, access, outputLang), + outputLangMode(outputLang) {} /// Returns true if we added the decl's module to the import set, false if /// the decl is a local decl. @@ -576,7 +578,11 @@ public: const Decl *D = declsToWrite.back(); bool success = true; - if (isa(D)) { + if (outputLangMode == OutputLanguageMode::Cxx) { + if (auto FD = dyn_cast(D)) + success = writeFunc(FD); + // FIXME: Warn on unsupported exported decl. + } else if (isa(D)) { if (auto CD = dyn_cast(D)) success = writeClass(CD); else if (auto PD = dyn_cast(D)) diff --git a/lib/PrintAsClang/PrintAsClang.cpp b/lib/PrintAsClang/PrintAsClang.cpp index 116067978d1..c9961870a9a 100644 --- a/lib/PrintAsClang/PrintAsClang.cpp +++ b/lib/PrintAsClang/PrintAsClang.cpp @@ -458,7 +458,8 @@ static std::string getModuleContentsCxxString(ModuleDecl &M) { } bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M, - StringRef bridgingHeader) { + StringRef bridgingHeader, + bool ExposePublicDeclsInClangHeader) { llvm::PrettyStackTraceString trace("While generating Clang header"); SmallPtrSet imports; @@ -472,7 +473,7 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M, emitObjCConditional(os, [&] { os << objcModuleContents.str(); }); emitCxxConditional(os, [&] { // FIXME: Expose Swift with @expose by default. - if (M->getASTContext().LangOpts.EnableCXXInterop) { + if (ExposePublicDeclsInClangHeader) { os << getModuleContentsCxxString(*M); } }); diff --git a/test/Interop/SwiftToCxx/functions/cdecl-execution.cpp b/test/Interop/SwiftToCxx/functions/cdecl-execution.cpp index ecef6bad7f3..0e1719fc52f 100644 --- a/test/Interop/SwiftToCxx/functions/cdecl-execution.cpp +++ b/test/Interop/SwiftToCxx/functions/cdecl-execution.cpp @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %S/cdecl.swift -typecheck -module-name CdeclFunctions -enable-cxx-interop -emit-clang-header-path %t/functions.h +// RUN: %target-swift-frontend %S/cdecl.swift -typecheck -module-name CdeclFunctions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h // RUN: %target-interop-build-clangxx -c %s -I %t -o %t/cdecl-execution.o // RUN: %target-interop-build-swift %S/cdecl.swift -o %t/cdecl-execution -Xlinker %t/cdecl-execution.o -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain diff --git a/test/Interop/SwiftToCxx/functions/cdecl.swift b/test/Interop/SwiftToCxx/functions/cdecl.swift index 94055be7bee..755165fffd7 100644 --- a/test/Interop/SwiftToCxx/functions/cdecl.swift +++ b/test/Interop/SwiftToCxx/functions/cdecl.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name CdeclFunctions -enable-cxx-interop -emit-clang-header-path %t/cdecl.h +// RUN: %target-swift-frontend %s -typecheck -module-name CdeclFunctions -clang-header-expose-public-decls -emit-clang-header-path %t/cdecl.h // RUN: %FileCheck %s < %t/cdecl.h // RUN: %check-interop-cxx-header-in-clang(%t/cdecl.h) diff --git a/test/Interop/SwiftToCxx/functions/function-availability.swift b/test/Interop/SwiftToCxx/functions/function-availability.swift index b3d9f7ca116..c026f6d1f37 100644 --- a/test/Interop/SwiftToCxx/functions/function-availability.swift +++ b/test/Interop/SwiftToCxx/functions/function-availability.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name Functions -enable-cxx-interop -emit-clang-header-path %t/functions.h +// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h // RUN: %FileCheck %s < %t/functions.h // RUN: %check-interop-cxx-header-in-clang(%t/functions.h) diff --git a/test/Interop/SwiftToCxx/functions/swift-functions-execution.cpp b/test/Interop/SwiftToCxx/functions/swift-functions-execution.cpp index e9c834d7b87..06d40a05b83 100644 --- a/test/Interop/SwiftToCxx/functions/swift-functions-execution.cpp +++ b/test/Interop/SwiftToCxx/functions/swift-functions-execution.cpp @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %S/swift-functions.swift -typecheck -module-name Functions -enable-cxx-interop -emit-clang-header-path %t/functions.h +// RUN: %target-swift-frontend %S/swift-functions.swift -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h // RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-functions-execution.o // RUN: %target-interop-build-swift %S/swift-functions.swift -o %t/swift-functions-execution -Xlinker %t/swift-functions-execution.o -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain diff --git a/test/Interop/SwiftToCxx/functions/swift-functions.swift b/test/Interop/SwiftToCxx/functions/swift-functions.swift index 6b889d20959..22d71bb44af 100644 --- a/test/Interop/SwiftToCxx/functions/swift-functions.swift +++ b/test/Interop/SwiftToCxx/functions/swift-functions.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name Functions -enable-cxx-interop -emit-clang-header-path %t/functions.h +// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h // RUN: %FileCheck %s < %t/functions.h // RUN: %check-interop-cxx-header-in-clang(%t/functions.h) diff --git a/test/Interop/SwiftToCxx/module/module-to-namespace.swift b/test/Interop/SwiftToCxx/module/module-to-namespace.swift index db53e90cd31..d9ff74fd5c1 100644 --- a/test/Interop/SwiftToCxx/module/module-to-namespace.swift +++ b/test/Interop/SwiftToCxx/module/module-to-namespace.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name Test -enable-cxx-interop -emit-clang-header-path %t/empty.h +// RUN: %target-swift-frontend %s -typecheck -module-name Test -clang-header-expose-public-decls -emit-clang-header-path %t/empty.h // RUN: %FileCheck %s < %t/empty.h // RUN: %check-interop-cxx-header-in-clang(%t/empty.h) diff --git a/test/PrintAsCxx/empty.swift b/test/PrintAsCxx/empty.swift index 317d3a8416f..2d45d28fb87 100644 --- a/test/PrintAsCxx/empty.swift +++ b/test/PrintAsCxx/empty.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -enable-cxx-interop -emit-clang-header-path %t/empty.h +// RUN: %target-swift-frontend %s -typecheck -clang-header-expose-public-decls -emit-clang-header-path %t/empty.h // RUN: %FileCheck %s < %t/empty.h // CHECK-LABEL: #ifndef EMPTY_SWIFT_H