Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init Accessors not found by linker when used in another file #71578

Open
RemiBardon opened this issue Feb 13, 2024 · 11 comments · May be fixed by #72857
Open

Init Accessors not found by linker when used in another file #71578

RemiBardon opened this issue Feb 13, 2024 · 11 comments · May be fixed by #72857
Assignees
Labels
accepts invalid Bug: Accepts invalid accessors Feature → declarations: Variable (property) accessors bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself init accessors Feature: Initialization property accessors linker error multiple files Flag: An issue whose reproduction requires multiple files swift 5.9 type checker Area → compiler: Semantic analysis

Comments

@RemiBardon
Copy link

RemiBardon commented Feb 13, 2024

Description

When I try to use an Init Accessor in a file different from where they have been defined, my Swift Package stops compiling:

ld: Undefined symbols:
  SwiftBugReport.Angle.radians.init : Swift.Double, referenced from:
      SwiftBugReport.Angle.init(radians: Swift.Double) -> SwiftBugReport.Angle in SwiftBugReport.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Reproduction

Taking example from https://github.com/apple/swift-evolution/blob/main/proposals/0400-init-accessors.md#proposed-solution:

//  File1.swift
import Foundation

public struct Angle {
  public var degrees: Double
  public var radians: Double {
    @storageRestrictions(initializes: degrees)
    init(initialValue)  {
      degrees = initialValue * 180 / .pi
    }

    get { degrees * .pi / 180 }
    set { degrees = newValue * 180 / .pi }
  }

  public init(degrees: Double) {
    self.degrees = degrees
  }
}

If we just put init(radians:) in another file, ld doesn't find Angle.radians.init : Swift.Double anymore and the build crashes.

//  File2.swift
import Foundation

extension Angle {
  public init(radians: Double) {
    self.radians = radians
  }
}

Stack dump

Showing All Messages

Prepare build
note: Removed stale file '/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReport.build/Objects-normal/arm64/SwiftBugReport.o'

note: Removed stale file '/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReport.build/Objects-normal/arm64/SwiftBugReport.swiftconstvalues'



Removed stale file '/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReport.build/Objects-normal/arm64/SwiftBugReport.o'


Removed stale file '/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReport.build/Objects-normal/arm64/SwiftBugReport.swiftconstvalues'


ComputeTargetDependencyGraph

note: Building targets in dependency order
note: Target dependency graph (3 targets)
    Target 'SwiftBugReportTests' in project 'SwiftBugReport'
        ➜ Explicit dependency on target 'SwiftBugReport' in project 'SwiftBugReport'
    Target 'SwiftBugReport' in project 'SwiftBugReport'
        ➜ Explicit dependency on target 'SwiftBugReport' in project 'SwiftBugReport'
    Target 'SwiftBugReport' in project 'SwiftBugReport' (no dependencies)

Building targets in dependency order

Target dependency graph (3 targets)

GatherProvisioningInputs

CreateBuildDescription

Build description signature: a61ce25f1e515067416dde88ad559544
Build description path: /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/XCBuildData/a61ce25f1e515067416dde88ad559544.xcbuilddata

[...]

SwiftDriverJobDiscovery normal arm64 Compiling SwiftBugReportTests.swift (in target 'SwiftBugReportTests' from project 'SwiftBugReport')

SwiftDriver\ Compilation SwiftBugReportTests normal arm64 com.apple.xcode.tools.swift.compiler (in target 'SwiftBugReportTests' from project 'SwiftBugReport')
    cd /Users/xxxx/SwiftBugReport
    builtin-Swift-Compilation -- /Applications/Xcode-15.2.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -module-name SwiftBugReportTests -Onone -enforce-exclusivity\=checked @/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests.SwiftFileList -DSWIFT_PACKAGE -DDEBUG -DXcode -sdk /Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.2.sdk -target arm64-apple-ios12.0 -g -module-cache-path /Users/xxxx/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -Xfrontend -serialize-debugging-options -profile-coverage-mapping -profile-generate -enable-testing -index-store-path /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Index.noindex/DataStore -swift-version 5 -I /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos -I /Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib -F /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos/PackageFrameworks -F /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos -F /Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks -F /Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.2.sdk/Developer/Library/Frameworks -parse-as-library -c -j12 -enable-batch-mode -incremental -Xcc -ivfsstatcache -Xcc /Users/xxxx/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphoneos17.2-21C52-d4853233c81beb1da90379997a312ef0.sdkstatcache -output-file-map /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests-OutputFileMap.json -use-frontend-parseable-output -save-temps -no-color-diagnostics -serialize-diagnostics -emit-dependencies -emit-module -emit-module-path /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests.swiftmodule -validate-clang-modules-once -clang-build-session-file /Users/xxxx/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -Xfrontend -package-name -Xfrontend swiftbugreport -emit-const-values -Xfrontend -const-gather-protocols-file -Xfrontend /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests_const_extract_protocols.json -Xcc -I/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos/include -Xcc -I/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/DerivedSources-normal/arm64 -Xcc -I/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/DerivedSources/arm64 -Xcc -I/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/DerivedSources -Xcc -DSWIFT_PACKAGE -Xcc -DDEBUG\=1 -working-directory /Users/xxxx/SwiftBugReport -experimental-emit-module-separately -disable-cmo

