From 33e41f1281c0328fd2174f79fcd709eb42079a3e Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Wed, 18 Jun 2025 11:40:07 +0100 Subject: [PATCH] [cxx-interop] Fix duplicate symbol error with default arguments We synthesize a Swift function that only calls a C++ funtion that produces the default argument. We produce this function for each module that imports the C++ function with the default argument. This symbol needs to be public as it is created in the context of the Clang module and used from the Swift module. To avoid the linker errors, we always emit this function into the client which is also the right thing to do as the whole body is a single function call. rdar://138513915 --- lib/ClangImporter/SwiftDeclSynthesizer.cpp | 3 ++ .../default-arguments-multifile.swift | 46 +++++++++++++++++++ test/Interop/Cxx/function/lit.local.cfg | 6 +++ 3 files changed, 55 insertions(+) create mode 100644 test/Interop/Cxx/function/default-arguments-multifile.swift create mode 100644 test/Interop/Cxx/function/lit.local.cfg diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index 24e1a8d94e565..9ce81fbc0c0a8 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -12,6 +12,7 @@ #include "SwiftDeclSynthesizer.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/Attr.h" #include "swift/AST/AttrKind.h" #include "swift/AST/Builtins.h" #include "swift/AST/Decl.h" @@ -2508,6 +2509,8 @@ SwiftDeclSynthesizer::makeDefaultArgument(const clang::ParmVarDecl *param, ImporterImpl.ImportedHeaderUnit); funcDecl->setBodySynthesizer(synthesizeDefaultArgumentBody, (void *)param); funcDecl->setAccess(AccessLevel::Public); + funcDecl->getAttrs().add(new (ctx) + AlwaysEmitIntoClientAttr(/*IsImplicit=*/true)); ImporterImpl.defaultArgGenerators[param] = funcDecl; diff --git a/test/Interop/Cxx/function/default-arguments-multifile.swift b/test/Interop/Cxx/function/default-arguments-multifile.swift new file mode 100644 index 0000000000000..2dd3bc315d7b0 --- /dev/null +++ b/test/Interop/Cxx/function/default-arguments-multifile.swift @@ -0,0 +1,46 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: mkdir -p %t/artifacts + +// Multiple usages in the same module. +// RUN: %target-build-swift %t/main.swift %t/b.swift %t/c.swift -cxx-interoperability-mode=upcoming-swift -I %S/Inputs -o %t/artifacts/out +// RUN: %empty-directory(%t/artifacts) + +// Multiple usages across different modules. +// RUN: %target-build-swift -emit-library -module-name BarLibrary -emit-module -emit-module-path %t/artifacts/BarLibrary.swiftmodule %t/b.swift %t/c.swift -cxx-interoperability-mode=upcoming-swift -I %S/Inputs -o %t/artifacts/%target-library-name(BarLibrary) +// RUN: %target-build-swift %t/uses-library.swift -cxx-interoperability-mode=upcoming-swift -I %S/Inputs -I %t/artifacts -L %t/artifacts -lBarLibrary -o %t/artifacts/uses-library + +// FIXME: Windows test can be enabled once merge-modules step is removed from the old driver, +// or the Windows CI starts to use the new driver to compile the compiler. +// The windows toolchains still use the new driver so the CI failure worked +// around here should not affect users on Windows. +// UNSUPPORTED: OS=windows-msvc + +//--- main.swift +import DefaultArguments +public func foo() { + let _ = isZero() +} +foo() +bar() +baz() + +//--- b.swift +import DefaultArguments +public func bar() { + let _ = isZero() +} + +//--- c.swift +import DefaultArguments +public func baz() { + let _ = isZero(123) +} + +//--- uses-library.swift +import DefaultArguments +import BarLibrary + +let _ = isZero() +bar() +baz() diff --git a/test/Interop/Cxx/function/lit.local.cfg b/test/Interop/Cxx/function/lit.local.cfg new file mode 100644 index 0000000000000..4e6b2cfd49774 --- /dev/null +++ b/test/Interop/Cxx/function/lit.local.cfg @@ -0,0 +1,6 @@ +# Make a local copy of the environment. +config.environment = dict(config.environment) + +# FIXME: deserialization failure with the old driver in default-arguments-multifile.swift +if 'SWIFT_USE_OLD_DRIVER' in config.environment: del config.environment['SWIFT_USE_OLD_DRIVER'] +if 'SWIFT_AVOID_WARNING_USING_OLD_DRIVER' in config.environment: del config.environment['SWIFT_AVOID_WARNING_USING_OLD_DRIVER']