Skip to content

[cxx-interop] Allow using std::map subscript #61385

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

Merged
merged 1 commit into from
Oct 3, 2022

Conversation

egorzhdan
Copy link
Contributor

This fixes an error that occurred when trying to use the subscript on an instance std::map:

error: cannot assign through subscript: 'map' is immutable

This was happening even with a mutable std::map instance.

std::map::operator[] has two overloads:

  • T& operator[]( const Key& key )
  • T& operator[]( Key&& key )

The second one is imported with an inout parameter, and we picked it as an implementation of the subscript getter because it was the last of the two overloads to get imported.

Swift does not allow subscripts with inout parameters. This is checked at the AST level, and those checks do not run for synthesized Swift code. This caused Swift to produce a surprising error which actually indicated that the argument of the subscript, not the instance itself, must be mutable.

rdar://100529571

@egorzhdan egorzhdan added the c++ interop Feature: Interoperability with C++ label Sep 30, 2022
@egorzhdan egorzhdan force-pushed the egorzhdan/cxx-inout-subscript branch from 7c6b552 to 9faa409 Compare September 30, 2022 16:33
@egorzhdan
Copy link
Contributor Author

@swift-ci please smoke test

Copy link
Contributor

@hyp hyp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

if (!typeDecl || !parameterType)
return nullptr;
if (parameter->isInOut())
// Subscripts with inout parameters are not allowed in Swift.
return nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should transform this to a non-inout parameter.

If you're not going to fix this in the next week or two please add a diagnostic here as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I missed what this is actually doing, this makes the other overload becomes usable. This is lower priority, then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's quite challenging to add a useful diagnostic here, since this method only gets invoked from generated Swift code. I think it's not worth the trouble, but let's discuss if you disagree 😉

@egorzhdan egorzhdan force-pushed the egorzhdan/cxx-inout-subscript branch from 9faa409 to eaee8b5 Compare September 30, 2022 18:30
@egorzhdan
Copy link
Contributor Author

@swift-ci please smoke test

@zoecarver
Copy link
Contributor

@swift-ci please smoke test

Copy link
Contributor

@ktoso ktoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, lgtm :-)

This fixes an error that occurred when trying to use the subscript on an instance `std::map`:
```
error: cannot assign through subscript: 'map' is immutable
```
This was happening even with a mutable `std::map` instance.

`std::map::operator[]` has two overloads:
* `T& operator[]( const Key& key )`
* `T& operator[]( Key&& key )`

The second one is imported with an `inout` parameter, and we picked it as an implementation of the subscript getter because it was the last of the two overloads to get imported.

Swift does not allow subscripts with `inout` parameters. This is checked at the AST level, and those checks do not run for synthesized Swift code. This caused Swift to produce a surprising error which actually indicated that the argument of the subscript, not the instance itself, must be mutable.

rdar://100529571
@egorzhdan egorzhdan force-pushed the egorzhdan/cxx-inout-subscript branch from eaee8b5 to e28605c Compare October 3, 2022 10:19
@egorzhdan
Copy link
Contributor Author

******************** TEST 'Swift(linux-x86_64) :: Interop/Cxx/stdlib/use-std-map.swift' FAILED ********************
Script:
--
: 'RUN: at line 1';   rm -rf "/home/build-user/build/buildbot_linux/swift-linux-x86_64/test-linux-x86_64/Interop/Cxx/stdlib/Output/use-std-map.swift.tmp" && mkdir -p "/home/build-user/build/buildbot_linux/swift-linux-x86_64/test-linux-x86_64/Interop/Cxx/stdlib/Output/use-std-map.swift.tmp" && /home/build-user/build/buildbot_linux/swift-linux-x86_64/bin/swiftc -target x86_64-unknown-linux-gnu -toolchain-stdlib-rpath  -module-cache-path /home/build-user/build/buildbot_linux/swift-linux-x86_64/swift-test-results/x86_64-unknown-linux-gnu/clang-module-cache -swift-version 4  -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 9999:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.0:macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.2' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.1:macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.2:macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.3:macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.4:macOS 11.3, iOS 14.5, watchOS 7.4, tvOS 14.5' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.5:macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.6:macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.7:macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0' -Xfrontend -define-availability -Xfrontend 'SwiftStdlib 5.8:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999'  -module-cache-path /home/build-user/build/buildbot_linux/swift-linux-x86_64/swift-test-results/x86_64-unknown-linux-gnu/clang-module-cache /home/build-user/swift/test/Interop/Cxx/stdlib/use-std-map.swift -I /home/build-user/swift/test/Interop/Cxx/stdlib/Inputs -Xfrontend -enable-experimental-cxx-interop -o /home/build-user/build/buildbot_linux/swift-linux-x86_64/test-linux-x86_64/Interop/Cxx/stdlib/Output/use-std-map.swift.tmp/a.out -module-name main  && echo /home/build-user/build/buildbot_linux/swift-linux-x86_64/test-linux-x86_64/Interop/Cxx/stdlib/Output/use-std-map.swift.tmp/a.out && /usr/bin/env LD_LIBRARY_PATH='/home/build-user/build/buildbot_linux/swift-linux-x86_64/lib/swift/linux'  /home/build-user/build/buildbot_linux/swift-linux-x86_64/test-linux-x86_64/Interop/Cxx/stdlib/Output/use-std-map.swift.tmp/a.out
--
Exit Code: 1

Command Output (stderr):
--
/tmp/lit-tmp-3vjnhydr/use-std-map-2481b4.o:use-std-map-2481b4.o:function $s4mainyycfU_: error: undefined reference to 'std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::map()'
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)

The test failure on Linux is quite unfortunate but it is a different issue, I'll address it separately (#61412).

@egorzhdan
Copy link
Contributor Author

@swift-ci please smoke test

@egorzhdan egorzhdan merged commit 351930e into main Oct 3, 2022
@egorzhdan egorzhdan deleted the egorzhdan/cxx-inout-subscript branch October 3, 2022 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants