Commit Graph
34 Commits
Author SHA1 Message Date
Jon Ross-Perkinsandjonmeow 9266ced4e3 Improve CanDestroyType to handle remaining cases (#6943)
This is only fixing the decision about *whether* to produce a witness.
Implementation of the witness is still a TODO, though where a body is
generated, it should also precisely reflect where one _needs_ to be
generated.

Note the tests:

- toolchain/lower/testdata/function/generic/import_core_witness.carbon
- toolchain/lower/testdata/function/generic/import_unused_def.carbon

These tests can probably be produced _without_ Core.Destroy, but I found
the essence of them while trying to build //examples with Core.Destroy
and a simpler minimization wasn't striking me.

Assisted-by: Google Antigravity with Gemini

---------

Co-authored-by: jonmeow <jperkins@google.com>
2026-04-02 22:54:58 +00:00
Jon Ross-Perkins c5761d2d16 Improve parsing large integers (#6908)
Though I started this thinking about performance of parse of large
decimal integers, I extended it to generally improve performance of
integer values (TBH I hadn't expected such a difference for binary/hex,
but I'll take it).

Note I think tests change because I'm making subtle changes to bit
widths. The changes themselves appear harmless to me, but happy to make
changes if it'd help.

Bumping up the number of digits by 10x because it's not really a
performance issue anymore (eh, maybe somebody will want to specify a
256-byte value in binary). But, at a certain point it still seems like a
mistake if somebody has that many digits in a row.

Fixes #980

Highlighting benchmark differences:
```diff
- BM_ComputeValue_IntDecimalN/1           37.1 ns         37.1 ns     18887116
+ BM_ComputeValue_IntDecimalN/1           21.9 ns         21.9 ns     31902433
- BM_ComputeValue_IntDecimalN/10000 1251228680 ns   1250457559 ns            1
+ BM_ComputeValue_IntDecimalN/10000     458818 ns       458626 ns         1523
- BM_ComputeValue_IntBinaryN/1            29.0 ns         29.0 ns     24058533
+ BM_ComputeValue_IntBinaryN/1            22.2 ns         22.1 ns     31566949
- BM_ComputeValue_IntBinaryN/10000     1390557 ns      1389782 ns          506
+ BM_ComputeValue_IntBinaryN/10000       16402 ns        16396 ns        42744
- BM_ComputeValue_IntHexN/1               34.0 ns         34.0 ns     20562432
+ BM_ComputeValue_IntHexN/1               22.4 ns         22.4 ns     31238055
- BM_ComputeValue_IntHexN/10000        5387942 ns      5385262 ns          130
+ BM_ComputeValue_IntHexN/10000          39249 ns        39233 ns        17859
```

Benchmark before:
```
----------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations
----------------------------------------------------------------------------
BM_Lex_Float                            10.6 ns         10.6 ns     66138191
BM_Lex_Int                              15.5 ns         15.4 ns     45149703
BM_Lex_IntDecimalN/1                    3.11 ns         3.11 ns    225524908
BM_Lex_IntDecimalN/10                   11.8 ns         11.8 ns     56719805
BM_Lex_IntDecimalN/100                   102 ns          102 ns      6867468
BM_Lex_IntDecimalN/1000                  943 ns          942 ns       745313
BM_Lex_IntDecimalN/10000                9465 ns         9461 ns        73970
BM_ComputeValue_Float                   61.6 ns         61.6 ns     11377463
BM_ComputeValue_Int                      106 ns          106 ns      6587381
BM_ComputeValue_IntDecimalN/1           37.1 ns         37.1 ns     18887116
BM_ComputeValue_IntDecimalN/10          87.7 ns         87.7 ns      7960837
BM_ComputeValue_IntDecimalN/100         7963 ns         7956 ns        88858
BM_ComputeValue_IntDecimalN/1000     1212577 ns      1211906 ns          578
BM_ComputeValue_IntDecimalN/10000 1251228680 ns   1250457559 ns            1
BM_ComputeValue_IntBinaryN/1            29.0 ns         29.0 ns     24058533
BM_ComputeValue_IntBinaryN/10           69.4 ns         69.4 ns     10108642
BM_ComputeValue_IntBinaryN/100           963 ns          962 ns       726982
BM_ComputeValue_IntBinaryN/1000        21562 ns        21551 ns        32506
BM_ComputeValue_IntBinaryN/10000     1390557 ns      1389782 ns          506
BM_ComputeValue_IntHexN/1               34.0 ns         34.0 ns     20562432
BM_ComputeValue_IntHexN/10              70.4 ns         70.4 ns      9953165
BM_ComputeValue_IntHexN/100             1474 ns         1473 ns       472776
BM_ComputeValue_IntHexN/1000           61818 ns        61762 ns        11363
BM_ComputeValue_IntHexN/10000        5387942 ns      5385262 ns          130
```

Benchmark after:
```
----------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations
----------------------------------------------------------------------------
BM_Lex_Float                            10.9 ns         10.9 ns     63993114
BM_Lex_Int                              15.1 ns         15.1 ns     46869766
BM_Lex_IntDecimalN/1                    3.16 ns         3.16 ns    220923300
BM_Lex_IntDecimalN/10                   12.2 ns         12.2 ns     57731654
BM_Lex_IntDecimalN/100                   102 ns          102 ns      6875516
BM_Lex_IntDecimalN/1000                  942 ns          942 ns       742359
BM_Lex_IntDecimalN/10000                9353 ns         9350 ns        75096
BM_ComputeValue_Float                   44.9 ns         44.9 ns     15619691
BM_ComputeValue_Int                     48.9 ns         48.9 ns     14361507
BM_ComputeValue_IntDecimalN/1           21.9 ns         21.9 ns     31902433
BM_ComputeValue_IntDecimalN/10          30.3 ns         30.3 ns     23134117
BM_ComputeValue_IntDecimalN/100          224 ns          223 ns      3092567
BM_ComputeValue_IntDecimalN/1000        5834 ns         5830 ns       117469
BM_ComputeValue_IntDecimalN/10000     458818 ns       458626 ns         1523
BM_ComputeValue_IntBinaryN/1            22.2 ns         22.1 ns     31566949
BM_ComputeValue_IntBinaryN/10           32.9 ns         32.9 ns     21306927
BM_ComputeValue_IntBinaryN/100           198 ns          198 ns      3545277
BM_ComputeValue_IntBinaryN/1000         1671 ns         1669 ns       419656
BM_ComputeValue_IntBinaryN/10000       16402 ns        16396 ns        42744
BM_ComputeValue_IntHexN/1               22.4 ns         22.4 ns     31238055
BM_ComputeValue_IntHexN/10              47.8 ns         47.7 ns     14694407
BM_ComputeValue_IntHexN/100              436 ns          436 ns      1609794
BM_ComputeValue_IntHexN/1000            3966 ns         3962 ns       177109
BM_ComputeValue_IntHexN/10000          39249 ns        39233 ns        17859
```

Assisted-by: Google Antigravity with Gemini
2026-03-16 20:00:51 +00:00
Nicholas Bishop 943cd41924 Support constexpr pointers (#6907)
This moves the LValue path code from macros.cpp to constant.cpp, so that
it can be called from `MapAPValueToConstant`. TODO messages are updated
accordingly to avoid referring to macros. Added a constexpr pointer test
to `constexpr.carbon` to show the result of this change.
2026-03-16 19:19:20 +00:00
Richard Smith c297344937 Support conversion between integer types. (#6856)
Add an `IntFitsIn` interface with a custom witness, such that `T impls
IntFitsIn(U)` if `T` is an integer type all of whose values fit
losslessly into the integer type `U`. Use it to constrain implicit
conversions between integer types.

So far, this has not been extended to the
`CppCompat.[U]{Long32,LongLong64}` types, only to `Core.Int(N)` and
`Core.UInt(N)`.

Assisted-by: Gemini 3 Pro via Antigravity
2026-03-10 01:40:16 +00:00
Nicholas Bishop 8a4888c3df Support assigning to a struct field through a macro (#6843)
Example:

```carbon
import Cpp inline '''
struct B {
  int c;
};
struct A {
  B b;
};
A a;
#define m a.b.c
''';

fn F() {
  Cpp.m = 2;
}
```
2026-03-09 15:31:16 +00:00
Nicholas Bishop e5957037fb Support assigning to a variable through an imported macro (#6827)
Support assigning to a variable through an imported macro

Example:

```carbon
import Cpp inline '''
int v = 1;
#define m v
''';

fn F() {
  Cpp.m = 2;
}
```
2026-03-05 18:24:32 +00:00
Nicholas Bishop 069c6f4447 Refactor TryEvaluateMacroToConstant to simplify and dedup code (#6820)
For integral and float types, `TryEvaluateMacroToConstant` now calls
`MapAPValueToConstant` to directly convert from an APValue, rather than
converting the `APValue` to an expression and importing it with
`MapConstant`.

`MapConstant` is still used, but only for string literals and nullptrs.
Since it's only used by `TryEvaluateMacroToConstant`, moved it to
`macros.cpp` and removed the code for other types of expressions.
2026-03-02 21:00:07 +00:00
Jon Ross-Perkins b14015602b Make Destroy.Op functions able to have a body (#6729)
This is iterating on how `Destroy.Op` generates, to start adding body
capabilities. This changes the way the signature is created, and adds a
`CoreWitness` function kind so that mangling can prevent name
collisions. The result is that what _was_ `DestroyOp` is now
`Core.Destroy.Op` or, as can be seen in
toolchain/lower/testdata/interop/cpp/nullptr.carbon,
`_COp.<hash>:core.Destroy.Core` where `:core` is indicating that it's a
core witness (taking a note from `:thunk`).

Assisted-by: Google Antigravity with Gemini 3 Flash
2026-03-02 17:57:31 +00:00
Dana Jansens cea52ad2d8 Format the InterfaceWithSelf and NamedConstraintWithSelf generic name with its ".WithSelf" suffix (#6798)
We used the ".WithSelf" suffix when formatting a parent scope, but
missed the suffix when formatting the scope name on its own.
2026-02-27 13:50:56 +00:00
Richard Smith f9ab963bd6 Add a type_literal instruction to represent syntactic type literals. (#6781)
This allows us to capture the location at which a type literal was used,
even in the cases where we don't otherwise need to create a new
instruction to represent the type such as for `char` or `str`.

The logic used to build the underlying type is now marked as desugaring.
For cases such as `iN`, this causes the call to `Core.Int` to no longer
be added as a dedicated IR instruction, and instead its constant value
is used directly as the value of the `type_literal`. This results in
this being on balance a reduction in the size of the IR.

This also fixes a crash in C++ interop when using a `char` literal as a
template argument. The crash was caused by the template argument not
having an associated location when mapping to a C++ location. See
changes to check/testdata/interop/cpp/template/type_param.carbon for an
example that used to crash before this change.

Update alias handling to allow an alias to point at any type literal,
reinstating support for aliases for type literals such as `bool` and
`i32` that had previously worked but stopped working when we
transitioned those types to being defined in the prelude. See changes to
toolchain/check/testdata/alias/builtins.carbon.

All the test changes other than the two mentioned above are mechanical
autoupdate changes switching to the new instruction.
2026-02-26 20:10:50 +00:00
fdb188ccfd Implement unused pattern bindings, continued (#6518)
Implementation of unused pattern bindings #2022, continued.

Whereas previous PR #6460 took care of parsing, and PR #6479 prepared
the stage by using _ in some test cases, this PR has the the actual
implementation, using a simple dataflow analysis.

---------

Co-authored-by: Burak Emir <bqe@google.com>
Co-authored-by: jonmeow <jperkins@google.com>
2026-02-19 23:33:36 +00:00
Dana Jansens 917a6ea971 Add an interface-with-self generic to each interface and same for constraints (#6667)
Currently each interface has a `Self` facet internally that becomes a
binding to every entity inside the interface: associated constants,
functions, and require decls. Each of these has to be independently
generic as a result. This makes is challenging in extended name lookup
to move into an extended scope of an interface, as we have a specific
for the interface, but the names within require a different specific
that includes a `Self` facet value.

We generalize this relationship by adding a second generic to Interface,
called `generic_with_self`. When we want to work with entities inside
the interface, we move from the interface-without-specific to the
interface-with-self specific by adding a Self to the specific. This is
done independently of any particular entity inside the Interface, as
those entities are now all members of the interface-with-self generic.

Associated constants no longer need a generic of their own, as they do
not have separate generic bindings. Functions retain a generic, but if
the function has no generic arguments, it will have no bindings of its
own now.

Require decls retain a generic so that their specific can be
instantiated separately from the interface. Requiring the interface to
be complete does not require the types in a require decl to be complete
unless it is modified by `extend`. So we allow them to be completed
later by keeping them in a separate generic.

Named constraints look like interfaces and gain the additional inner
generic-with-self, with the same relationship to require decls.

This removes the need for name lookup to perform Substitution of a Self
facet into the extended scope instruction. Instead, the
`SpecificConstant` instruction inserted by a `require` decl is part of
the interface-with-self generic. When looking through a FacetType for
extended scopes, for each interface, we push the scope with the specific
for the interface-with-self. Then the constant value of the
`SpecificConstant` is correctly modified by the provided self
automatically through applying that specific.
2026-02-19 16:24:07 +00:00
Geoff Romer 3c324e4877 Add category to parameter format, and share some code. (#6730) 2026-02-13 22:20:05 +00:00
Jon Ross-Perkins 74969cab04 Generate non-final Destroy witnesses for symbolics (#6731)
This is related to #6727, but is generally a necessary fix even without
that issue. I'm not adding a specific test of #6727 because it should
also be covered by the tests in #6726.

Assisted-by: Google Antigravity with Gemini 3 Flash
2026-02-13 17:46:50 +00:00
Geoff RomerandRichard Smith e5b05a1fac ExprCategory for guaranteed-in-place initializing expressions (#6623)
The primary change in this PR is to split the `Initializing` expression
category into separate `ReprInitializing` and `InPlaceInitializing`
categories, depending on whether initialization uses the types
initializing representation, or is guaranteed to be in place. It also
rationalizes and documents the SemIR-level semantics of those categories
(including where #5545's "ephemeral entire reference" category will
fit), and introduces two new inst kinds to close gaps exposed in the
process.

Some additional secondary changes:
- Consistently format the storage arguments of initializers with `to`,
regardless of whether initialization is in-place, and document the `to`
notation.
- Rename some inst kinds and functions, and restructure some of the
code, for clarity and consistency with the new documentation.
- Resolve a TODO to handle more category conversions in
`CategoryConverter`, in order to make it easier to reason about category
conversions.

See #6588 and the review history of this PR for background.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2026-02-04 02:27:12 +00:00
Geoff Romer 4329a83e4c Form-aware textual format for return parameters and arguments (#6588)
The key changes are:
- Function output parameters are now prefixed with `out`, and more
consistently formatted as named parameters.
- Function and inst output arguments are now written as part of the inst
form, rather than as one of the inst arguments.

As a drive-by fix, this also changes `Temporary::storage_id` from
`DestInstId` to `InstId`, because it doesn't represent an output
parameter of the `Temporary` inst itself.

See the review of
[#6532](https://github.com/carbon-language/carbon-lang/pull/6532) and
[this Discord
discussion](https://discord.com/channels/655572317891461132/999638000126394370/1458268977020141589)
for additional background.
2026-01-14 23:27:21 +00:00
Richard Smith ead7803d60 Simplify importing of C++ global variables. (#6565)
Remove the unnecessary two-phase creation of variables in C++ import. We
don't need to create a placeholder and overwrite it here, so stop doing
so.

Also, add the patterns to the imports table and don't create a
NameBindingDecl. The NameBindingDecl would never be used for anything.
This matches what we do when importing a Carbon variable, and improves
the formatted SemIR output.
2026-01-09 00:16:27 +00:00
Jon Ross-Perkins c5eba90317 Change Destroy to use a CustomWitness instead of a blanket impl (#6512)
Pursuant to recent decisions on #6124, switch `Destroy` to use a
`CustomWitness` for its implementation. Right now this is manufacturing
no-op implementation functions on each lookup, which obviously isn't
ideal but is intended as a first pass. I'm mostly trying to find the
right balance between updating the approach to reflect new decisions,
while still breaking apart work in a way.

The `CoreInterface` logic is intended to build on `CoreIdentifier`
support. We have a number of additional interfaces that require
specialized logic, and that'll extend pretty far with C++ interop, so it
seemed easiest to have a generic function for it. That's what's
replacing the logic inside C++ interop that was doing string comparisons
(which could have already been moved to `CoreIdentifier`, I just missed
it in my first pass).

This adds `CustomWitness` support because the `Destroy` witnesses can be
imported cross-file. `CustomWitness` was previously only used for C++
types, which don't yet support import, which is why that wasn't
previously an issue. The addition of `query_specific_interface_id` is
similarly needed in order to get correct sorting of witness blocks when
imported.

This PR also removes builtin constraint logic (note this is in a
separate commit to help review; it's not a separate PR because it's
difficult to split apart without tests breaking). This had been made
generic with the expectation that destroy, copy, move, and conversions
would all need related support. Under the new decision, we are not going
to do blanket impls and will instead just manufacture a `CustomWitness`
for everything.

A lot of SemIR fingerprints change, but that's probably because the
addition of `Destroy` on core classes is yielding structural changes.
2025-12-19 18:36:06 +00:00
Jon Ross-Perkins 47e551141f Change the package namespace to use the package name (#6495)
Instead of naming the root namespace `package` (because it's accessed by
the `package` keyword), change it to use the current package name. Note,
buried in the checksum changes,
`toolchain/check/testdata/package_expr/fail_not_found.carbon`:

```
-  // CHECK:STDERR: fail_not_found.carbon:[[@LINE+4]]:16: error: member name `x` not found in `package` [MemberNameNotFoundInInstScope]
+  // CHECK:STDERR: fail_not_found.carbon:[[@LINE+4]]:16: error: member name `x` not found in `Main` [MemberNameNotFoundInInstScope]
```

for:

```
  // CHECK:STDERR:   var y: i32 = package.x;
  // CHECK:STDERR:                ^~~~~~~~~
```

I'll leave it to you if you prefer this; the alternative I see is to
just rename `IsCorePackage` to `IsImportedCorePackage`, and/or change it
to a helper that takes a `Context` and does the right thing with
`parse_tree` (which, I need for `Destroy`-related reasons and was my
default approach).
2025-12-16 01:33:53 +00:00
Richard SmithandJon Ross-Perkins a8eca2ece6 Delay finishing the C++ translation unit until we reach the real EOF. (#6489)
Instead of parsing a complete C++ translation unit and then interacting
with the translation unit further after the fact, delay finishing the
translation unit until we finish the Carbon check phase. This fixes some
issues where we would produce duplicated or incorrect diagnostics at the
end of the C++ translation unit, particularly for unused declarations.
Now we're in control of how we parse the translation unit, also disable
parsing of C++20 modules if the syntax appears within `import Cpp
inline` code.

Keep the same clang parser alive throughout check, and use it instead of
building a new one when parsing macros. This resolves issues where the
translation unit scope was destroyed too early, resulting in unqualified
lookup within macros being unable to find global scope entities.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2025-12-13 00:56:30 +00:00
Richard Smith 154e4012c4 Include the parent scope when fingerprinting an entity name. (#6473)
This is a prerequisite for support for interop with C++ template names.
No behavior change here, except that it sadly changes the fingerprinting
for a lot of tests.
2025-12-08 15:31:13 +00:00
Ivana Ivanovska 4ddff65e8e Add support for macros pointing to a constexpr integer (#6441)
Similarly to the enums, these are for the moment only available when
referenced with a global scope “::”. Only integer constexpr are
available for now.

Part of #6303
2025-12-03 15:31:37 +00:00
Ivana Ivanovska a2821be1be Dump SemIR for all passing macros tests (#6454)
Some of the macros tests were not printing the SemIR. Printing it can
help spot issues (as in PR #6440), so added that now for all passing
tests.

Part of #6303
2025-12-03 12:28:32 +00:00
Ivana Ivanovska 108e39e095 Fix SemIR printout for string literals in macros (#6440)
Added SemIR printout for string literals in macros in the tests. Removed
adding the inst in the imports to make the printout succeed.

Part of #6303
2025-11-28 16:34:25 +00:00
Boaz Brickner bef92cf881 Add CppCompat.ULong32, CppCompat.LongLong64 and CppCompat.ULongLong64 (#6386)
This extends #6364 to allow having:
* `Cpp.unsigned_long` as a distinct type when `unsigned long` is 32
bits.
* `Cpp.long_long` and `Cpp.unsigned_long_long` as distinct types when
`long` and `unsigned long` are 64 bits.

Similarly to #6364, we only support implicit conversions from the
matching literal type (`u32`, `i64` and `u64`).

See #6275 for rationale.

Part of #5263.
2025-11-26 16:51:22 +00:00
Ivana Ivanovska e7b71c031a Add a failing test for user-defined literals in macros (#6431)
These types of literals are not supported at the moment, adding a `todo`
test for it.

Part of #6303
2025-11-26 14:58:39 +00:00
Ivana Ivanovska cf2c66c1b2 Add support for macros evaluating to an enum constant (#6432)
Enum constants in a macro replacement list are recognized only when
prefixed with “::”.
There is a `todo` test to make explicit that this still needs to be
fixed.
When prefixed with a global scope “::”, they are correctly found and
evaluated to a const.


Part of #6303
2025-11-25 17:44:07 +00:00
Ivana Ivanovska 109e39c75c Add support for nullptr literals in macros (#6426)
Adding support for macros that evaluate to nullptr literal.

Demo:

```c++
// macros.h
void foo(int a[2]);
#define MyNullPtr nullptr
```
```c++
// macros.cpp
void foo(int a[2]) {
  if (!a) {
    printf("array a is nullptr\n");
    return;
  }
  printf("a[0] = %d \n", a[0]);
}
```

```c++
// main.carbon

library "Main";

import Cpp library "macros.h";

fn Run() -> i32 {
  Cpp.foo(Cpp.MyNullPtr);
  return 0;
}
```

```
$ clang -c macros.cpp;
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link macros.o main.o \--output=demo_carbon
$ ./demo_carbon
array a is nullptr
```

Part of #6303
2025-11-24 21:03:35 +00:00
Ivana Ivanovska 7be6538aec Add support for character literals in macros (#6419)
Adding support for macros with character literals.

Part of #6303
2025-11-24 13:54:17 +00:00
Ivana Ivanovska 093700b274 Add support for boolean literals in macros (#6418)
Adding support for macros with boolean literals.

Demo:

```c++
// main.carbon

library "Main";

import Core library "io";

import Cpp inline '''
  #define M_TRUE true
''';

fn Run() -> i32 {
  let a: bool = Cpp.M_TRUE;
  if (a) {
    Core.Print(1);
  } else {
    Core.Print(0);
  }
  return 0;
}
```

```
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link main.o \--output=demo_carbon
$ ./demo_carbon
1
```

Part of #6303
2025-11-24 10:40:57 +00:00
Ivana Ivanovska 8866e39085 Add support for string literals in macros (#6408)
Adding support for macros with string literals.

Part of #6303
2025-11-21 12:33:18 +00:00
Ivana Ivanovska 994e6c904d Add support for macros with floating-point literals (#6391)
Adding support for floating-point literals in macros.

Part of #6303
2025-11-20 12:49:43 +00:00
Ivana Ivanovska b68b6ae1e7 Add support for more complex object-like macros (#6338)
Uses `clang::Parser::ParseConstantExpression()` to parse the macro
replacement tokens, added as a token stream to the preprocessor. This
extends the support from simple object-like macros with a single
replacement token, to multiple tokens like unary operators, binary
operators, casting, nested macros etc.
The support is still limited to macros that are evaluated to an integer
constant. More types to be added as a follow-up.

Part of #6303
2025-11-12 17:06:39 +00:00
Ivana Ivanovska 3b0dad9dd5 Add support for simple object-like macros (#6326)
Adds support for object-like macros with a single replacement
numeric-literal kind token. Only macros that evaluate to an integer
constant are supported for now. When detected at name lookup, they are
imported as a constant integer value in Carbon.

Demo:

```c++
// --- macros.h

#define CONFIG_VALUE 2
```

``` c++
// main.carbon
library "Main";

import Cpp library "macros.h";
import Core library "io";

fn Run() {
    let a: i32 = Cpp.CONFIG_VALUE;
    Core.Print(a);
}
```

```c++
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link main.o \--output=demo_carbon
$ ./demo_carbon
2
```

Part of #6303
2025-11-11 11:24:20 +00:00