From aa33a1e9e21834a669c3e4594423a835ed175435 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Wed, 12 Nov 2025 15:45:10 +0100 Subject: [PATCH 01/10] C++ Interop design details - the basics This includes high level design ideas and the basics of importing C++ APIs and function calling. Leaving plenty of TODOs to make it easier to fill in more details in followups. --- docs/design/interoperability/README.md | 228 ++++++++++++++++++++++++- 1 file changed, 227 insertions(+), 1 deletion(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index 487567848a5e1..a398af33f490d 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -12,6 +12,27 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Philosophy and goals](#philosophy-and-goals) - [Overview](#overview) +- [C++ Interoperability Model: Introduction and Principles](#c-interoperability-model-introduction-and-principles) + - [The "Successor Language" Mandate](#the-successor-language-mandate) + - [The `Cpp` Associated Type: The Interop Trigger](#the-cpp-associated-type-the-interop-trigger) +- [Importing C++ APIs into Carbon](#importing-c-apis-into-carbon) + - [Importing C++ Libraries (Header-Based)](#importing-c-libraries-header-based) + - [TODO: Importing C++ Code (Inline)](#todo-importing-c-code-inline) + - [Accessing Built-in C++ Entities (File-less)](#accessing-built-in-c-entities-file-less) + - [The `Cpp` Namespace](#the-cpp-namespace) + - [TODO: Importing C++ Macros](#todo-importing-c-macros) +- [Calling C++ Code from Carbon](#calling-c-code-from-carbon) + - [Function Call Syntax and Semantics](#function-call-syntax-and-semantics) + - [TODO: Overload Resolution](#todo-overload-resolution) + - [TODO: Thunks](#todo-thunks) + - [TODO: Constructors](#todo-constructors) + - [TODO: Struct Literals](#todo-struct-literals) +- [TODO: Accessing C++ Classes, Structs, and Members](#todo-accessing-c-classes-structs-and-members) +- [TODO: Accessing Global Variables](#todo-accessing-global-variables) +- [TODO: Bi-directional Type Mapping: Primitives and Core Types](#todo-bi-directional-type-mapping-primitives-and-core-types) +- [TODO: Advanced Type Mapping: Pointers, References, and `const`](#todo-advanced-type-mapping-pointers-references-and-const) +- [TODO: Bi-directional Type Mapping: Standard Library Types](#todo-bi-directional-type-mapping-standard-library-types) +- [TODO: The Operator Interoperability Model](#todo-the-operator-interoperability-model) @@ -29,4 +50,209 @@ more detail. ## Overview -TODO +Carbon's bidirectional interoperability with C++ is +[a cornerstone of its design](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code), +enabling a gradual transition from existing C++ codebases. The goal is not just +a foreign function interface (FFI), but a seamless, high-fidelity integration +that supports advanced C++ features, from templates to class hierarchies. + +C++ APIs are imported into Carbon using an `import Cpp` directive, which makes +C++ declarations available within a dedicated `Cpp` namespace in Carbon. This +prevents name collisions and makes the origin of symbols explicit. Carbon code +can then call C++ functions, instantiate C++ classes, and use C++ types, while +respecting C++'s semantics, including its complex overload resolution rules. + +Similarly, Carbon APIs can be designed to be callable from C++. The +interoperability layer is designed to be zero-cost, avoiding unnecessary +allocations or copies when calling between the two languages This is achieved +through a deep semantic co-design, where the Carbon compiler embeds a C++ +compiler frontend (Clang) to understand and map C++ constructs with high +fidelity. This includes preserving the nominal distinctions between C++ types +like `long` and `long long`, or `T*` and `T&`, which is critical for correct +overload resolution and template instantiation. + +## C++ Interoperability Model: Introduction and Principles + +### The "Successor Language" Mandate + +The design of Carbon's C++ interoperability is governed by its foundational +goal: [to be a successor language](/README.md), not merely a language with a +foreign function interface (FFI). This mandate dictates a design that moves +beyond the C-style FFI adopted by most modern languages and instead provides +"seamless, bidirectional interoperability". The objective is to support deep +integration with existing C++ code, encompassing its most complex features, +"from inheritance to templates". + +This goal has profound implications for the Carbon compiler and language +semantics. It requires that C++ is not treated as a "foreign" entity. Instead, +Carbon's semantic model must be _co-designed_ to understand, map, and interact +with C++'s semantic constructs—including templates, class hierarchies, and +complex overload resolution—with high fidelity. The interoperability layer must, +therefore, operate at the semantic analysis (SemIR) level, not just at the +linking (ABI) level. This document specifies the design of this semantic +contract. + +### The `Cpp` Associated Type: The Interop Trigger + +A core mechanism in this design is the `Cpp` associated type. This concept +defines the "trigger" that activates C++-specific semantic rules within the +Carbon compiler. Any operation involving a type that is designated as a `Cpp` +associated type will invoke the specialized interoperability logic, such as the +operator model detailed in +[The Operator Interoperability Model Section](#todo-the-operator-interoperability-model). + +A type is considered a `Cpp` associated type if its definition involves an +imported C++ type in any of the following ways: + +1. The C++ type itself (for example, `Cpp.Widget`). +2. A pointer to a C++ type (for example, `Cpp.Widget*`). +3. A Carbon generic type parameterized with a C++ type (for example, + `MyCarbonVector(Cpp.Widget)`). +4. A Carbon struct or class containing a C++ type as a member (for example, + `MyCarbonStruct { x: Cpp.Widget }`). + +This "pervasive" model of C++-awareness is a fundamental design choice. The C++ +semantics are not confined to a specific `unsafe` or `extern "C++"` block; they +"infect" any Carbon type that composes them. For example, when the Carbon +compiler instantiates a _Carbon_ generic type like `MyCarbonVector(Cpp.Widget)`, +its type system must be aware that the `Cpp.Widget` parameter carries +C++-specific rules. This mandates that Carbon's own generic system, struct +layout logic, and operator lookup must query the type system for the presence of +a `Cpp` associated type. If present, the compiler must branch to a different, +more complex logic path (for example, C++-aware overload resolution). This +design prioritizes the goal of a "seamless" and "intuitive" user experience over +implementation simplicity. + +## Importing C++ APIs into Carbon + +### Importing C++ Libraries (Header-Based) + +The primary mechanism for importing existing, user-defined C++ code is through +header file inclusion. The Carbon toolchain must be able to parse and analyze +C++ header files to make their declarations available within Carbon. + +**Syntax:** The syntax for this operation is `import Cpp library "header_name"`. +This syntax is used for both C-style standard libraries and C++ headers: + +- **C Standard Library:** + + ```carbon + import Cpp library ""; + ``` + + This import makes entities like `putchar` available. + +- **C++ User-Defined Header:** + ```carbon + import Cpp library "circle.h"; + ``` + This import makes user-defined declarations and definitions available. + +**Mechanism:** This file-based import model implies a co-compilation strategy. +The Carbon toolchain must embed a full C++ compiler front-end (specifically, +Clang). When the Carbon compiler encounters an `import Cpp library` directive, +it does not attempt to parse the C++ header itself. Instead, it must: + +1. Invoke the embedded Clang library to parse, preprocess, and perform semantic + analysis on the specified header file. +2. Request that Clang build an Abstract Syntax Tree (AST) of the public + declarations within that header. +3. Perform a complex "AST-to-SemIR" translation on demand, "bridging" the C++ + declarations from Clang's AST into Carbon's own semantic representation + (SemIR). + +This model allows Carbon to leverage Clang's mature and correct implementation +of C++'s complex parsing and semantic rules, including template instantiation, +without having to reimplement them. + +### TODO: Importing C++ Code (Inline) + +### Accessing Built-in C++ Entities (File-less) + +Some C++ entities, particularly built-in primitive types, are not defined in any +header file. They are "intrinsic" to the C++ compiler. These entities are +available in Carbon without an explicit `import` declaration. + +**Mechanism:** When a built-in C++ entity is accessed in Carbon code, the +compiler checks if the necessary C++ Abstract Syntax Tree (AST) has been +generated. If not, an AST is generated on-demand. This on-demand generation +ensures that types like `long` or `float` are available seamlessly within the +`Cpp` namespace when they are first used, without requiring developers to +explicitly import them. This approach provides a clean, file-less way to access +the foundational types required for C++ interoperability. + +### The `Cpp` Namespace + +A critical design choice for managing C++ imports is the mandatory use of a +containing namespace, `Cpp`. All imported C++ entities—functions, classes, +types, and operators—are accessed by way of this prefix. + +- **Functions:** `Cpp.putchar(...)` +- **Classes/Types:** `Cpp.Circle`, `Cpp.Point` +- **Constructors:** `Cpp.Circle.Circle()` + +**Rationale:** This prefix acts as a "firewall" and is essential for adhering to +Carbon's core design principles of +[Namespace cleanliness](/docs/project/principles/namespace_cleanliness.md) and +[Low context-sensitivity](/docs/project/principles/low_context_sensitivity.md). + +C++ codebases, particularly older ones, are often "polluted" with +global-namespace functions and, most problematically, thousands of un-namespaced +preprocessor macros (for example, in standard platform headers). A "naive" +import that dumps these symbols into the Carbon global namespace would be +disastrous, leading to rampant name collisions and high context-sensitivity (for +example, "Does `Foo` refer to Carbon's `Foo` or an imported C++ `Foo`?"). + +The `Cpp.` prefix makes the _origin_ of every symbol explicit and unambiguous. +It ensures that C++ entities cannot collide with Carbon code, thereby "learning +from" one of C++'s most significant legacy design issues. + +### TODO: Importing C++ Macros + +## Calling C++ Code from Carbon + +### Function Call Syntax and Semantics + +Once imported, C++ functions are invoked using standard Carbon function call +syntax, prefixed with the `Cpp` namespace. The Carbon compiler is responsible +for mapping the Carbon arguments to the types expected by the C++ function's +signature. + +This often requires explicit casting on the Carbon side, using the `as` keyword, +to satisfy the C++ function's parameter types. + +**Example:** The following example imports `cstdio` and calls the C function +`putchar`. The Carbon `Core.Char` variable `n` must be cast first to `u8` and +then to `i32` to match the `int` parameter expected by `putchar`. + +```carbon +import Cpp library ""; + +fn Run() { + let hello: array(Core.Char, 6) = ('H', 'e', 'l', 'l', 'o', '!'); + for (n: Core.Char in hello) { + // Carbon 'as' casting is used to match the C++ signature + Cpp.putchar((n as u8) as i32); + } +} +``` + +### TODO: Overload Resolution + +### TODO: Thunks + +### TODO: Constructors + +### TODO: Struct Literals + +## TODO: Accessing C++ Classes, Structs, and Members + +## TODO: Accessing Global Variables + +## TODO: Bi-directional Type Mapping: Primitives and Core Types + +## TODO: Advanced Type Mapping: Pointers, References, and `const` + +## TODO: Bi-directional Type Mapping: Standard Library Types + +## TODO: The Operator Interoperability Model From 56249f76dd0af2fb54327b8a7c777c847d71c10c Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Thu, 13 Nov 2025 10:23:31 +0100 Subject: [PATCH 02/10] Use sentence case for headings --- docs/design/interoperability/README.md | 72 +++++++++++++------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index a398af33f490d..e89ac618a12be 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -12,27 +12,27 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Philosophy and goals](#philosophy-and-goals) - [Overview](#overview) -- [C++ Interoperability Model: Introduction and Principles](#c-interoperability-model-introduction-and-principles) - - [The "Successor Language" Mandate](#the-successor-language-mandate) - - [The `Cpp` Associated Type: The Interop Trigger](#the-cpp-associated-type-the-interop-trigger) +- [C++ interoperability model: introduction and principles](#c-interoperability-model-introduction-and-principles) + - [The "successor language" mandate](#the-successor-language-mandate) + - [The `Cpp` associated type: the interop trigger](#the-cpp-associated-type-the-interop-trigger) - [Importing C++ APIs into Carbon](#importing-c-apis-into-carbon) - - [Importing C++ Libraries (Header-Based)](#importing-c-libraries-header-based) - - [TODO: Importing C++ Code (Inline)](#todo-importing-c-code-inline) - - [Accessing Built-in C++ Entities (File-less)](#accessing-built-in-c-entities-file-less) - - [The `Cpp` Namespace](#the-cpp-namespace) - - [TODO: Importing C++ Macros](#todo-importing-c-macros) -- [Calling C++ Code from Carbon](#calling-c-code-from-carbon) - - [Function Call Syntax and Semantics](#function-call-syntax-and-semantics) - - [TODO: Overload Resolution](#todo-overload-resolution) + - [Importing C++ libraries (header-based)](#importing-c-libraries-header-based) + - [TODO: Importing C++ code (inline)](#todo-importing-c-code-inline) + - [Accessing built-in C++ entities (file-less)](#accessing-built-in-c-entities-file-less) + - [The `Cpp` namespace](#the-cpp-namespace) + - [TODO: Importing C++ macros](#todo-importing-c-macros) +- [Calling C++ code from Carbon](#calling-c-code-from-carbon) + - [Function call syntax and semantics](#function-call-syntax-and-semantics) + - [TODO: Overload resolution](#todo-overload-resolution) - [TODO: Thunks](#todo-thunks) - [TODO: Constructors](#todo-constructors) - - [TODO: Struct Literals](#todo-struct-literals) -- [TODO: Accessing C++ Classes, Structs, and Members](#todo-accessing-c-classes-structs-and-members) -- [TODO: Accessing Global Variables](#todo-accessing-global-variables) -- [TODO: Bi-directional Type Mapping: Primitives and Core Types](#todo-bi-directional-type-mapping-primitives-and-core-types) -- [TODO: Advanced Type Mapping: Pointers, References, and `const`](#todo-advanced-type-mapping-pointers-references-and-const) -- [TODO: Bi-directional Type Mapping: Standard Library Types](#todo-bi-directional-type-mapping-standard-library-types) -- [TODO: The Operator Interoperability Model](#todo-the-operator-interoperability-model) + - [TODO: Struct literals](#todo-struct-literals) +- [TODO: Accessing C++ classes, structs, and members](#todo-accessing-c-classes-structs-and-members) +- [TODO: Accessing global variables](#todo-accessing-global-variables) +- [TODO: Bi-directional type mapping: primitives and core types](#todo-bi-directional-type-mapping-primitives-and-core-types) +- [TODO: Advanced type mapping: pointers, references, and `const`](#todo-advanced-type-mapping-pointers-references-and-const) +- [TODO: Bi-directional type mapping: standard library types](#todo-bi-directional-type-mapping-standard-library-types) +- [TODO: The operator interoperability model](#todo-the-operator-interoperability-model) @@ -71,9 +71,9 @@ fidelity. This includes preserving the nominal distinctions between C++ types like `long` and `long long`, or `T*` and `T&`, which is critical for correct overload resolution and template instantiation. -## C++ Interoperability Model: Introduction and Principles +## C++ interoperability model: introduction and principles -### The "Successor Language" Mandate +### The "successor language" mandate The design of Carbon's C++ interoperability is governed by its foundational goal: [to be a successor language](/README.md), not merely a language with a @@ -92,7 +92,7 @@ therefore, operate at the semantic analysis (SemIR) level, not just at the linking (ABI) level. This document specifies the design of this semantic contract. -### The `Cpp` Associated Type: The Interop Trigger +### The `Cpp` associated type: the interop trigger A core mechanism in this design is the `Cpp` associated type. This concept defines the "trigger" that activates C++-specific semantic rules within the @@ -125,7 +125,7 @@ implementation simplicity. ## Importing C++ APIs into Carbon -### Importing C++ Libraries (Header-Based) +### Importing C++ libraries (header-based) The primary mechanism for importing existing, user-defined C++ code is through header file inclusion. The Carbon toolchain must be able to parse and analyze @@ -165,9 +165,9 @@ This model allows Carbon to leverage Clang's mature and correct implementation of C++'s complex parsing and semantic rules, including template instantiation, without having to reimplement them. -### TODO: Importing C++ Code (Inline) +### TODO: Importing C++ code (inline) -### Accessing Built-in C++ Entities (File-less) +### Accessing built-in C++ entities (file-less) Some C++ entities, particularly built-in primitive types, are not defined in any header file. They are "intrinsic" to the C++ compiler. These entities are @@ -181,7 +181,7 @@ ensures that types like `long` or `float` are available seamlessly within the explicitly import them. This approach provides a clean, file-less way to access the foundational types required for C++ interoperability. -### The `Cpp` Namespace +### The `Cpp` namespace A critical design choice for managing C++ imports is the mandatory use of a containing namespace, `Cpp`. All imported C++ entities—functions, classes, @@ -207,11 +207,11 @@ The `Cpp.` prefix makes the _origin_ of every symbol explicit and unambiguous. It ensures that C++ entities cannot collide with Carbon code, thereby "learning from" one of C++'s most significant legacy design issues. -### TODO: Importing C++ Macros +### TODO: Importing C++ macros -## Calling C++ Code from Carbon +## Calling C++ code from Carbon -### Function Call Syntax and Semantics +### Function call syntax and semantics Once imported, C++ functions are invoked using standard Carbon function call syntax, prefixed with the `Cpp` namespace. The Carbon compiler is responsible @@ -237,22 +237,22 @@ fn Run() { } ``` -### TODO: Overload Resolution +### TODO: Overload resolution ### TODO: Thunks ### TODO: Constructors -### TODO: Struct Literals +### TODO: Struct literals -## TODO: Accessing C++ Classes, Structs, and Members +## TODO: Accessing C++ classes, structs, and members -## TODO: Accessing Global Variables +## TODO: Accessing global variables -## TODO: Bi-directional Type Mapping: Primitives and Core Types +## TODO: Bi-directional type mapping: primitives and core types -## TODO: Advanced Type Mapping: Pointers, References, and `const` +## TODO: Advanced type mapping: pointers, references, and `const` -## TODO: Bi-directional Type Mapping: Standard Library Types +## TODO: Bi-directional type mapping: standard library types -## TODO: The Operator Interoperability Model +## TODO: The operator interoperability model From 6da998bbaaaa35340a6a4b5d13638f26d7fffe23 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Thu, 13 Nov 2025 11:37:53 +0100 Subject: [PATCH 03/10] Focus on language design and address review comments. --- docs/design/interoperability/README.md | 127 ++++++++----------------- 1 file changed, 41 insertions(+), 86 deletions(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index e89ac618a12be..30fce42e654fc 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -14,17 +14,16 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Overview](#overview) - [C++ interoperability model: introduction and principles](#c-interoperability-model-introduction-and-principles) - [The "successor language" mandate](#the-successor-language-mandate) - - [The `Cpp` associated type: the interop trigger](#the-cpp-associated-type-the-interop-trigger) + - [The C++ interop type](#the-c-interop-type) - [Importing C++ APIs into Carbon](#importing-c-apis-into-carbon) - [Importing C++ libraries (header-based)](#importing-c-libraries-header-based) - [TODO: Importing C++ code (inline)](#todo-importing-c-code-inline) - [Accessing built-in C++ entities (file-less)](#accessing-built-in-c-entities-file-less) - - [The `Cpp` namespace](#the-cpp-namespace) + - [The `Cpp` package](#the-cpp-package) - [TODO: Importing C++ macros](#todo-importing-c-macros) - [Calling C++ code from Carbon](#calling-c-code-from-carbon) - [Function call syntax and semantics](#function-call-syntax-and-semantics) - [TODO: Overload resolution](#todo-overload-resolution) - - [TODO: Thunks](#todo-thunks) - [TODO: Constructors](#todo-constructors) - [TODO: Struct literals](#todo-struct-literals) - [TODO: Accessing C++ classes, structs, and members](#todo-accessing-c-classes-structs-and-members) @@ -57,19 +56,17 @@ a foreign function interface (FFI), but a seamless, high-fidelity integration that supports advanced C++ features, from templates to class hierarchies. C++ APIs are imported into Carbon using an `import Cpp` directive, which makes -C++ declarations available within a dedicated `Cpp` namespace in Carbon. This +C++ declarations available within a dedicated `Cpp` package in Carbon. This prevents name collisions and makes the origin of symbols explicit. Carbon code can then call C++ functions, instantiate C++ classes, and use C++ types, while -respecting C++'s semantics, including its complex overload resolution rules. +respecting C++'s semantics, including its complex overload resolution rules and +preserving the nominal distinctions between C++ types like `long` and +`long long`, or `T*` and `T&`, which is critical for correct overload resolution +and template instantiation. Similarly, Carbon APIs can be designed to be callable from C++. The interoperability layer is designed to be zero-cost, avoiding unnecessary -allocations or copies when calling between the two languages This is achieved -through a deep semantic co-design, where the Carbon compiler embeds a C++ -compiler frontend (Clang) to understand and map C++ constructs with high -fidelity. This includes preserving the nominal distinctions between C++ types -like `long` and `long long`, or `T*` and `T&`, which is critical for correct -overload resolution and template instantiation. +allocations or copies when calling between the two languages. ## C++ interoperability model: introduction and principles @@ -88,48 +85,46 @@ semantics. It requires that C++ is not treated as a "foreign" entity. Instead, Carbon's semantic model must be _co-designed_ to understand, map, and interact with C++'s semantic constructs—including templates, class hierarchies, and complex overload resolution—with high fidelity. The interoperability layer must, -therefore, operate at the semantic analysis (SemIR) level, not just at the -linking (ABI) level. This document specifies the design of this semantic -contract. +therefore, operate at the semantic analysis level, not just at the linking (ABI) +level. This document specifies the design of this semantic contract. -### The `Cpp` associated type: the interop trigger +### The C++ interop type -A core mechanism in this design is the `Cpp` associated type. This concept -defines the "trigger" that activates C++-specific semantic rules within the -Carbon compiler. Any operation involving a type that is designated as a `Cpp` -associated type will invoke the specialized interoperability logic, such as the -operator model detailed in -[The Operator Interoperability Model Section](#todo-the-operator-interoperability-model). +A core mechanism in this design is the C++ interop type. This concept defines +the "trigger" that activates C++-specific semantic rules within the Carbon +compiler. Any operation involving a type that is designated as a C++ interop +type could invoke the specialized interoperability logic, such as C++ overload +resolution or operator overload resolution that involves both Carbon and C++ +operator overloads.. -A type is considered a `Cpp` associated type if its definition involves an -imported C++ type in any of the following ways: +A type is considered a C++ interop type if its definition involves an imported +C++ type in any of the following ways: -1. The C++ type itself (for example, `Cpp.Widget`). -2. A pointer to a C++ type (for example, `Cpp.Widget*`). -3. A Carbon generic type parameterized with a C++ type (for example, +1. A C++ imported type (for example, `Cpp.Widget`). +2. A pointer to a C++ interop type (for example, `Cpp.Widget*`). +3. A Carbon generic type parameterized with a C++ interop type (for example, `MyCarbonVector(Cpp.Widget)`). -4. A Carbon struct or class containing a C++ type as a member (for example, - `MyCarbonStruct { x: Cpp.Widget }`). +4. A Carbon struct or class containing a C++ interop type as a member (for + example, `MyCarbonStruct { x: Cpp.Widget }`). This "pervasive" model of C++-awareness is a fundamental design choice. The C++ semantics are not confined to a specific `unsafe` or `extern "C++"` block; they -"infect" any Carbon type that composes them. For example, when the Carbon -compiler instantiates a _Carbon_ generic type like `MyCarbonVector(Cpp.Widget)`, -its type system must be aware that the `Cpp.Widget` parameter carries -C++-specific rules. This mandates that Carbon's own generic system, struct -layout logic, and operator lookup must query the type system for the presence of -a `Cpp` associated type. If present, the compiler must branch to a different, -more complex logic path (for example, C++-aware overload resolution). This -design prioritizes the goal of a "seamless" and "intuitive" user experience over -implementation simplicity. +affect any Carbon type that composes them. For example, when the Carbon compiler +instantiates a _Carbon_ generic type like `MyCarbonVector(Cpp.Widget)`, its type +system must be aware that the `Cpp.Widget` parameter carries C++-specific rules. +This mandates that Carbon's own generic system, struct layout logic, overload +resolution and operator lookup must query the type system for the presence of a +C++ interop type. If present, Carbon must consider C++ rules when operating over +C++ interop types. This design prioritizes the goal of a "seamless" and +"intuitive" user experience. ## Importing C++ APIs into Carbon ### Importing C++ libraries (header-based) The primary mechanism for importing existing, user-defined C++ code is through -header file inclusion. The Carbon toolchain must be able to parse and analyze -C++ header files to make their declarations available within Carbon. +header file inclusion. Carbon must be able to parse and analyze C++ header files +to make their declarations available within Carbon. **Syntax:** The syntax for this operation is `import Cpp library "header_name"`. This syntax is used for both C-style standard libraries and C++ headers: @@ -148,64 +143,26 @@ This syntax is used for both C-style standard libraries and C++ headers: ``` This import makes user-defined declarations and definitions available. -**Mechanism:** This file-based import model implies a co-compilation strategy. -The Carbon toolchain must embed a full C++ compiler front-end (specifically, -Clang). When the Carbon compiler encounters an `import Cpp library` directive, -it does not attempt to parse the C++ header itself. Instead, it must: - -1. Invoke the embedded Clang library to parse, preprocess, and perform semantic - analysis on the specified header file. -2. Request that Clang build an Abstract Syntax Tree (AST) of the public - declarations within that header. -3. Perform a complex "AST-to-SemIR" translation on demand, "bridging" the C++ - declarations from Clang's AST into Carbon's own semantic representation - (SemIR). - -This model allows Carbon to leverage Clang's mature and correct implementation -of C++'s complex parsing and semantic rules, including template instantiation, -without having to reimplement them. - ### TODO: Importing C++ code (inline) ### Accessing built-in C++ entities (file-less) Some C++ entities, particularly built-in primitive types, are not defined in any -header file. They are "intrinsic" to the C++ compiler. These entities are +header file. They are "intrinsic" to the C++ language. These entities are available in Carbon without an explicit `import` declaration. -**Mechanism:** When a built-in C++ entity is accessed in Carbon code, the -compiler checks if the necessary C++ Abstract Syntax Tree (AST) has been -generated. If not, an AST is generated on-demand. This on-demand generation -ensures that types like `long` or `float` are available seamlessly within the -`Cpp` namespace when they are first used, without requiring developers to -explicitly import them. This approach provides a clean, file-less way to access -the foundational types required for C++ interoperability. - -### The `Cpp` namespace +### The `Cpp` package A critical design choice for managing C++ imports is the mandatory use of a -containing namespace, `Cpp`. All imported C++ entities—functions, classes, -types, and operators—are accessed by way of this prefix. +containing package, `Cpp`. All imported C++ named entities (functions, types, +namespaces) are contained in the `Cpp` package. - **Functions:** `Cpp.putchar(...)` - **Classes/Types:** `Cpp.Circle`, `Cpp.Point` - **Constructors:** `Cpp.Circle.Circle()` -**Rationale:** This prefix acts as a "firewall" and is essential for adhering to -Carbon's core design principles of -[Namespace cleanliness](/docs/project/principles/namespace_cleanliness.md) and -[Low context-sensitivity](/docs/project/principles/low_context_sensitivity.md). - -C++ codebases, particularly older ones, are often "polluted" with -global-namespace functions and, most problematically, thousands of un-namespaced -preprocessor macros (for example, in standard platform headers). A "naive" -import that dumps these symbols into the Carbon global namespace would be -disastrous, leading to rampant name collisions and high context-sensitivity (for -example, "Does `Foo` refer to Carbon's `Foo` or an imported C++ `Foo`?"). - The `Cpp.` prefix makes the _origin_ of every symbol explicit and unambiguous. -It ensures that C++ entities cannot collide with Carbon code, thereby "learning -from" one of C++'s most significant legacy design issues. +It ensures that C++ entities cannot collide with Carbon code. ### TODO: Importing C++ macros @@ -214,8 +171,8 @@ from" one of C++'s most significant legacy design issues. ### Function call syntax and semantics Once imported, C++ functions are invoked using standard Carbon function call -syntax, prefixed with the `Cpp` namespace. The Carbon compiler is responsible -for mapping the Carbon arguments to the types expected by the C++ function's +syntax, prefixed with the `Cpp` name. The Carbon compiler is responsible for +mapping the Carbon arguments to the types expected by the C++ function's signature. This often requires explicit casting on the Carbon side, using the `as` keyword, @@ -239,8 +196,6 @@ fn Run() { ### TODO: Overload resolution -### TODO: Thunks - ### TODO: Constructors ### TODO: Struct literals From db976ee89039a3200f934879e23f31621efc0f18 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 17 Nov 2025 08:58:08 +0100 Subject: [PATCH 04/10] Avoid mentioning C. --- docs/design/interoperability/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index 30fce42e654fc..249d651814df3 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -127,9 +127,9 @@ header file inclusion. Carbon must be able to parse and analyze C++ header files to make their declarations available within Carbon. **Syntax:** The syntax for this operation is `import Cpp library "header_name"`. -This syntax is used for both C-style standard libraries and C++ headers: +This syntax is used for both standard library headers and user-defined headers: -- **C Standard Library:** +- **Standard Library:** ```carbon import Cpp library ""; From 5aec63f54d17b10fb4f79f1178c40d6ce1c1c331 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 17 Nov 2025 09:00:30 +0100 Subject: [PATCH 05/10] Remove double-quotes. --- docs/design/interoperability/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index 249d651814df3..1121218f0eeff 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -13,7 +13,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Philosophy and goals](#philosophy-and-goals) - [Overview](#overview) - [C++ interoperability model: introduction and principles](#c-interoperability-model-introduction-and-principles) - - [The "successor language" mandate](#the-successor-language-mandate) + - [The successor language mandate](#the-successor-language-mandate) - [The C++ interop type](#the-c-interop-type) - [Importing C++ APIs into Carbon](#importing-c-apis-into-carbon) - [Importing C++ libraries (header-based)](#importing-c-libraries-header-based) @@ -70,18 +70,18 @@ allocations or copies when calling between the two languages. ## C++ interoperability model: introduction and principles -### The "successor language" mandate +### The successor language mandate The design of Carbon's C++ interoperability is governed by its foundational goal: [to be a successor language](/README.md), not merely a language with a foreign function interface (FFI). This mandate dictates a design that moves beyond the C-style FFI adopted by most modern languages and instead provides -"seamless, bidirectional interoperability". The objective is to support deep -integration with existing C++ code, encompassing its most complex features, -"from inheritance to templates". +seamless, bidirectional interoperability. The objective is to support deep +integration with existing C++ code, encompassing its most complex features, from +inheritance to templates. This goal has profound implications for the Carbon compiler and language -semantics. It requires that C++ is not treated as a "foreign" entity. Instead, +semantics. It requires that C++ is not treated as a foreign entity. Instead, Carbon's semantic model must be _co-designed_ to understand, map, and interact with C++'s semantic constructs—including templates, class hierarchies, and complex overload resolution—with high fidelity. The interoperability layer must, @@ -115,8 +115,8 @@ system must be aware that the `Cpp.Widget` parameter carries C++-specific rules. This mandates that Carbon's own generic system, struct layout logic, overload resolution and operator lookup must query the type system for the presence of a C++ interop type. If present, Carbon must consider C++ rules when operating over -C++ interop types. This design prioritizes the goal of a "seamless" and -"intuitive" user experience. +C++ interop types. This design prioritizes the goal of a seamless and intuitive +user experience. ## Importing C++ APIs into Carbon From a7efde0a255542ae517b681728185193d2b1ee77 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 17 Nov 2025 09:05:12 +0100 Subject: [PATCH 06/10] For C++ interop type definition, replace containing a member with extending. --- docs/design/interoperability/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index 1121218f0eeff..68084c2360e72 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -104,8 +104,8 @@ C++ type in any of the following ways: 2. A pointer to a C++ interop type (for example, `Cpp.Widget*`). 3. A Carbon generic type parameterized with a C++ interop type (for example, `MyCarbonVector(Cpp.Widget)`). -4. A Carbon struct or class containing a C++ interop type as a member (for - example, `MyCarbonStruct { x: Cpp.Widget }`). +4. A Carbon class extending a C++ interop type as a member (for example, + `class MyCarbonClass { extend base: Cpp.Widget; }`). This "pervasive" model of C++-awareness is a fundamental design choice. The C++ semantics are not confined to a specific `unsafe` or `extern "C++"` block; they From 1f2f37f90fa76b1f3e6db68826a71cc5acd9ee30 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 17 Nov 2025 09:05:34 +0100 Subject: [PATCH 07/10] Fix double period typo. --- docs/design/interoperability/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index 68084c2360e72..c3b8d95b6763f 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -95,7 +95,7 @@ the "trigger" that activates C++-specific semantic rules within the Carbon compiler. Any operation involving a type that is designated as a C++ interop type could invoke the specialized interoperability logic, such as C++ overload resolution or operator overload resolution that involves both Carbon and C++ -operator overloads.. +operator overloads. A type is considered a C++ interop type if its definition involves an imported C++ type in any of the following ways: From 9c59aa1b4245697f7d9e9090cf1dcde2dcbeae34 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 17 Nov 2025 10:07:25 +0100 Subject: [PATCH 08/10] Filling out template with PR 6358 --- proposals/p6358.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 proposals/p6358.md diff --git a/proposals/p6358.md b/proposals/p6358.md new file mode 100644 index 0000000000000..947f84c1ccee1 --- /dev/null +++ b/proposals/p6358.md @@ -0,0 +1,70 @@ +# C++ Interop: API importing and semantics + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/6358) + + + +## Table of contents + +- [Abstract](#abstract) +- [Problem](#problem) +- [Background](#background) +- [Proposal](#proposal) +- [Details](#details) +- [Rationale](#rationale) +- [Alternatives considered](#alternatives-considered) + + + +## Abstract + +TODO: Describe, in a succinct paragraph, the gist of this document. This +paragraph should be reproduced verbatim in the PR summary. + +## Problem + +TODO: What problem are you trying to solve? How important is that problem? Who +is impacted by it? + +## Background + +TODO: Is there any background that readers should consider to fully understand +this problem and your approach to solving it? + +## Proposal + +TODO: Briefly and at a high level, how do you propose to solve the problem? Why +will that in fact solve it? + +## Details + +TODO: Fully explain the details of the proposed solution. + +## Rationale + +TODO: How does this proposal effectively advance Carbon's goals? Rather than +re-stating the full motivation, this should connect that motivation back to +Carbon's stated goals and principles. This may evolve during review. Use links +to appropriate sections of [`/docs/project/goals.md`](/docs/project/goals.md), +and/or to documents in [`/docs/project/principles`](/docs/project/principles). +For example: + +- [Community and culture](/docs/project/goals.md#community-and-culture) +- [Language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem) +- [Performance-critical software](/docs/project/goals.md#performance-critical-software) +- [Software and language evolution](/docs/project/goals.md#software-and-language-evolution) +- [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write) +- [Practical safety and testing mechanisms](/docs/project/goals.md#practical-safety-and-testing-mechanisms) +- [Fast and scalable development](/docs/project/goals.md#fast-and-scalable-development) +- [Modern OS platforms, hardware architectures, and environments](/docs/project/goals.md#modern-os-platforms-hardware-architectures-and-environments) +- [Interoperability with and migration from existing C++ code](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code) + +## Alternatives considered + +TODO: What alternative solutions have you considered? From a8a3c4fd7d1c9f5b04dd6e58737ba656cc7f56fc Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 17 Nov 2025 10:24:41 +0100 Subject: [PATCH 09/10] Fix typo. --- docs/design/interoperability/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index c3b8d95b6763f..b19f5c5f391c6 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -104,7 +104,7 @@ C++ type in any of the following ways: 2. A pointer to a C++ interop type (for example, `Cpp.Widget*`). 3. A Carbon generic type parameterized with a C++ interop type (for example, `MyCarbonVector(Cpp.Widget)`). -4. A Carbon class extending a C++ interop type as a member (for example, +4. A Carbon class extending a C++ interop type (for example, `class MyCarbonClass { extend base: Cpp.Widget; }`). This "pervasive" model of C++-awareness is a fundamental design choice. The C++ From d06da8e3b72add7b9f4bd89e233de33e7b592068 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 17 Nov 2025 13:29:25 +0100 Subject: [PATCH 10/10] Add C++ Interop: API importing and semantics proposal --- proposals/p6358.md | 121 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 26 deletions(-) diff --git a/proposals/p6358.md b/proposals/p6358.md index 947f84c1ccee1..5c00056397d4d 100644 --- a/proposals/p6358.md +++ b/proposals/p6358.md @@ -17,6 +17,9 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Background](#background) - [Proposal](#proposal) - [Details](#details) + - [The `Cpp` package and namespace mapping](#the-cpp-package-and-namespace-mapping) + - [`import Cpp library` directive](#import-cpp-library-directive) + - [C++ built-in types](#c-built-in-types) - [Rationale](#rationale) - [Alternatives considered](#alternatives-considered) @@ -24,47 +27,113 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ## Abstract -TODO: Describe, in a succinct paragraph, the gist of this document. This -paragraph should be reproduced verbatim in the PR summary. +This proposal defines the concrete technical mechanisms for C++ +interoperability. It builds on the high-level directional agreement of #6254 +("Calling C++ Functions") by specifying the precise syntax and semantics for +importing C++ APIs. This includes the `import Cpp library "..."` and implicitly +importing C++ built-in entities, and the establishment of the `Cpp` package as +the dedicated namespace for all imported entities. ## Problem -TODO: What problem are you trying to solve? How important is that problem? Who -is impacted by it? +While Carbon has a stated goal of seamless C++ interoperability, and a +high-level direction has been agreed upon, there is currently no concrete, +specified mechanism for developers to actually import and use C++ APIs. This +proposal aims to address that by defining the specific syntax and semantics for +C++ interoperability. ## Background -TODO: Is there any background that readers should consider to fully understand -this problem and your approach to solving it? +One of Carbon's primary goals is to be a successor language. This strategy is +entirely dependent on seamless, bidirectional interoperability with C++ to +enable large-scale adoption and migration for existing C++ codebases. + +Proposal #6254 describes how C++ function should be called. This proposal +provides the necessary details on how C++ APIs should be imported. ## Proposal -TODO: Briefly and at a high level, how do you propose to solve the problem? Why -will that in fact solve it? +We propose to formalize the following specific design elements for C++ +interoperability: + +1. **The `Cpp` Package:** All imported C++ entities, whether from built-ins or + library headers (see below), will be nested within a dedicated `Cpp` + package. This prevents name collisions with Carbon code and makes the + language boundary explicit. + + ```carbon + fn UseCppTypes() { + // Access C++ types and functions by way of the Cpp package + var circle: Cpp.Circle = Cpp.GenerateCircle(); + Cpp.PrintCircle(circle); + } + ``` + +2. **Importing C++ Header-Defined APIs:** To import C++ APIs from a specific + library header file (for example, `` or `"my_library.h"`), Carbon + code will use the `import Cpp library "..."` directive. + + ```carbon + import Cpp library ""; + import Cpp library "circle.h"; + ``` + +3. **Importing C++ Built-in Entities:** To access fundamental C++ types (such + as `int`, `bool`, etc.), no explicit importing is needed and writing + `Cpp.int` and `Cpp.bool` would just work. ## Details -TODO: Fully explain the details of the proposed solution. +### The `Cpp` package and namespace mapping + +All C++ declarations will be imported into the `Cpp` package. C++ namespaces +will be mapped to nested packages within `Cpp`. For example, a C++ function +`std::string::find` would be accessible in Carbon as `Cpp.std.string.find`. The +C++ global namespace will be mapped to the `Cpp` package itself. So a function +`MyGlobalFunction` in the C++ global namespace will be `Cpp.MyGlobalFunction` in +Carbon. + +### `import Cpp library` directive + +The `import Cpp library "..."` directive will instruct the Carbon compiler to +parse the specified C++ header file. The compiler will use the standard C++ +include paths to locate the header. Additional paths can be provided through +compiler flags. + +The Carbon compiler will leverage a C++ front-end, like Clang, to parse the +headers. This ensures a high degree of compatibility with existing C++ code. +Only the declarations from the header will be imported, not the definitions +(unless they are inline). + +### C++ built-in types + +A set of fundamental C++ types will be available within the `Cpp` package +without any explicit `import` directive. Mapping examples: + +| C++ Type | Carbon Type | +| -------------- | ------------------ | +| `int` | `Cpp.int` | +| `unsigned int` | `Cpp.unsigned_int` | +| `double` | `Cpp.double` | +| `float` | `Cpp.float` | +| `bool` | `Cpp.bool` | +| `char` | `Cpp.char` | + +This automatic availability of built-in types is designed to make basic +interoperability tasks as smooth as possible. ## Rationale -TODO: How does this proposal effectively advance Carbon's goals? Rather than -re-stating the full motivation, this should connect that motivation back to -Carbon's stated goals and principles. This may evolve during review. Use links -to appropriate sections of [`/docs/project/goals.md`](/docs/project/goals.md), -and/or to documents in [`/docs/project/principles`](/docs/project/principles). -For example: - -- [Community and culture](/docs/project/goals.md#community-and-culture) -- [Language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem) -- [Performance-critical software](/docs/project/goals.md#performance-critical-software) -- [Software and language evolution](/docs/project/goals.md#software-and-language-evolution) -- [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write) -- [Practical safety and testing mechanisms](/docs/project/goals.md#practical-safety-and-testing-mechanisms) -- [Fast and scalable development](/docs/project/goals.md#fast-and-scalable-development) -- [Modern OS platforms, hardware architectures, and environments](/docs/project/goals.md#modern-os-platforms-hardware-architectures-and-environments) -- [Interoperability with and migration from existing C++ code](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code) +- **Explicitness and Clarity:** The `import Cpp library "..."` directives make + all dependencies on C++ headers. +- **Preventing Name Collisions:** The `Cpp` package is a critical design + element. It provides a clean, unambiguous namespace for all imported C++ + code. ## Alternatives considered -TODO: What alternative solutions have you considered? +- **Alternative: Explicitly importing built-ins:** We considered making C++ + built-in types (like `int`) require some `import Cpp` directive like + `import Cpp;`. + - **Reason for Rejection:** Since `Cpp` is a special package, it should be + implicitly imported, similar to Carbon's prelude.