From 67c7fbc87bfd9d89aa34886ecf42feb6745192d6 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 3 Oct 2025 11:35:25 -0700 Subject: [PATCH] [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}} } }