diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index 960ba6d469fe..2c36944d9bf3 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -30,6 +30,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [TODO: Accessing global variables](#todo-accessing-global-variables) - [Bi-directional type mapping: primitives and core types](#bi-directional-type-mapping-primitives-and-core-types) - [TODO: Integers](#todo-integers) + - [Literals](#literals) - [Character types](#character-types) - [References](#references) - [TODO: Advanced type mapping: pointers, references, and `const`](#todo-advanced-type-mapping-pointers-references-and-const) @@ -213,6 +214,16 @@ fn Run() { ### TODO: Integers +### Literals + +Carbon and C++ support bi-directional mapping for the types of integer and +floating-point literals. Because Carbon literals do not have suffixes, they +typically follow C++ rules for unsuffixed decimal literals, but can also be +explicitly cast. C++ literals map to corresponding Carbon types based on their +suffixes. + +For details, see [literals](literals.md). + ### Character types Carbon's `char` type transparently maps to C++'s `char` type. Carbon's `char` diff --git a/docs/design/interoperability/literals.md b/docs/design/interoperability/literals.md new file mode 100644 index 000000000000..4e50082e1de5 --- /dev/null +++ b/docs/design/interoperability/literals.md @@ -0,0 +1,136 @@ +# C++ interop type mapping for integer and floating-point literals + + + + + +## Table of contents + +- [Overview](#overview) +- [Carbon to C++ type mapping](#carbon-to-c-type-mapping) + - [Integer literals](#integer-literals) + - [Floating-point literals](#floating-point-literals) +- [C++ to Carbon type mapping](#c-to-carbon-type-mapping) + - [Integer literals](#integer-literals-1) + - [Floating-point literals](#floating-point-literals-1) +- [Alternatives considered](#alternatives-considered) +- [References](#references) + + + +## Overview + +The behavior of literals that participate in interop depends on the direction of +interop, but generally follows C++ rules: + +- **Carbon literal to C++ type**: A Carbon literal will be given a C++ type + according to the C++ rules when used in C++ context, such as calling a C++ + function. +- **C++ literal to Carbon type**: A C++ literal will be given a C++ type + following the C++ rules, which will then be mapped to a Carbon type as + defined in + [primitive types mapping](/proposals/p005448-carbon-c-interop-primitive-types.md#carbon-primitive-types). + - For example, `1` becomes `int` according to C++ rules, and `int` maps to + `i32` in Carbon. + +This is used: + +- During overload resolution of C++ functions, when a C++ function is called + from Carbon with a literal as an argument. +- When importing C++ macros to Carbon, such as macros defining constants where + the constant is a literal. + +## Carbon to C++ type mapping + +### Integer literals + +Because there are no suffixes in Carbon for the integer types, a Carbon decimal +integer literal will follow the C++ rules for decimal integers. Carbon also +doesn't make a distinction between hexadecimal and binary literals for interop, +so these literals will also follow the C++ rules for decimal integers without a +suffix. + +The first type from the following list in which the literal's value can fit is +selected: + +- `int` +- `long` +- `long long` +- `__int128` + +If the value doesn’t fit in any of these types, the program is ill-formed and +diagnosed with an error. This matches the C++ standard behavior rather than +Clang's `-Wimplicitly-unsigned-literal` behavior. + +Because decimal numbers are most commonly used as integer literals, this should +match most existing C++ calls. To match a C++ call with a non-decimal literal +argument expecting an unsigned type, an explicit unsigned type must be provided +in Carbon. For example: + +```carbon +Cpp.f(0xDEADBEEF as u32); +``` + +### Floating-point literals + +As there are no suffixes in Carbon for the floating-point literals, a Carbon +floating-point literal will map to C++ `double`. If the value doesn’t fit in +`double`, the program is ill-formed. + +## C++ to Carbon type mapping + +### Integer literals + +A C++ integer literal will be given a C++ integer type following the C++ rules, +which is then mapped to a Carbon type as defined in the +[primitive types mapping](/proposals/p005448-carbon-c-interop-primitive-types.md#carbon-primitive-types). + +| C++ literal suffix | Carbon type with decimal C++ integer literals | Carbon type with hexadecimal, binary and octal C++ integer literals | +| --------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| (none) | `Cpp.int`, `Cpp.long`, `Cpp.long_long` | `Cpp.int`, `Cpp.unsigned_int`, `Cpp.long`, `Cpp.unsigned_long`, `Cpp.long_long`, `Cpp.unsigned_long_long` | +| `u` or `U` | `Cpp.unsigned_int`, `Cpp.unsigned_long`, `Cpp.unsigned_long_long` | `Cpp.unsigned_int`, `Cpp.unsigned_long`, `Cpp.unsigned_long_long` | +| `l` or `L` | `Cpp.long`, `Cpp.long_long` | `Cpp.long`, `Cpp.unsigned_long`, `Cpp.long_long`, `Cpp.unsigned_long_long` | +| `u` or `U` and `l` or `L` | `Cpp.unsigned_long`, `Cpp.unsigned_long_long` | `Cpp.unsigned_long`, `Cpp.unsigned_long_long` | +| `ll` or `LL` | `Cpp.long_long` | `Cpp.long_long`, `Cpp.unsigned_long_long` | +| `u` or `U` and `ll` or `LL` | `Cpp.unsigned_long_long` | `Cpp.unsigned_long_long` | +| `z` or `Z` (since C++23) | `Cpp.uintptr_t` | `Cpp.uintptr_t`, `Cpp.size_t` | +| `u` or `U` and `z` or `Z` (since C++23) | `Cpp.size_t` | `Cpp.size_t` | + +### Floating-point literals + +A C++ floating literal will be given a C++ type following the C++ rules, which +is then mapped to a Carbon type as defined in +[primitive types mapping](/proposals/p005448-carbon-c-interop-primitive-types.md#carbon-primitive-types). +: + +| C++ floating-point literal suffix | Carbon floating-point literal type | +| --------------------------------- | ---------------------------------- | +| (none) | `f64` | +| `f` or `F` | `f32` | +| `l` or `L` | `Cpp.long_double` | +| `f16` or `F16` (since C++23) | `f16` | +| `f32` or `F32` (since C++23) | TBD | +| `f64` or `F64` (since C++23) | TBD | +| `f128` or `F128` (since C++23) | `f128` | +| `bf16` or `BF16` (since C++23) | TBD | + +## Alternatives considered + +Carbon to C++ type mapping + +- [Use the C++ standard rules for hexadecimal and binary literals](/proposals/p006668-c-interop-type-mapping-for-integer-and-floating-point-literals.md#use-the-c-standard-rules-for-hexadecimal-and-binary-literals) +- [Use the Clang way of determining the type](/proposals/p006668-c-interop-type-mapping-for-integer-and-floating-point-literals.md#use-the-clang-way-of-determining-the-type) + +C++ to Carbon type mapping + +- [Use Carbon literal types](/proposals/p006668-c-interop-type-mapping-for-integer-and-floating-point-literals.md#use-carbon-literal-types) + +## References + +- [Proposal #144: Numeric literal semantics](https://github.com/carbon-language/carbon-lang/pull/144) +- [Proposal #5448: Carbon / C++ interop primitive types](https://github.com/carbon-language/carbon-lang/pull/5448) +- [Proposal #6668: C++ interop type mapping for integer and floating-point literals](https://github.com/carbon-language/carbon-lang/pull/6668)