Skip to content

Carbon/C++ Interop: Primitive Types proposal #5448

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 14 commits into
base: trunk
Choose a base branch
from

Conversation

ivanaivanovska
Copy link
Contributor

@ivanaivanovska ivanaivanovska commented May 8, 2025

A proposal for Primitive Types mapping between Carbon and C++.

Part of #5263

@github-actions github-actions bot added the proposal A proposal label May 8, 2025
@ivanaivanovska ivanaivanovska marked this pull request as ready for review May 23, 2025 09:43
@github-actions github-actions bot added the proposal rfc Proposal with request-for-comment sent out label May 23, 2025
@github-actions github-actions bot requested a review from KateGregory May 23, 2025 09:43
Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

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

Generally looks good to me, I think the conversions align. Looking through this did make me realize I'd missed the Core.Cpp naming -- sorry about that.

- Carbon `iN` types will map to C++ `intN_t` types (for example `i32` ->
`int32_t`).
- `long`, `long long` in C++ will map to new Carbon types (for example
`Core.Cpp.long/long_long`).
Copy link
Contributor

Choose a reason for hiding this comment

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

@zygoloid What was your intent for where long falls? I'd been assuming Cpp.long, and missed that the design was writing Core.Cpp.long until now. I think there are some behavioral trade-offs:

  1. If it's in a non-prelude Core library, it's presumably implicitly imported when import Cpp is written, but not added to name lookup. I think this would require some work on import boundaries.
  2. If it's in the prelude, then we're privileging a C++ type in a way that we might not want to echo for other programming languages (or even other C++ types).
  3. If it's in a Cpp-packaged library implemented in Carbon code, then we might need some special-casing to allow package Cpp, but it could behave similar to export import for a user.
  4. If it's treated similar to other C++ types, it could just be added every time import Cpp is processed. So it's still Cpp.long, and conversions to Carbon types work, but it's still a little special because that's not how most C++ types work.

Copy link
Contributor

Choose a reason for hiding this comment

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

Per discussion in the interop meeting and separate discussion with @chandlerc, I think our preference here is Cpp.long, Cpp.long_long, and so on. I don't think we've explicitly discussed keyword order, but I'm assuming it's:

Cpp.[unsigned_](long_long|long|int|short|double|float)

That is: signedness, then size keyword(s), then a type keyword only if there were no size keywords. (So unsigned_int not unsigned, long not long_int.)

Some mention of why we think it's OK to do this despite the risk of name collisions would be great to include in this proposal.

We should include in "Alternatives considered" at least three other options:

  • Allow all keyword permutations. Reason not to do this: it's unnecessary and complicated.
  • Only include the keywords, and provide some syntax for combining them (eg, Cpp.unsigned & Cpp.long or Cpp.unsigned(Cpp.long)). Reason to do this: avoids taking any identifiers from Cpp that are not C++ keywords. Reason not to do this: overly complicated.
  • Use Core.Cpp.blah instead of Cpp.blah. Reason to do this: avoid name collisions with C++ code. Reason not to do this: we don't think the name collisions are a problem in practice, and would prefer to keep C++-specific stuff in package Cpp.

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. Done.

- `f16`, `f32`, and `f64` - always available
- `f80`, `f128`, or `f256` may be available, depending on the platform

### C++ Fundamental Types
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps let's improve consistency on how we write platform specific notes.
I suggest:

<Platform>: definition
Other: definition

Also, I don't think we need to mention that LP32 is not Carbon supported several times, we can have it as a note at the beginning or at the end, and clarify that for now we're considering this platform as not supported.

If you say it in the beginning, you can also decide to just ignore it in the table, so it might be useful to have that information (perhaps you can move it to a different place).


**Standard floating-point types**

| Type | Format | Width in bits | Note |
Copy link
Contributor

Choose a reason for hiding this comment

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

Add links to the specific formats.

[LP64](/proposals/p5448.md#data-models)). Historic platforms like
[LP32](/proposals/p5448.md#data-models) won't be supported.

## Proposal
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we say explicitly that if C++ considered two types to be different types, Carbon would treat them as different types as well?
I see you write it below, but you can put it above instead to clarify this guides the mapping.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

| `Core.Cpp.unsigned_long` | `unsigned long`, [LP64](/proposals/p5448.md#data-models): `uint_fast64_t`, `uint_least64_t`, `uintmax_t`, `uintptr_t`, `size_t` |
| `Core.Cpp.unsigned_long_long` | `unsigned long long`, [LLP64](/proposals/p5448.md#data-models): `uint_fast64_t`, `uint_least64_t`, `uintmax_t` |
| `Core.Cpp.long_double` | `long double` |
| X (No mapping) | `float32_t`, `float64_t`, `bfloat16_t` |
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 probably map them eventually, why not TBD?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

- Carbon `iN` types will map to C++ `intN_t` types (for example `i32` ->
`int32_t`).
- `long`, `long long` in C++ will map to new Carbon types (for example
`Core.Cpp.long/long_long`).
Copy link
Contributor

Choose a reason for hiding this comment

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

Per discussion in the interop meeting and separate discussion with @chandlerc, I think our preference here is Cpp.long, Cpp.long_long, and so on. I don't think we've explicitly discussed keyword order, but I'm assuming it's:

Cpp.[unsigned_](long_long|long|int|short|double|float)

That is: signedness, then size keyword(s), then a type keyword only if there were no size keywords. (So unsigned_int not unsigned, long not long_int.)

Some mention of why we think it's OK to do this despite the risk of name collisions would be great to include in this proposal.

We should include in "Alternatives considered" at least three other options:

  • Allow all keyword permutations. Reason not to do this: it's unnecessary and complicated.
  • Only include the keywords, and provide some syntax for combining them (eg, Cpp.unsigned & Cpp.long or Cpp.unsigned(Cpp.long)). Reason to do this: avoids taking any identifiers from Cpp that are not C++ keywords. Reason not to do this: overly complicated.
  • Use Core.Cpp.blah instead of Cpp.blah. Reason to do this: avoid name collisions with C++ code. Reason not to do this: we don't think the name collisions are a problem in practice, and would prefer to keep C++-specific stuff in package Cpp.

Comment on lines 294 to 298
| `Core.Cpp.long` | `long`, [LP64](/proposals/p5448.md#data-models): `int_fast64_t`, `int_least64_t`, `intmax_t`, `intptr_t`, `ptrdiff_t` |
| `Core.Cpp.long_long` | `long long`, [LLP64](/proposals/p5448.md#data-models): `int_fast64_t`, `int_least64_t`, `intmax_t` |
| `Core.Cpp.unsigned_long` | `unsigned long`, [LP64](/proposals/p5448.md#data-models): `uint_fast64_t`, `uint_least64_t`, `uintmax_t`, `uintptr_t`, `size_t` |
| `Core.Cpp.unsigned_long_long` | `unsigned long long`, [LLP64](/proposals/p5448.md#data-models): `uint_fast64_t`, `uint_least64_t`, `uintmax_t` |
| `Core.Cpp.long_double` | `long double` |
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we add just these five [Core.]Cpp.something types, or all the C++ types, including the ones with an effectively fixed mapping? It'd be more consistent to add them all.

Copy link
Contributor Author

@ivanaivanovska ivanaivanovska Jun 18, 2025

Choose a reason for hiding this comment

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

Added them all, PTAL.

Comment on lines 316 to 318
- `Core.Cpp.long`: either 32-bit or 64-bit, and use an appropriate int
type that is compatible with (but different) from `i32`/`i64`.
- `Core.Cpp.long_long`: a platform dependent alias to `i64`.
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not completely clear to me what model is being proposed here. I think the main options are:

  1. Cpp.long and Cpp.long_long both map to Carbon types that are distinct from iN for any N, but are compatible with either i32 or i64 as appropriate.
  2. If int64_t is long then Cpp.long is i64 and if int64_t is long long then Cpp.long_long is i64. Whichever types don't map to iN are distinct Carbon types that are compatible with iN instead.
  3. int, long, and long long all map to one of i32 or i64. This means two different C++ types map to the same Carbon type.

Your alternatives considered says why we're not doing option 3. But I think we should also consider whether we want option 1 or option 2. I think the description in this proposal is saying we'd do option 1, but we'd at least previously been talking about doing option 2 instead. That seems to be a reasonable rule that can be described without explicitly treating long and long long as special cases:

  • intN_t in C++ is always the same type as iN in Carbon. And likewise for uintN_t / uN.
  • builtin type in C++ is always the same type as Cpp.builtin_type in Carbon for some specified set of builtin types.
  • As a consequence, builtin types in C++ that aren't the same as intN_t or uintN_t for any N end up being nameable in Carbon only as Cpp.builtin_type.

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. I updated the proposal to reflect on these comments, PTAL.

Comment on lines 329 to 331
Carbon won't have aliases or distinct types for `int_fastN_t`, `int_leastN_t`,
`intmax_t`, `intptr_t`, `ptrdiff_t`, `size_t`. This may be reconsidered in the
future if need arises.
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be worth pointing out that Cpp.size_t etc will exist if the C++ header declaring the typedef is imported, so we don't need any explicit support for these.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@ivanaivanovska ivanaivanovska requested a review from zygoloid June 18, 2025 09:57
@ivanaivanovska
Copy link
Contributor Author

I updated the Proposal, Details and Alternatives sections to reflect on the comments. Will go later through the comments on the Background section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal rfc Proposal with request-for-comment sent out proposal A proposal
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants