Skip to content

[cxx-interop] Add CxxStack protocol for std::stack ergonomics. #81087

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

CrazyFanFan
Copy link
Contributor

This adds a protocol to the C++ standard library overlay that will improve the ergonomics of std::stack when used from Swift code.

As of now, CxxStack adds a top() -> Element function to C++ stacks.

@j-hui
Copy link
Contributor

j-hui commented Apr 25, 2025

@swift-ci please test

Copy link
Contributor

@j-hui j-hui left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution @CrazyFanFan ! I left some preliminary comments for now

@@ -865,6 +865,45 @@ void swift::conformToCxxSequenceIfNeeded(
}
}

void swift::conformToCxxStackIfNeeded(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be good with some negative test cases for inferring conformance, just to make sure it gets handled properly. In particular I'm interested in how element types that are ~Escapable and/or ~Copyable are handled. Do they get a diagnostic, or is the conformance just omitted? Also, can std::stack be declared for forward declared types in C++? If so, it'd be good to have a test case for that too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestions!
Could you provide an example to illustrate how to test types that are ~Escapable and/or ~Copyable, as well as forward declared types? This would help me better understand your requirements and write the relevant test cases.

Copy link
Contributor

Choose a reason for hiding this comment

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

Something like this:

struct SWIFT_NONESCAPABLE ne_t {
  int dummy;
};
void foo(std::stack<ne_t> s);

struct SWIFT_NONCOPYABLE nc_t {
  int dummy;
};
void bar(std::stack<nc_t> s);

struct fd_t;
void baz(std::stack<fd_t> s);

What kind of errors does importing a header like that, and trying to call those functions, result in?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it. Thank you for your suggestion.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think what would happen in those cases is that the public extension CxxStack { ... } would not work, because ~Copyable and ~Escapable constraints need to be explicitly opted out of (though I'm not familiar enough with that feature to say for sure yet). So the protocol conformance would either be unusable by the user (what I would expect to happen) or cause the compiler to crash/misbehave (what should not happen).

@CrazyFanFan what happens when you try to import those tests that @hnrklssn suggested?

@j-hui
Copy link
Contributor

j-hui commented May 2, 2025

@swift-ci please test

@CrazyFanFan
Copy link
Contributor Author

Hi @j-hui, I’ve marked the default pop as unsafe and implemented a safe version: mutating func pop() -> Element?.

For the negative test cases, I haven’t figured out the best approach yet—maybe we should handle them in a separate task? Also, sets and maps are not yet handled.

@hnrklssn, Is that okay with you?

Copy link
Contributor

@j-hui j-hui left a comment

Choose a reason for hiding this comment

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

This looks good to me, pending resolution of the discussion about ~Copyable and ~Escapable types.

@j-hui
Copy link
Contributor

j-hui commented May 15, 2025

@swift-ci please test

@CrazyFanFan
Copy link
Contributor Author

Hi @hnrklssn , any update on the PR review? Thanks!

@hnrklssn
Copy link
Contributor

Sorry, I forgot about this one! What was the issue WRT implementing the tests?

@CrazyFanFan
Copy link
Contributor Author

Hi @j-hui, I’ve marked the default pop as unsafe and implemented a safe version: mutating func pop() -> Element?.

For the negative test cases, I haven’t figured out the best approach yet—maybe we should handle them in a separate task? Also, sets and maps are not yet handled.

@hnrklssn, Is that okay with you?

@hnrklssn Here's the context. Regarding the negative test cases, I think we could make it an independent task. What do you think?

@hnrklssn
Copy link
Contributor

Hi @j-hui, I’ve marked the default pop as unsafe and implemented a safe version: mutating func pop() -> Element?.
For the negative test cases, I haven’t figured out the best approach yet—maybe we should handle them in a separate task? Also, sets and maps are not yet handled.
@hnrklssn, Is that okay with you?

@hnrklssn Here's the context. Regarding the negative test cases, I think we could make it an independent task. What do you think?

I think it'd be such a small task, that we may as well include it in this PR.

@CrazyFanFan
Copy link
Contributor Author

@hnrklssn Apologies for the delayed response—I've been swamped recently.
Testing shows:

  1. C++ types marked SWIFT_NONESCAPABLE cause a C++ compilation error for std::stack: "An initializer cannot return a ~Escapable result".
  2. SWIFT_NONCOPYABLE types compile without issues.
  3. Forward-declared types behave like SWIFT_NONESCAPABLE, triggering C++ compilation errors.

I'm challenged to add negative test cases for these scenarios. Since errors occur during C++ compilation (before Swift inference), capturing them in Swift-level tests is difficult.

std::stack conformance inference runs only after successful C++ compilation. For cases like SWIFT_NONESCAPABLE or forward-declared types where C++ compilation fails, inference never starts.

Do you have suggestions for testing these C++-stage error scenarios?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants