From 67c7fbc87bfd9d89aa34886ecf42feb6745192d6 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 3 Oct 2025 11:35:25 -0700 Subject: [PATCH 1/2] [SE-0495] Make sure we can find imported C functions for @c @implementation @c @implementation relies on matching the original C declaration. The lookup for the original C declaration was doing the wrong kind of lookup, meaning that it could only find the C declaration if it came through a bridging header, and not through a normal module import. Using unqualified lookup here finds the name appropriately. Clarify the diagnostics here as well to not talk about umbrella and bridging headers. Fixes rdar://161909754. --- include/swift/AST/DiagnosticsSema.def | 8 ++++---- lib/AST/UnqualifiedLookup.cpp | 3 +++ lib/ClangImporter/ClangImporter.cpp | 16 ++++++++++++---- .../Inputs/accessibility_other.swift | 2 +- test/NameLookup/accessibility.swift | 4 ++-- test/decl/ext/Inputs/c_decls.h | 1 + test/decl/ext/Inputs/module.modulemap | 3 +++ .../ext/cdecl_official_implementation.swift | 18 ++++++++++++------ test/decl/ext/objc_implementation.swift | 14 +++++++------- .../objc_implementation_early_adopter.swift | 14 +++++++------- 10 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 test/decl/ext/Inputs/c_decls.h create mode 100644 test/decl/ext/Inputs/module.modulemap diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index b07b9544dc3d3..e060a8dd6261e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1879,12 +1879,12 @@ ERROR(objc_implementation_cannot_have_generics,none, "'@objc @implementation' cannot be used to implement %kind0", (ValueDecl *)) ERROR(attr_objc_implementation_category_not_found,none, - "could not find category %0 on Objective-C class %1; make sure your " - "umbrella or bridging header imports the header that declares it", + "could not find category %0 on Objective-C class %1; make sure you " + "import the module or header that declares it", (Identifier, ValueDecl*)) ERROR(attr_objc_implementation_func_not_found,none, - "could not find imported function '%0' matching %kind1; make sure your " - "umbrella or bridging header imports the header that declares it", + "could not find imported function '%0' matching %kind1; make sure you " + "import the module or header that declares it", (StringRef, ValueDecl*)) NOTE(attr_objc_implementation_fixit_remove_category_name,none, "remove arguments to implement the main '@interface' for this class", diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 51820b41a9ca8..45f6ed4b3fcb1 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -483,6 +483,9 @@ void UnqualifiedLookupFactory::addImportedResults(const DeclContext *const dc) { nlOptions |= NL_ExcludeMacroExpansions; if (options.contains(Flags::ABIProviding)) nlOptions |= NL_ABIProviding; + if (options.contains(Flags::IgnoreAccessControl)) + nlOptions |= NL_IgnoreAccessControl; + lookupInModule(dc, Name.getFullName(), CurModuleResults, NLKind::UnqualifiedLookup, resolutionKind, dc, Loc, nlOptions); diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 8f5648145d350..9d0bed0087c8d 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -6689,15 +6689,23 @@ static void lookupRelatedFuncs(AbstractFunctionDecl *func, else swiftName = func->getName(); - NLOptions options = NL_IgnoreAccessControl | NL_IgnoreMissingImports; if (auto ty = func->getDeclContext()->getSelfNominalTypeDecl()) { + NLOptions options = NL_IgnoreAccessControl | NL_IgnoreMissingImports; ty->lookupQualified({ ty }, DeclNameRef(swiftName), func->getLoc(), NL_QualifiedDefault | options, results); } else { - auto mod = func->getDeclContext()->getParentModule(); - mod->lookupQualified(mod, DeclNameRef(swiftName), func->getLoc(), - NL_RemoveOverridden | options, results); + ASTContext &ctx = func->getASTContext(); + UnqualifiedLookupOptions options = + UnqualifiedLookupFlags::IgnoreAccessControl; + UnqualifiedLookupDescriptor descriptor( + DeclNameRef(ctx, Identifier(), swiftName), func->getDeclContext(), + func->getLoc(), options); + auto lookup = evaluateOrDefault(func->getASTContext().evaluator, + UnqualifiedLookupRequest{descriptor}, {}); + for (const auto &result : lookup) { + results.push_back(result.getValueDecl()); + } } } diff --git a/test/NameLookup/Inputs/accessibility_other.swift b/test/NameLookup/Inputs/accessibility_other.swift index 8fcfbd44739b2..4c001873d1ea0 100644 --- a/test/NameLookup/Inputs/accessibility_other.swift +++ b/test/NameLookup/Inputs/accessibility_other.swift @@ -2,7 +2,7 @@ import has_accessibility public let a = 0 // expected-note * {{did you mean 'a'?}} internal let b = 0 // expected-note * {{did you mean 'b'?}} -private let c = 0 // expected-note {{'c' declared here}} +private let c = 0 // expected-note 2 {{'c' declared here}} extension Foo { public static func a() {} diff --git a/test/NameLookup/accessibility.swift b/test/NameLookup/accessibility.swift index eac3b6b186d0b..4c3524ed5860a 100644 --- a/test/NameLookup/accessibility.swift +++ b/test/NameLookup/accessibility.swift @@ -37,7 +37,7 @@ markUsed(z) // expected-error {{cannot find 'z' in scope}} markUsed(a) markUsed(b) -markUsed(c) // expected-error {{cannot find 'c' in scope}} +markUsed(c) // expected-error {{'c' is inaccessible due to 'private' protection level}} Foo.x() Foo.y() // expected-error {{'y' is inaccessible due to 'internal' protection level}} @@ -64,7 +64,7 @@ _ = PrivateInit() // expected-error {{'PrivateInit' initializer is inaccessible // TESTABLE: :[[@LINE-1]]:{{[^:]+}}: error: 'PrivateInit' initializer is inaccessible due to 'private' protection level var s = StructWithPrivateSetter() -// expected-note@-1 3{{did you mean 's'?}} +// expected-note@-1 2{{did you mean 's'?}} s.x = 42 // expected-error {{cannot assign to property: 'x' setter is inaccessible}} class Sub : Base { diff --git a/test/decl/ext/Inputs/c_decls.h b/test/decl/ext/Inputs/c_decls.h new file mode 100644 index 0000000000000..9f9526fec249c --- /dev/null +++ b/test/decl/ext/Inputs/c_decls.h @@ -0,0 +1 @@ +double c_function_returns_double(void); diff --git a/test/decl/ext/Inputs/module.modulemap b/test/decl/ext/Inputs/module.modulemap new file mode 100644 index 0000000000000..796a273ec3dd7 --- /dev/null +++ b/test/decl/ext/Inputs/module.modulemap @@ -0,0 +1,3 @@ +module ToBeImplemented { + header "c_decls.h" +} diff --git a/test/decl/ext/cdecl_official_implementation.swift b/test/decl/ext/cdecl_official_implementation.swift index d0d596d87bc19..87ddea64ccd72 100644 --- a/test/decl/ext/cdecl_official_implementation.swift +++ b/test/decl/ext/cdecl_official_implementation.swift @@ -1,5 +1,6 @@ // RUN: %target-typecheck-verify-swift -target %target-stable-abi-triple \ // RUN: -import-bridging-header %S/Inputs/objc_implementation.h \ +// RUN: -I %S/Inputs \ // RUN: -disable-objc-interop \ // RUN: -enable-experimental-feature CImplementation \ // RUN: -enable-experimental-feature CDecl @@ -7,6 +8,11 @@ // REQUIRES: swift_feature_CImplementation // REQUIRES: swift_feature_CDecl +import ToBeImplemented + +@implementation @c +func c_function_returns_double() -> Double { 0 } + @implementation @c func CImplFunc1(_: Int32) { // OK @@ -24,7 +30,7 @@ func CImplFunc2(_: Int32) { @implementation @c func CImplFuncMissing(_: Int32) { - // expected-error@-2 {{could not find imported function 'CImplFuncMissing' matching global function 'CImplFuncMissing'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'CImplFuncMissing' matching global function 'CImplFuncMissing'; make sure you import the module or header that declares it}} } @implementation @c @@ -39,13 +45,13 @@ func CImplFuncMismatch2(_: Int32) -> Float { @implementation @c(CImplFuncNameMismatch1) func mismatchedName1(_: Int32) { - // expected-error@-2 {{could not find imported function 'CImplFuncNameMismatch1' matching global function 'mismatchedName1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'CImplFuncNameMismatch1' matching global function 'mismatchedName1'; make sure you import the module or header that declares it}} // FIXME: Improve diagnostic for a partial match. } @implementation @c(mismatchedName2) func CImplFuncNameMismatch2(_: Int32) { - // expected-error@-2 {{could not find imported function 'mismatchedName2' matching global function 'CImplFuncNameMismatch2'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'mismatchedName2' matching global function 'CImplFuncNameMismatch2'; make sure you import the module or header that declares it}} // FIXME: Improve diagnostic for a partial match. } @@ -56,14 +62,14 @@ var cImplComputedGlobal1: Int32 { @implementation @c(CImplGetComputedGlobal1) get { // FIXME: Lookup for vars isn't working yet - // expected-error@-3 {{could not find imported function 'CImplGetComputedGlobal1' matching getter for var 'cImplComputedGlobal1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-3 {{could not find imported function 'CImplGetComputedGlobal1' matching getter for var 'cImplComputedGlobal1'; make sure you import the module or header that declares it}} return 0 } @implementation @c(CImplSetComputedGlobal1) set { // FIXME: Lookup for vars isn't working yet - // expected-error@-3 {{could not find imported function 'CImplSetComputedGlobal1' matching setter for var 'cImplComputedGlobal1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-3 {{could not find imported function 'CImplSetComputedGlobal1' matching setter for var 'cImplComputedGlobal1'; make sure you import the module or header that declares it}} print(newValue) } } @@ -77,6 +83,6 @@ extension CImplStruct { // FIXME: Add underlying support for this // expected-error@-3 {{@c can only be applied to global functions}} // FIXME: Lookup in an enclosing type is not working yet - // expected-error@-5 {{could not find imported function 'CImplStructStaticFunc1' matching static method 'staticFunc1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-5 {{could not find imported function 'CImplStructStaticFunc1' matching static method 'staticFunc1'; make sure you import the module or header that declares it}} } } diff --git a/test/decl/ext/objc_implementation.swift b/test/decl/ext/objc_implementation.swift index 73382ad12f3b6..1b7f852347815 100644 --- a/test/decl/ext/objc_implementation.swift +++ b/test/decl/ext/objc_implementation.swift @@ -503,7 +503,7 @@ protocol EmptySwiftProto {} // expected-warning@-1 {{extension with Objective-C category name 'PresentAdditions' conflicts with previous extension with the same category name; this is an error in the Swift 6 language mode}} @objc(MissingAdditions) @implementation extension ObjCClass {} -// expected-error@-1 {{could not find category 'MissingAdditions' on Objective-C class 'ObjCClass'; make sure your umbrella or bridging header imports the header that declares it}} +// expected-error@-1 {{could not find category 'MissingAdditions' on Objective-C class 'ObjCClass'; make sure you import the module or header that declares it}} // expected-note@-2 {{remove arguments to implement the main '@interface' for this class}} {{6-24=}} @objc @implementation extension ObjCStruct {} @@ -558,7 +558,7 @@ func CImplFunc2(_: Int32) { @implementation @_cdecl("CImplFuncMissing") func CImplFuncMissing(_: Int32) { - // expected-error@-2 {{could not find imported function 'CImplFuncMissing' matching global function 'CImplFuncMissing'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'CImplFuncMissing' matching global function 'CImplFuncMissing'; make sure you import the module or header that declares it}} } @implementation @_cdecl("CImplFuncMismatch1") @@ -614,13 +614,13 @@ func CImplFuncMismatch6a(_: Int32) -> Any! { @implementation @_cdecl("CImplFuncNameMismatch1") func mismatchedName1(_: Int32) { - // expected-error@-2 {{could not find imported function 'CImplFuncNameMismatch1' matching global function 'mismatchedName1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'CImplFuncNameMismatch1' matching global function 'mismatchedName1'; make sure you import the module or header that declares it}} // FIXME: Improve diagnostic for a partial match. } @implementation @_cdecl("mismatchedName2") func CImplFuncNameMismatch2(_: Int32) { - // expected-error@-2 {{could not find imported function 'mismatchedName2' matching global function 'CImplFuncNameMismatch2'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'mismatchedName2' matching global function 'CImplFuncNameMismatch2'; make sure you import the module or header that declares it}} // FIXME: Improve diagnostic for a partial match. } @@ -631,14 +631,14 @@ var cImplComputedGlobal1: Int32 { @implementation @_cdecl("CImplGetComputedGlobal1") get { // FIXME: Lookup for vars isn't working yet - // expected-error@-3 {{could not find imported function 'CImplGetComputedGlobal1' matching getter for var 'cImplComputedGlobal1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-3 {{could not find imported function 'CImplGetComputedGlobal1' matching getter for var 'cImplComputedGlobal1'; make sure you import the module or header that declares it}} return 0 } @implementation @_cdecl("CImplSetComputedGlobal1") set { // FIXME: Lookup for vars isn't working yet - // expected-error@-3 {{could not find imported function 'CImplSetComputedGlobal1' matching setter for var 'cImplComputedGlobal1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-3 {{could not find imported function 'CImplSetComputedGlobal1' matching setter for var 'cImplComputedGlobal1'; make sure you import the module or header that declares it}} print(newValue) } } @@ -652,7 +652,7 @@ extension CImplStruct { // FIXME: Add underlying support for this // expected-error@-3 {{@_cdecl can only be applied to global functions}} // FIXME: Lookup in an enclosing type is not working yet - // expected-error@-5 {{could not find imported function 'CImplStructStaticFunc1' matching static method 'staticFunc1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-5 {{could not find imported function 'CImplStructStaticFunc1' matching static method 'staticFunc1'; make sure you import the module or header that declares it}} } } diff --git a/test/decl/ext/objc_implementation_early_adopter.swift b/test/decl/ext/objc_implementation_early_adopter.swift index f8b2f5461c710..3170083a269c1 100644 --- a/test/decl/ext/objc_implementation_early_adopter.swift +++ b/test/decl/ext/objc_implementation_early_adopter.swift @@ -507,7 +507,7 @@ protocol EmptySwiftProto {} // expected-warning@-1 {{extension with Objective-C category name 'PresentAdditions' conflicts with previous extension with the same category name; this is an error in the Swift 6 language mode}} @_objcImplementation(MissingAdditions) extension ObjCClass {} -// expected-error@-1 {{could not find category 'MissingAdditions' on Objective-C class 'ObjCClass'; make sure your umbrella or bridging header imports the header that declares it}} +// expected-error@-1 {{could not find category 'MissingAdditions' on Objective-C class 'ObjCClass'; make sure you import the module or header that declares it}} // expected-note@-2 {{remove arguments to implement the main '@interface' for this class}} {{21-39=}} @_objcImplementation extension ObjCStruct {} @@ -549,7 +549,7 @@ func CImplFunc2(_: Int32) { @_objcImplementation @_cdecl("CImplFuncMissing") func CImplFuncMissing(_: Int32) { - // expected-error@-2 {{could not find imported function 'CImplFuncMissing' matching global function 'CImplFuncMissing'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'CImplFuncMissing' matching global function 'CImplFuncMissing'; make sure you import the module or header that declares it}} } @_objcImplementation @_cdecl("CImplFuncMismatch1") @@ -605,13 +605,13 @@ func CImplFuncMismatch6a(_: Int32) -> Any! { @_objcImplementation @_cdecl("CImplFuncNameMismatch1") func mismatchedName1(_: Int32) { - // expected-error@-2 {{could not find imported function 'CImplFuncNameMismatch1' matching global function 'mismatchedName1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'CImplFuncNameMismatch1' matching global function 'mismatchedName1'; make sure you import the module or header that declares it}} // FIXME: Improve diagnostic for a partial match. } @_objcImplementation @_cdecl("mismatchedName2") func CImplFuncNameMismatch2(_: Int32) { - // expected-error@-2 {{could not find imported function 'mismatchedName2' matching global function 'CImplFuncNameMismatch2'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-2 {{could not find imported function 'mismatchedName2' matching global function 'CImplFuncNameMismatch2'; make sure you import the module or header that declares it}} // FIXME: Improve diagnostic for a partial match. } @@ -622,14 +622,14 @@ var cImplComputedGlobal1: Int32 { @_objcImplementation @_cdecl("CImplGetComputedGlobal1") get { // FIXME: Lookup for vars isn't working yet - // expected-error@-3 {{could not find imported function 'CImplGetComputedGlobal1' matching getter for var 'cImplComputedGlobal1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-3 {{could not find imported function 'CImplGetComputedGlobal1' matching getter for var 'cImplComputedGlobal1'; make sure you import the module or header that declares it}} return 0 } @_objcImplementation @_cdecl("CImplSetComputedGlobal1") set { // FIXME: Lookup for vars isn't working yet - // expected-error@-3 {{could not find imported function 'CImplSetComputedGlobal1' matching setter for var 'cImplComputedGlobal1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-3 {{could not find imported function 'CImplSetComputedGlobal1' matching setter for var 'cImplComputedGlobal1'; make sure you import the module or header that declares it}} print(newValue) } } @@ -643,7 +643,7 @@ extension CImplStruct { // FIXME: Add underlying support for this // expected-error@-3 {{@_cdecl can only be applied to global functions}} // FIXME: Lookup in an enclosing type is not working yet - // expected-error@-5 {{could not find imported function 'CImplStructStaticFunc1' matching static method 'staticFunc1'; make sure your umbrella or bridging header imports the header that declares it}} + // expected-error@-5 {{could not find imported function 'CImplStructStaticFunc1' matching static method 'staticFunc1'; make sure you import the module or header that declares it}} } } From cc519a09d06e9bfb2d342e5f5f273d083707acf3 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 3 Oct 2025 15:25:53 -0700 Subject: [PATCH 2/2] [Embedded] Identify more places to emit symbols even with deferred code generation Deferred code generation only produces symbols when they are needed. Expand this out to cover more of the cases where we need them: * @c/@_cdecl with and without @implementation * @_expose(Cxx) and @_expose(Wasm) * @_section and @_used * (already present) the main entry point Part of the Embedded Swift linkage model. Also fixes #74328 / rdar://147207945 along the way. --- include/swift/SIL/SILDeclRef.h | 4 + lib/SIL/IR/SILDeclRef.cpp | 45 +++++++++++ lib/SIL/IR/SILFunction.cpp | 12 +++ lib/SIL/IR/SILGlobalVariable.cpp | 3 + .../embedded/linkage/Inputs/MyModuleExports.h | 4 + test/embedded/linkage/Inputs/module.modulemap | 4 + test/embedded/linkage/c.swift | 81 +++++++++++++++++++ test/embedded/linkage/cxx.swift | 16 ++++ 8 files changed, 169 insertions(+) create mode 100644 test/embedded/linkage/Inputs/MyModuleExports.h create mode 100644 test/embedded/linkage/c.swift create mode 100644 test/embedded/linkage/cxx.swift diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index 3966fb5302168..6841a7161fd63 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -415,6 +415,10 @@ struct SILDeclRef { /// embedded linkage model. bool hasNonUniqueDefinition() const; + /// True if the declaration is explicitly marked as being exposed to a + /// foreign language or environment, + static bool declExposedToForeignLanguage(const ValueDecl *decl); + /// True if the declaration should have a non-unique definition based on the /// embedded linkage model. static bool declHasNonUniqueDefinition(const ValueDecl *decl); diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index b615b98c9e51a..592f05e988b25 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -1153,6 +1153,29 @@ bool SILDeclRef::hasNonUniqueDefinition() const { return false; } +bool SILDeclRef::declExposedToForeignLanguage(const ValueDecl *decl) { + // @c / @_cdecl / @objc. + if (decl->getAttrs().hasAttribute() || + (decl->getAttrs().hasAttribute() && + decl->getDeclContext()->isModuleScopeContext())) { + return true; + } + + // @_expose that isn't negated. + for (auto *expose : decl->getAttrs().getAttributes()) { + switch (expose->getExposureKind()) { + case ExposureKind::Cxx: + case ExposureKind::Wasm: + return true; + + case ExposureKind::NotCxx: + continue; + } + } + + return false; +} + bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) { // This function only forces the issue in embedded. if (!decl->getASTContext().LangOpts.hasFeature(Feature::Embedded)) @@ -1167,6 +1190,28 @@ bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) { if (decl->getAttrs().hasAttribute()) return true; + // If the declaration is marked in a manner that indicates that other + // systems will expect it to have a symbol, then it has a unique definition. + // There are a few cases here. + + // - @implementation explicitly says that we are implementing something to + // be called from another language, so call it non-unique. + if (decl->isObjCImplementation()) + return false; + + // - @c / @_cdecl / @objc / @_expose expect to be called from another + // language if the symbol itself would be visible. + if (declExposedToForeignLanguage(decl) && + decl->getFormalAccess() >= AccessLevel::Internal) { + return false; + } + + // - @_section and @_used imply that external tools will look for this symbol. + if (decl->getAttrs().hasAttribute() || + decl->getAttrs().hasAttribute()) { + return false; + } + auto module = decl->getModuleContext(); auto &ctx = module->getASTContext(); diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index 7713ae57f345b..69e1d4793c999 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -1069,6 +1069,18 @@ SILFunction::isPossiblyUsedExternally() const { if (markedAsUsed()) return true; + // If this function is exposed to a foreign language, it can be used + // externally (by that language). + if (auto decl = getDeclRef().getDecl()) { + if (SILDeclRef::declExposedToForeignLanguage(decl)) + return true; + } + + // If this function was explicitly placed in a section or given a WebAssembly + // export, it can be used externally. + if (!Section.empty() || !WasmExportName.empty()) + return true; + if (shouldBePreservedForDebugger()) return true; diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index c32ccfbb9ded2..241a39eb4126e 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -91,6 +91,9 @@ bool SILGlobalVariable::isPossiblyUsedExternally() const { if (markedAsUsed()) return true; + if (getSectionAttr()) + return true; + SILLinkage linkage = getLinkage(); return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule()); } diff --git a/test/embedded/linkage/Inputs/MyModuleExports.h b/test/embedded/linkage/Inputs/MyModuleExports.h new file mode 100644 index 0000000000000..ab74ed6f4f450 --- /dev/null +++ b/test/embedded/linkage/Inputs/MyModuleExports.h @@ -0,0 +1,4 @@ +double clib_func1(void); +double clib_func2(void); +double clib_func3(void); +double clib_func4(void); diff --git a/test/embedded/linkage/Inputs/module.modulemap b/test/embedded/linkage/Inputs/module.modulemap index 5445080fa9516..a1f15125ed19d 100644 --- a/test/embedded/linkage/Inputs/module.modulemap +++ b/test/embedded/linkage/Inputs/module.modulemap @@ -1,3 +1,7 @@ module CDependency { header "CHeader.h" } + +module MyModuleExports { + header "MyModuleExports.h" +} diff --git a/test/embedded/linkage/c.swift b/test/embedded/linkage/c.swift new file mode 100644 index 0000000000000..2edc76eac5618 --- /dev/null +++ b/test/embedded/linkage/c.swift @@ -0,0 +1,81 @@ +// Check that C functions are exported as needed. + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: swift_feature_Embedded +// REQUIRES: swift_feature_DeferredCodeGen +// REQUIRES: swift_feature_CDecl +// REQUIRES: swift_feature_CImplementation +// REQUIRES: swift_feature_SymbolLinkageMarkers + +// RUN: %target-swift-frontend -emit-ir -o - %s -I %S/Inputs -package-name MyPackage -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -enable-experimental-feature CDecl -enable-experimental-feature CImplementation -enable-experimental-feature SymbolLinkageMarkers -parse-as-library | %FileCheck %s + +import MyModuleExports + +// --------------------------------------------------------------------------- +// @c / @_cdecl on > internal declarations cause symbol emission +// --------------------------------------------------------------------------- + +// CHECK: define {{(protected |dllexport )?}}void @lib_publicCDeclFunc() +@_cdecl("lib_publicCDeclFunc") +public func f1() { } + +// CHECK: define {{(protected |dllexport )?}}void @lib_publicCFunc() +@c(lib_publicCFunc) +package func f2() { } + +// CHECK: define hidden void @lib_publicCDeclFunc3 +@_cdecl("lib_publicCDeclFunc3") +internal func f3() { } + +// CHECK: define hidden void @lib_publicCDeclFunc4 +@c("lib_publicCDeclFunc4") +internal func f4() { } + +// CHECK-NOT: lib_publicCDeclFunc5 +@_cdecl("lib_publicCDeclFunc5") +private func f5() { } + +// CHECK-NOT: lib_publicCDeclFunc6 +@c("lib_publicCDeclFunc6") +private func f6() { } + +// --------------------------------------------------------------------------- +// @implementation @c / @_cdecl cause symbol emission +// --------------------------------------------------------------------------- + +// CHECK: define {{(protected |dllexport )?}}double @clib_func1 +@_cdecl("clib_func1") @implementation +public func clib_func1() -> Double { 0 } + +// CHECK: define {{(protected |dllexport )?}}double @clib_func2 +@c @implementation +package func clib_func2() -> Double { 0 } + +// CHECK: define hidden double @clib_func3 +@_cdecl("clib_func3") @implementation +internal func clib_func3() -> Double { 0 } + +// CHECK: define hidden double @clib_func4 +@c @implementation +internal func clib_func4() -> Double { 0 } + +// --------------------------------------------------------------------------- +// @_section causes symbol emission +// --------------------------------------------------------------------------- + +// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$e1c15symbolInSectionyyF" +@_section("__TEXT,__mysection") +public func symbolInSection() { } + +// CHECK: define hidden swiftcc void @"$e1c23internalSymbolInSectionyyF" +@_section("__TEXT,__mysection") +func internalSymbolInSection() { } + +// --------------------------------------------------------------------------- +// @_used causes symbol emission +// --------------------------------------------------------------------------- + +// CHECK: define hidden swiftcc void @"$e1c10usedSymbolyyF" +@_used +func usedSymbol() { } diff --git a/test/embedded/linkage/cxx.swift b/test/embedded/linkage/cxx.swift new file mode 100644 index 0000000000000..7390e8d123de4 --- /dev/null +++ b/test/embedded/linkage/cxx.swift @@ -0,0 +1,16 @@ +// Check that C++ functions are exported as needed. + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: swift_feature_Embedded +// REQUIRES: swift_feature_DeferredCodeGen + +// RUN: %target-swift-frontend -emit-ir -o - %s -I %S/Inputs -package-name MyPackage -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library -cxx-interoperability-mode=default | %FileCheck %s + +// CHECK: define hidden swiftcc void @"$e3cxx2f1yyF"() +@_expose(Cxx) +func f1() { } + +// CHECK-NOT: 2f2 +@_expose(!Cxx) +public func f2() { }