WriteAuxiliaryFile /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests.LinkFileList (in target 'SwiftBugReportTests' from project 'SwiftBugReport')
    cd /Users/xxxx/SwiftBugReport
    write-file /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests.LinkFileList

Ld /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos/SwiftBugReportTests.xctest/SwiftBugReportTests normal (in target 'SwiftBugReportTests' from project 'SwiftBugReport')
    cd /Users/xxxx/SwiftBugReport
    /Applications/Xcode-15.2.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -Xlinker -reproducible -target arm64-apple-ios12.0 -bundle -isysroot /Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.2.sdk -O0 -L/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/EagerLinkingTBDs/Debug-iphoneos -L/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos -L/Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib -F/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/EagerLinkingTBDs/Debug-iphoneos -F/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos/PackageFrameworks -F/Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos -F/Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks -iframework /Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks -iframework /Applications/Xcode-15.2.0.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.2.sdk/Developer/Library/Frameworks -filelist /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests.LinkFileList -Xlinker -rpath -Xlinker /usr/lib/swift -Xlinker -rpath -Xlinker /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos/PackageFrameworks -Xlinker -rpath -Xlinker @loader_path/Frameworks -Xlinker -rpath -Xlinker @loader_path/../Frameworks -dead_strip -Xlinker -object_path_lto -Xlinker /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests_lto.o -Xlinker -export_dynamic -Xlinker -no_deduplicate -Xlinker -debug_variant -fobjc-link-runtime -fprofile-instr-generate -L/Applications/Xcode-15.2.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos -L/usr/lib/swift -Xlinker -add_ast_path -Xlinker /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests.swiftmodule -Wl,-no_warn_duplicate_libraries -framework XCTest -Xlinker -dependency_info -Xlinker /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReportTests.build/Objects-normal/arm64/SwiftBugReportTests_dependency_info.dat -o /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Products/Debug-iphoneos/SwiftBugReportTests.xctest/SwiftBugReportTests -Xlinker -add_ast_path -Xlinker /Users/xxxx/Library/Developer/Xcode/DerivedData/SwiftBugReport-euwmnzzwnujrvucebxjwtxhzfmjr/Build/Intermediates.noindex/SwiftBugReport.build/Debug-iphoneos/SwiftBugReport.build/Objects-normal/arm64/SwiftBugReport.swiftmodule

ld: Undefined symbols:
  SwiftBugReport.Angle.radians.init : Swift.Double, referenced from:
      SwiftBugReport.Angle.init(radians: Swift.Double) -> SwiftBugReport.Angle in SwiftBugReport.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Undefined symbols:

Linker command failed with exit code 1 (use -v to see invocation)



Build failed    13/02/2024, 11:35    0.7 seconds

Expected behavior

I would expect either to be able to use an Init Accessor in a separate file or receive a comprehensive compiler error message saying along the lines of "This is not possible, Init Accessors can only be used in the file where they have been declared" (if it's a known limitation).

Environment

swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: x86_64-apple-macosx14.0

Additional information

  • I used a Swift Package, I don't know if it changes anything
  • A simple workaround exists: moving the extension back in the same file (which means this crash is non-blocking)
@RemiBardon RemiBardon added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Feb 13, 2024
@AnthonyLatsis AnthonyLatsis added linker error unexpected error Bug: Unexpected error compiler The Swift compiler in itself SILGen Area → compiler: The SIL generation stage init accessors Feature: Initialization property accessors accessors Feature → declarations: Variable (property) accessors swift 5.9 multiple files Flag: An issue whose reproduction requires multiple files and removed crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Feb 13, 2024
@li3zhen1
Copy link
Contributor

li3zhen1 commented Apr 2, 2024

It looks like the access level of init accessors are always set to private before lowering to SIL:

case AccessorKind::Init:
// These are only called from designated initializers.
return AccessLevel::Private;

The original proposal here implies the maximal access level could only be private or internal:

ABI compatibility

init accessors are only called from within a module, so they are not part of the module's ABI. In cases where a type's initializer is @inlinable, the body of an init accessor must also be inlinable.


IIUC init() extensions must call the original initializers outside the module, so I guess the way to fix this is either

  • keep it to private.
  • or make it internal when the decl has a higher access level than private if this does not break ABI.

(And also teach type checker to respect these access levels so it emits some diagnostics when accessed incorrectly)

@AnthonyLatsis Could you please give a hint on which way to take and assign this to me? Thank you!

@AnthonyLatsis
Copy link
Collaborator

Apparently, this is a problem with the SIL linkage these init accessors are getting, likely due to AccessLevel::Private. You can try aligning the access level with the property’s and see if that makes a difference. I am not sure what the proposal authors had in mind about initializing such properties outside the declaring module though.

cc @hborla.

@xedin
Copy link
Member

xedin commented Apr 3, 2024

This case should be diagnosed during Sema, init accessors are not ABI and could only be used inside of the defining module.

@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Apr 3, 2024

But they should work across files, right? (The report says they don’t either.)

@xedin
Copy link
Member

xedin commented Apr 3, 2024

I was just replying to your comment. Regarding same module but different files - I think the discussion settled on allowing use of init accessors in extensions but in the same file, similar to property wrappers (if I remember correctly). Use cross files should be diagnosed just like cross module use. I think it might be worth it to look at the pitch/discussion thread on forums too.

@AnthonyLatsis AnthonyLatsis added accepts invalid Bug: Accepts invalid type checker Area → compiler: Semantic analysis and removed unexpected error Bug: Unexpected error SILGen Area → compiler: The SIL generation stage labels Apr 3, 2024
@AnthonyLatsis
Copy link
Collaborator

Sorry, I took your comment for a general one on the issue. This is the closest I got to finding anything related, but the post is about declaring, not using, init accessors in extensions or across files.

@li3zhen1 While we’re waiting for clarification, let’s assume init accessors cannot be used outside the enclosing lexical type context.

@AnthonyLatsis
Copy link
Collaborator

@li3zhen1
Copy link
Contributor

li3zhen1 commented Apr 4, 2024

Seems like bool checkAccess(const DeclContext *useDC, const ValueDecl *VD, ...) always check the access level of the outer var radians { ... } and thus failed to catch the inner private init.

Should I add some additional check

  • in checkAccess,
  • or in genAssignDestType() like assignment_lhs_is_immutable_property (feel like it's to early)
  • or perhaps in SIL passes like immutable_property_already_initialized?

@xedin
Copy link
Member

xedin commented Apr 4, 2024

I finally had a chance to take a look at what is going on with property wrappers and assign_by_wrapper is emitted only when access happens to be in an initializer that is enclosed in a lexical type context.

I think we wanted to make this a little bit broader for init accessors though and allow extensions in the same file where init accessor property is declared. Let's add a check to canRewriteSetAsInitAccessor in SILGenLValue.cpp to return true only if access happens in the same source file where the property is declared and all other uses would be diagnosed by DI because they produce getter/setter access pattern.

@AnthonyLatsis
Copy link
Collaborator

I think we also need semantic analysis to ignore the init accessor in assignments to get-only properties.

@li3zhen1 li3zhen1 linked a pull request Apr 4, 2024 that will close this issue
@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Apr 22, 2024

Holly says init accessors are supposed to be (at most) internal, not private, but can only be declared in the primary declaration of the file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepts invalid Bug: Accepts invalid accessors Feature → declarations: Variable (property) accessors bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself init accessors Feature: Initialization property accessors linker error multiple files Flag: An issue whose reproduction requires multiple files swift 5.9 type checker Area → compiler: Semantic analysis
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants