Skip to content

[WIP] pac ty disc#158567

Draft
jchlanda wants to merge 22 commits into
rust-lang:mainfrom
jchlanda:jakub/pac_ty_disc
Draft

[WIP] pac ty disc#158567
jchlanda wants to merge 22 commits into
rust-lang:mainfrom
jchlanda:jakub/pac_ty_disc

Conversation

@jchlanda

@jchlanda jchlanda commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

@rustbot rustbot added A-compiletest Area: The compiletest test runner A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-run-make Area: port run-make Makefiles to rmake.rs A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 29, 2026
@rust-log-analyzer

This comment has been minimized.

cv: Scalar,
layout: abi::Scalar,
llty: Self::Type,
schema: Option<PointerAuthSchema>,

@bjorn3 bjorn3 Jun 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This function should have access to the Session already through self.tcx.sess.

View changes since the review

fn get_fn_addr(
&self,
instance: Instance<'tcx>,
pointer_auth_schema: Option<PointerAuthSchema>,

@bjorn3 bjorn3 Jun 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch from 2d3b257 to f5fa52a Compare June 30, 2026 11:57
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch from d6ce62a to 755b0b7 Compare June 30, 2026 15:08
@rust-log-analyzer

This comment has been minimized.

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch from 755b0b7 to c3fd17f Compare June 30, 2026 15:23
@rust-log-analyzer

This comment has been minimized.

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch from c3fd17f to 8b6e351 Compare July 1, 2026 06:23
@rust-log-analyzer

This comment has been minimized.

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch from 8b6e351 to 5b8ba19 Compare July 1, 2026 07:24
@rust-log-analyzer

This comment has been minimized.

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch 2 times, most recently from 4301abb to 9545275 Compare July 1, 2026 15:06
_new_key: u32,
_new_discriminator: u64,
) -> Self::Value {
bug!("Resigning of pointers not implemented");

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a test for this (ensuring that it's not supported) or is it infeasible to reach this path?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is not a user facing function, so the only way it could be triggered is if we wrote incorrect code within the compiler itself, hence the bug!. The relevant call chain for this function starts inside codegen_transmute and is guarded by a function pointer support check.

// Direct function pointer.
if let Some(input) = build_fn_ptr_type_discriminator_input(tcx, ty) {
// Only support about extern "C".
if matches!(input.abi(), ExternAbi::C { .. } | ExternAbi::System { .. }) {

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you please explain what ExternAbi::System stands for? I would appreciate if you also refer me to the corresponding test

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

System means the platform’s default system ABI for foreign functions, whatever the platform uses by default for system libraries. I was told in one of the PRs that for all practical cases they should match. Hence the inclusion of both.

The docs.


let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx);
let schema = if cx.sess().pointer_authentication() {
let mut schema = if cx.sess().pointer_authentication() {

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why do we need mut here?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because we then retrieve the discriminator and store it in the schema.

operand: OperandRef<'tcx, Bx::Value>,
cast: TyAndLayout<'tcx>,
) -> OperandValue<Bx::Value> {
debug!(

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to be included in the PR or is it a development-stage-only debug printing?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Intended. This serves the same purpose as LLVM_DEBUG(dbgs()...) in llvm.

pub mod middle;
pub mod mir;
pub mod mono;
pub mod ptrauth;

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There are no other changes in the file - so, is this actually needed?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes.
This says something along the lines of: "There is a module called ptrauth, and it should be included in the library’s public interface.If you go toptrauthdirectory you'll see themod.rs` which in turns tells us what is publicly exported from the module.
So the flow of visibility is: lib.rs -> ptrauth -> discriminator / llvm_siphash (where the last two are controlled by https://github.com/jchlanda/rust/blob/9545275cededc9e307c61ef9d640d256ae59eab3/compiler/rustc_middle/src/ptrauth/mod.rs#L5)

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This deleted test should also be removed from the markdown documentation file which includes it in test coverage

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeap, need to work on that file a bit more.

Comment thread compiler/rustc_public/src/abi.rs Outdated
pub c_variadic: bool,

/// Computed type discriminator for pointer authentication purpose.
pub type_discriminator: u64,

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's probably worth prefixing ptrauth-related things with smth like ptrauth_ in such "generic" places (which are not ptrauth-specific). A comment here contains explanation, but when constructing struct objects we have type_discriminator: XXX which non-ptrauth-aware reader would not easily understand

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK, renamed to ptrauth_type_discriminator.

fixed_count: self.fixed_count,
conv: self.conv.stable(tables, cx),
c_variadic: self.c_variadic,
type_discriminator: 0,

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you please explain why we have 0 here and are there any cases when non-zero discriminator would be needed here?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think you are on to something. There are 3 structs with the same name (FnAbi): public, callconv and gcc. I wonder if we could get away with only extending callconv.

I'll get back to you on this one.

@jchlanda jchlanda Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeap, the only one we need is the callconv, refactored.

Comment thread compiler/rustc_codegen_gcc/src/int.rs Outdated
fixed_count: 3,
conv: CanonAbi::C,
can_unwind: false,
type_discriminator: 0,

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Probably deserves a comment that it's just a placeholder value since gcc backend is not supported for pointer authentication (if I got your reasoning right)

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same as above.

fn_ptr_discriminators.as_ref().and_then(|m| m.get(Size::from_bytes(offset as u64)));

if let (Some(schema), Some(discr)) = (schema.as_mut(), discr) {
schema.constant_discriminator = discr as u16;

@kovdan01 kovdan01 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this override discriminator value for init/fini if fn ptr type discr is enabled? If so, it looks diverging from how clang handles this - and my understanding is that it actually makes sense to have hard-coded separate discriminator for init/fini since these are (a) known type (b) we need to know discriminator in dynamic loader.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Are you saying that discriminator for init/fini must always be 0xd9d4, regardless if fn ptr type discrimination is on or not? If so, than we've got a bug, as it would be indeed overridden. Let me see what clang does and come back to you.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right, we do have a bug. Clang does:

  • no init/fini, no fn ptr ty disc:
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 90, ptr @foo, ptr null }]
  • init/fini, no fn ptr ty disc:
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 90, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }]
  • no init/fini, fn ptr ty disc:
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 90, ptr @foo, ptr null }]
  • init/fini, fn ptr ty disc:
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 90, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), ptr null }]

I'll have to fix that in rust.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK, fixed now, extended the test with O{0|3}_PAUTH-INIT-FINI-FN-TY-DISC.

@rust-log-analyzer

This comment has been minimized.

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch 2 times, most recently from 697c5ce to eef2752 Compare July 3, 2026 14:44
@rust-log-analyzer

This comment has been minimized.

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch from fb93d1f to bff0a2e Compare July 14, 2026 09:29
@rust-log-analyzer

This comment has been minimized.

}

// Canonicalize `Option<fn ptr>` to `fn ptr`. This is so that we can express C's null ptr argument.
// Please see pauth-fn-ptr-type-discrimination-null-arg.rs test for an example.

@kovdan01 kovdan01 Jul 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was unable to find this test. Was it accidentally lost or maybe renamed?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My bad, got split to different tests:

  • pauth-fn-ptr-type-discrimination-option-callback.rs,
  • pauth-fn-ptr-type-discrimination-option-return.rs,
  • pauth-fn-ptr-type-discrimination-option.rs

}
}

// Canonicalize `Option<fn ptr>` to `fn ptr`. This is so that we can express C's null ptr argument.

@kovdan01 kovdan01 Jul 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it deliberate choice that we only care about function pointers in this functions? What about data pointers which could also be nullptr - are they represented w/o Option wrapper and such unwrapping is not needed therefore, or they are handled somehow somewhere else, or maybe I'm just missing smth?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In all honesty I did not think about Rust nullable data pointer representation. Let me research it a bit and come back to you.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It was an omission, I made it follow function pointer logic, so we will now recover underlying pointer type from Option<* T>. Expanded the test (pauth-fn-ptr-type-discrimination-option-callback.rs) as well.

Done in: 697a1f4

Comment on lines +222 to +235
let x = (A(f), NotFn(999));
// DISC: [[Y:%.*]] = alloca [16 x i8]
// DISC: store ptr ptrauth (ptr @{{.*}}f, i32 0, i64 18983), ptr [[Y]]
// NO_DISC: [[Y:%.*]] = alloca [16 x i8]
// NO_DISC: store ptr ptrauth (ptr @{{.*}}f, i32 0), ptr [[Y]]
let y: (B, AlsoNotFn) = unsafe { mem::transmute(x) };

unsafe {
ptr::read_volatile(&y);
// DISC: [[Y_LOAD:%.*]] = load ptr, ptr [[Y]]
// DISC: call void [[Y_LOAD]](i32 42) {{.*}} [ "ptrauth"(i32 0, i64 2712) ]
// NO_DISC: [[Y_LOAD:%.*]] = load ptr, ptr [[Y]]
// NO_DISC: call void [[Y_LOAD]](i32 42) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
(y.0.0)(42);

@kovdan01 kovdan01 Jul 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be missing smth, but currently this reads as:

  1. We store function pointer of type void() to a struct nested into a tuple.
  2. We transmute that to another tuple so the struct now carries void(i32) instead of void(). BUT: the stored function pointer is still signed with discriminator 18983 standing for void() if I'm not mistaken
  3. During function call, we do authentication with discriminator 2712 standing for void(i32) if I'm not mistaken

So, this smells as auth failure (was it intended?)

And also: should the transmute-handling logic do the resigning (including nested members) so y already carries the pointer signed with 2712 (so transmute first does auth of value from x with discr 18983 and then resign with 2712)?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You are right, it will result in auth failure. However, I think in this particular case it is desired. My reading of this is that the compiler sees it as a type pun through a pointer cast on the tuple, not a function pointer cast and so does not try to apply the discriminator domain transition.

This is exactly the same behaviour that clang displays. Consider this C sample:

#include <stdint.h>

typedef void (*fn0)(void);
typedef void (*fn1)(int);

void f(void);
void g(int);

typedef struct {
  fn0 f;
} A;

typedef struct {
  fn1 f;
} B;

typedef struct {
  uint64_t x;
} NotFn;

typedef struct {
  uint64_t x;
} AlsoNotFn;

typedef struct {
  A a;
  NotFn n;
} TupleA;

typedef struct {
  B b;
  AlsoNotFn n;
} TupleB;

__attribute__((noinline)) void test_6_mixed_layout_cast(void) {
  TupleA x;
  x.a.f = f;
  x.n.x = 999;

  TupleB y = *(TupleB *)&x;
  volatile TupleB tmp = y;

  y.b.f(42);
}

It compiles to essentially the same IR:

define dso_local void @test_6_mixed_layout_cast() local_unnamed_addr #0 {
  %1 = alloca ptr, align 8
  %2 = alloca i64, align 8
  %3 = alloca ptr, align 8
  %4 = alloca i64, align 8
  call void @llvm.lifetime.start.p0(ptr nonnull %1)
  call void @llvm.lifetime.start.p0(ptr nonnull %2)
  store ptr ptrauth (ptr @f, i32 0, i64 18983), ptr %1, align 8, !tbaa !13
  store i64 999, ptr %2, align 8, !tbaa !15
  call void @llvm.lifetime.start.p0(ptr nonnull %3)
  call void @llvm.lifetime.start.p0(ptr nonnull %4)
  %5 = load volatile ptr, ptr %1, align 8, !tbaa !13
  store volatile ptr %5, ptr %3, align 8, !tbaa !13
  %6 = load volatile i64, ptr %2, align 8, !tbaa !15
  store volatile i64 %6, ptr %4, align 8, !tbaa !15
  tail call void %5(i32 noundef 42) #3 [ "ptrauth"(i32 0, i64 2712) ]
  call void @llvm.lifetime.end.p0(ptr nonnull %3)
  call void @llvm.lifetime.end.p0(ptr nonnull %4)
  call void @llvm.lifetime.end.p0(ptr nonnull %1)
  call void @llvm.lifetime.end.p0(ptr nonnull %2)
  ret void
}

Comment on lines +314 to +317
// Lowering (Rust Ty -> ClangDiscTy)
fn is_representing_c_complex(fields: &[Ty<'_>]) -> bool {
fields.len() == 2 && fields[0] == fields[1] && is_complex_compatible_float(fields[0])
}

@kovdan01 kovdan01 Jul 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm wondering if we actually need that. My understanding is that if rust does not have native _Complex type, it's not very likely that it appears in real-world interop with C. And if one needs that - they might adopt different strategies, including this solution involving tuples, but not limited to it.

So my concern is that we are "inventing" smth for a use case which (a) is rare (b) might be handled differently by different parties.

Sure, our "type mangling" logic would not be full-mirror of Clang's if we drop _Complex support, and if we do, it should be properly documented. I just want to raise attention to this decision point - whether we really want this new assumption about tuple of two floats being introduced or maybe just do not support _Complex explicitly and let downstream users which need that (if any) implement this the way they want given that representations might vary.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is a valid point. My reasoning was to follow explicitly clang's behaviour with maximum alignment to what can and can not be expressed. I don't have a preference, nor the knowledge of how end users would end up interacting with the types. Perhaps this one is for an offline (off the PR, in person) discussion, it will be easy to remove the support in future (follow up PR)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've removed it now, after thinking about it for a wee while forcing users to a particular representation for a non-native type felt like a bad idea. I've updated the code and added explicit mention of the decision in here: d9f0aee

/// Indicates if an unwind may happen across a call to this function.
pub can_unwind: bool,
/// Computed type discriminator for pointer authentication purpose.
pub ptrauth_type_discriminator: u64,

@jchlanda jchlanda Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@kovdan01 I'll answer you comments re FnAbi here, to keep things in one place.

So this boils down to two things: can we do it and should we do it?

Can we do it - yes, I had a go and it is pretty straight forward, please see the implementation.

As to the latter, it's a bit more complicated. The way I understand the pipeline is as follows:

  • discriminator is a property of the source-level function type, much more aligned withFnSig
  • whereas FnAbi is a property of the lowered calling convention, how arguments to a function should be handled.

Those are intentionally different abstractions.

If FnAbi is used, we would forever have to rely on ArgAbi, which is not designed to preserve source-level type information. Although ArgAbi::layout.ty currently exists, it is only used in a very limited way (primarily for an "equal enough" comparison for vec types), while most uses of layout revolve around things like size of the type and it's layout, not the type logic per se. To me it suggests that the presence of the original type is incidental rather than a stable guarantee.

More importantly, the FnAbi documentation explicitly states that it may not match the original MIR function signature. Compiler transformations such as #[track_caller] and GPU offload can introduce (implicit) arguments that would not be present in a corresponding FnSig. While fixed_count distinguishes fixed and variadic arguments, it does not provide a way to recover the original source-level parameter list in the presence of these inserted arguments, or at least the comments does not give a strong enough guarantee that it would.

As to CanonAbi I think matching against CanonAbi::C should be good enough for all practical uses. And should we ever discover it is not, we could use the abi map hook that guards the conversion of ExternAbi to CanonAbi, so we would be able to control it fully.

To sum up, using FnAbi seems like layering violation, we would be trying to reconstruct information that does not belong to the llvm codegen stage from bits of data that does exist, but is not meant for that purpose.

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jchlanda Thanks for the research and the prototype! I agree with your point - let's stick with current approach and just have the alternative just in case it's considered a better solution during proper review conducted by actual rust maintainers

@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch 2 times, most recently from 697a1f4 to c224581 Compare July 16, 2026 14:44
jchlanda added 22 commits July 17, 2026 06:55
Alongside Rust implementation of LLVM's SipHash-2-4.
This is only to be used when emitting an operand bundle, which might not
have access to an Instance of the function, but for which FnAbi is
guaranteed to be correct.
Start moving away from global schema, by cloning it into users.
Helpers for fn ptr type discrimination status and value of the key.
This is a move away from a blind bitcast between the types. Now, when
dealing with function pointers, transmute will detect a domain change
(change of fn ptr type) and issue resigning.
As the libc changes was merged in to the main we do not need to patch
it. cc-rs still needs to be patched as compiler/rustc_llvm/Cargo.toml
still pins to an old version: cc = "=1.2.16"
@jchlanda
jchlanda force-pushed the jakub/pac_ty_disc branch from c224581 to cff5996 Compare July 17, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-compiletest Area: The compiletest test runner A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-run-make Area: port run-make Makefiles to rmake.rs A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants