Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions proposals/p6331.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Add `import Cpp;` for C++ built-in entities

<!--
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
Exceptions. See /LICENSE for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->

[Pull request](https://github.com/carbon-language/carbon-lang/pull/6331)

<!-- toc -->

## Table of contents

- [Abstract](#abstract)
- [Problem](#problem)
- [Background](#background)
- [Proposal](#proposal)
- [Details](#details)
- [Activated Entities](#activated-entities)
- [Interaction with Other Imports](#interaction-with-other-imports)
- [Rationale](#rationale)
- [Alternatives Considered](#alternatives-considered)

<!-- tocstop -->

## Abstract

This proposal introduces an `import Cpp;` directive. This directive makes C++
built-in types, such as `long`, available in Carbon through a clear and explicit
mechanism.

## Problem

Carbon's C++ interoperability requires seamless, bidirectional access. The
primary mechanism for this is `import Cpp library "header.h";`, which parses a
C++ header file and maps its AST into Carbon's `Cpp` namespace.

However, this mechanism falls short when a developer only needs C++ built-in
types (for example, `long`, `long long`, `unsigned long`), as these are not
defined in any header file.

Furthermore, some C++ types are **nominally distinct**. For example, on many
64-bit systems, `long` and `long long` share the same 64-bit representation, but
C++ treats them as distinct types - a critical feature for function overloading.
If Carbon were to map both types to its canonical `i64`, this semantic
distinction would be lost, breaking interoperability.

To address this, Carbon must provide its own distinct mirror types, such as
`Cpp.long` and `Cpp.long_long`. The language currently lacks a clear and direct
way to "activate" or import only these compiler-provided, built-in C++ entities.
While `import Cpp inline "";` can achieve this, it is an unintuitive and
indirect solution.

## Background

Currently, C++ built-in types can be brought into the `Cpp` namespace using
`import Cpp inline "";`. This works because the `inline` import implicitly makes
the built-in types available. However, this is a side effect of the `inline`
import's behavior, not an obvious or intentional feature.

## Proposal

We propose a new import directive:

```carbon
import Cpp;
```

This file-level statement instructs the Carbon compiler to populate the `Cpp`
namespace with all C++ built-in entities required for interoperability. This
acts as a compiler-level activation and does not involve reading any files.

## Details

### Activated Entities

The set of entities activated by `import Cpp;` is determined by the compiler's
interoperability model. This will include C++ primitive types, including those
necessary to preserve nominal distinction (for example, `Cpp.long`,
`Cpp.unsigned_long`, `Cpp.long_long`).

### Interaction with Other Imports

The `import Cpp;` directive is **not** mutually exclusive with
`import Cpp library "..."` or `import Cpp inline "..."`.

Both `import Cpp library "..."` and `import Cpp inline "..."` will implicitly
trigger the effects of `import Cpp;`. Since any C++ code is likely to use
built-in types, making them available by default enhances the user experience.

## Rationale

**Explicitness over Magic:** This directive provides a clear, non-magical
opt-in. It prevents the `Cpp` namespace from being automatically available to
users who have not explicitly declared their intent to use C++ interoperability,
aligning with Carbon's design principles.

## Alternatives Considered

1. **Use `import Cpp inline "";`:** Rejected. This approach is not obvious and
relies on a side effect of the `inline` import implementation, rather than
being a clear, intentional feature.
2. **Implicit Activation:** Rejected. Automatically making `Cpp.long` available
in all files would be unexpected and would violate Carbon's design
principles.
Copy link
Contributor

Choose a reason for hiding this comment

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

Better to be explicit about which design principles are relevant here. For example, it could be about adding overhead to compiles that don't need it which falls under "Fast and scalable development".

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 think the overhead depends on the implementation and we could avoid any significant impact.
I was actually thinking about "principle of least surprise". Clarified.

Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if there has been much discussion about this option?

These seem awfully like what we would want in a "prelude" like construct for C++. We already have a prelude that brings in names in Core, and the Cpp package name is going to be similarly special (or more special) to Core due to it enabling the C++ importing. For example, it isn't reasonable to define a Carbon file with the package name Cpp.

So maybe that argues that this should be part of Carbon's prelude, and that prelude should introduce names both in Core and Cpp?

(If this is controversial or we want a longer discussion, maybe this should be factored into a leads issue.)

Copy link
Contributor

@zygoloid zygoloid Nov 7, 2025

Choose a reason for hiding this comment

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

I think I'd be happy with this if we make Cpp a keyword (see https://docs.carbon-lang.dev/docs/project/principles/namespace_cleanliness.html#exceptions). Though in another leads issue we did just suggest adding names Core.Cpp.Long32 etc, which would presumably add another special case if Cpp is a keyword.

Notably we made Cpp a keyword in the toolchain already because it simplifies the implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

FTR, the suggestion to add Core.Cpp.Long32 is here.

I think Cpp is currently only special when used as a top namespace, and it can be used by users elsewhere.
I guess if it's an official keyword, we should not allow using it elsewhere.

I think introducing Cpp as part of Carbon language by default means we don't just support great interop with C++, we incorporate C++ names as part of Carbon.
Future users of pure Carbon might find having Cpp.long in pure Carbon a bit surprising and legacy of C++.

I agree Core is somewhat similar, but Core is probably necessary for almost any Carbon based project, and Cpp is not necessary for future pure Carbon projects.

I think we could make a decision between the proposed solution here and alternative 2. If we decided on alternative 2, I'll be happy to create a new proposal for that and close this one. I can also create a leads question, but I feel like this would just split the discussion unnecessarily.

Copy link
Contributor

Choose a reason for hiding this comment

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

Chatted a bit with @zygoloid and I think we're both increasingly comfortable with this alternative, and making Cpp a keyword and refer to the special Cpp package.

That will force us to use a different namespace inside of Core for types like Long32, but that's probably good -- these aren't ways of naming the C++ name, but the Carbon type that is used for compatibility with a specific C++ name. Basic suggestion for #6275 names is Core.CppCompat.*.

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!
To clarify, we want to not support import Cpp; and instead, when there's no import Cpp ... (library or inline), and the Cpp keyword is used (e.g. Cpp.long or even Cpp.MyType), we will trigger AST creation so we can query it.
In other words, Cpp and Cpp.<builtin_type> are always found, regardless of whether we explicitly imported Cpp.
Correct?

3. **Magic Header (`import Cpp library "<cpp_builtins>";`)**: Rejected. This is
a confusing anti-pattern. The `library` keyword implies that a file is being
parsed, which is not the case here, breaking the user's mental model.
Loading