├── bootstrap ├── .gitignore ├── Cargo.toml ├── src │ ├── clean.rs │ ├── rustc.rs │ ├── fmt.rs │ ├── manifest.rs │ ├── main.rs │ └── test.rs └── Cargo.lock ├── crates ├── .gitignore ├── rustc_codegen_c │ ├── messages.ftl │ ├── src │ │ ├── context │ │ │ ├── type_membership.rs │ │ │ ├── asm.rs │ │ │ ├── static.rs │ │ │ ├── pre_define.rs │ │ │ ├── misc.rs │ │ │ ├── layout_type.rs │ │ │ ├── base_type.rs │ │ │ ├── debug_info.rs │ │ │ └── const.rs │ │ ├── builder │ │ │ ├── static.rs │ │ │ ├── coverage_info.rs │ │ │ ├── asm.rs │ │ │ ├── debug_info.rs │ │ │ ├── abi.rs │ │ │ └── intrinsic_call.rs │ │ ├── helper.h │ │ ├── archive.rs │ │ ├── base.rs │ │ ├── write.rs │ │ ├── context.rs │ │ ├── lib.rs │ │ └── builder.rs │ └── Cargo.toml ├── rustc_codegen_c_ast │ ├── tests │ │ ├── blessed │ │ │ ├── test_expr_raw.out │ │ │ ├── test_value_func.out │ │ │ ├── test_expr_binary.out │ │ │ ├── test_expr_call.out │ │ │ ├── test_expr_member.out │ │ │ ├── test_value_local.out │ │ │ ├── test_value_scalar.out │ │ │ ├── test_expr_cast.out │ │ │ ├── test_stmt_expr.out │ │ │ ├── test_decl_var.out │ │ │ ├── test_stmt_block.out │ │ │ ├── test_stmt_decl.out │ │ │ ├── test_stmt_if.out │ │ │ ├── test_expr_complex.out │ │ │ ├── test_function.out │ │ │ └── test_module.out │ │ ├── decl.rs │ │ ├── func.rs │ │ ├── module.rs │ │ ├── blessed_test │ │ │ └── mod.rs │ │ ├── stmt.rs │ │ └── expr.rs │ ├── Cargo.toml │ └── src │ │ ├── arena.rs │ │ ├── decl.rs │ │ ├── lib.rs │ │ ├── module.rs │ │ ├── stmt.rs │ │ ├── func.rs │ │ ├── pretty.rs │ │ ├── expr.rs │ │ └── ty.rs ├── Cargo.toml └── Cargo.lock ├── .gitignore ├── compile_flags.txt ├── rust_runtime ├── rust_runtime.c └── rust_runtime.h ├── .rustfmt.toml ├── rust-toolchain.toml ├── y ├── .vscode └── settings.json ├── examples └── basic_math.rs ├── tests ├── bless │ ├── basic_math.rs │ └── basic_math.c ├── codegen │ ├── ret_value.rs │ ├── filename.rs │ ├── func_call.rs │ └── params_count.rs └── auxiliary │ └── mini_core.rs ├── README.md ├── LICENSE-MIT ├── .github └── workflows │ └── main.yaml └── LICENSE-APACHE /bootstrap/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /crates/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | rustc-ice-* 3 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/messages.ftl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /compile_flags.txt: -------------------------------------------------------------------------------- 1 | --std=c99 2 | -I 3 | rust_runtime 4 | -------------------------------------------------------------------------------- /rust_runtime/rust_runtime.c: -------------------------------------------------------------------------------- 1 | #include "rust_runtime.h" 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_expr_raw.out: -------------------------------------------------------------------------------- 1 | 42 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_value_func.out: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_expr_binary.out: -------------------------------------------------------------------------------- 1 | (1 + 2) 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_expr_call.out: -------------------------------------------------------------------------------- 1 | foo(1, 2) 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_expr_member.out: -------------------------------------------------------------------------------- 1 | _42.foo 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_value_local.out: -------------------------------------------------------------------------------- 1 | _42 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_value_scalar.out: -------------------------------------------------------------------------------- 1 | 42 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_expr_cast.out: -------------------------------------------------------------------------------- 1 | (int32_t) 42 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_stmt_expr.out: -------------------------------------------------------------------------------- 1 | foo(1, 2); 2 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | use_small_heuristics = "Max" 2 | imports_granularity = "Module" 3 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_decl_var.out: -------------------------------------------------------------------------------- 1 | int32_t _42 = 42; 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_stmt_block.out: -------------------------------------------------------------------------------- 1 | { foo(1, 2); } 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_stmt_decl.out: -------------------------------------------------------------------------------- 1 | int32_t _42 = 42; 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_stmt_if.out: -------------------------------------------------------------------------------- 1 | return foo(1, 2); 2 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_expr_complex.out: -------------------------------------------------------------------------------- 1 | foo(1, (int32_t) (1 + 2)).bar 2 | -------------------------------------------------------------------------------- /rust_runtime/rust_runtime.h: -------------------------------------------------------------------------------- 1 | #ifndef RUST_RUNTIME_H 2 | #define RUST_RUNTIME_H 3 | 4 | #endif 5 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2024-07-01" 3 | components = ["rust-src", "rustc-dev", "llvm-tools-preview"] 4 | -------------------------------------------------------------------------------- /y: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo "[BUILD] build system" 1>&2 5 | exec cargo run --manifest-path bootstrap/Cargo.toml -- "$@" 6 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_function.out: -------------------------------------------------------------------------------- 1 | int32_t foo(int32_t _0) 2 | { 3 | int32_t _1; 4 | (_1 = 1); 5 | return _1; 6 | } 7 | -------------------------------------------------------------------------------- /crates/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["rustc_codegen_c", "rustc_codegen_c_ast"] 4 | 5 | [workspace.package] 6 | version = "0.1.0" 7 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/type_membership.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_ssa::traits::TypeMembershipMethods; 2 | 3 | use crate::context::CodegenCx; 4 | 5 | impl<'tcx, 'mx> TypeMembershipMethods<'tcx> for CodegenCx<'tcx, 'mx> {} 6 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed/test_module.out: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // blessed test 4 | 5 | int32_t _42; 6 | int32_t foo(int32_t _0); 7 | 8 | int32_t foo(int32_t _0) 9 | { 10 | int32_t _1; 11 | (_1 = 1); 12 | return _1; 13 | } 14 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustc_codegen_c_ast" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | [dependencies] 7 | 8 | # This package uses rustc crates. 9 | [package.metadata.rust-analyzer] 10 | rustc_private = true 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.rustc.source": "discover", 3 | "rust-analyzer.workspace.symbol.search.scope": "workspace_and_dependencies", 4 | "rust-analyzer.linkedProjects": [ 5 | "./crates/Cargo.toml", 6 | "./bootstrap/Cargo.toml", 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /examples/basic_math.rs: -------------------------------------------------------------------------------- 1 | //@ aux-build:mini_core.rs 2 | 3 | #![feature(no_core)] 4 | #![no_core] 5 | #![no_main] 6 | 7 | extern crate mini_core; 8 | 9 | #[no_mangle] 10 | pub fn main() -> i32 { 11 | 0 12 | } 13 | 14 | #[no_mangle] 15 | pub fn foo(x: u8, _y: u8) -> i64 { 16 | x as i64 17 | } 18 | -------------------------------------------------------------------------------- /crates/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "rustc_codegen_c" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "rustc_codegen_c_ast", 10 | ] 11 | 12 | [[package]] 13 | name = "rustc_codegen_c_ast" 14 | version = "0.1.0" 15 | -------------------------------------------------------------------------------- /bootstrap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "y" 3 | edition = "2021" 4 | publish = false 5 | 6 | [dependencies] 7 | anstream = "0.6.14" 8 | clap = { version = "4.5.9", features = ["derive"] } 9 | color-print = "0.3.6" 10 | env_logger = "0.11.5" 11 | glob = "0.3.1" 12 | log = "0.4.22" 13 | regex = "1.11.1" 14 | similar = "2.6.0" 15 | which = "6.0.1" 16 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/builder/static.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_ssa::traits::StaticBuilderMethods; 2 | use rustc_hir::def_id::DefId; 3 | 4 | use crate::builder::Builder; 5 | 6 | impl<'tcx, 'mx> StaticBuilderMethods for Builder<'_, 'tcx, 'mx> { 7 | fn get_static(&mut self, def_id: DefId) -> Self::Value { 8 | todo!() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/bless/basic_math.rs: -------------------------------------------------------------------------------- 1 | //@ aux-build:mini_core.rs 2 | //@ run-pass 3 | //@ exit-code: 0 4 | 5 | #![feature(no_core)] 6 | #![no_core] 7 | #![no_main] 8 | 9 | extern crate mini_core; 10 | 11 | #[no_mangle] 12 | pub fn main() -> i32 { 13 | 0 14 | } 15 | 16 | #[no_mangle] 17 | pub fn foo(x: u8, _y: u16, _z: u32) -> i64 { 18 | x as i64 19 | } 20 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustc_codegen_c" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | [lib] 7 | crate-type = ["dylib"] 8 | 9 | [dependencies] 10 | rustc_codegen_c_ast = { path = "../rustc_codegen_c_ast" } 11 | 12 | # This package uses rustc crates. 13 | [package.metadata.rust-analyzer] 14 | rustc_private = true 15 | -------------------------------------------------------------------------------- /tests/codegen/ret_value.rs: -------------------------------------------------------------------------------- 1 | //! Test that we can return a value from a function 2 | 3 | //@ aux-build:mini_core.rs 4 | //@ run-pass 5 | //@ exit-code: 42 6 | 7 | #![feature(no_core)] 8 | #![no_core] 9 | #![no_main] 10 | 11 | extern crate mini_core; 12 | 13 | // CHECK-LABEL: main 14 | // CHECK: return 42; 15 | #[no_mangle] 16 | pub fn main() -> i32 { 17 | 42 18 | } 19 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/builder/coverage_info.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods; 2 | 3 | use crate::builder::Builder; 4 | 5 | impl<'tcx, 'mx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> { 6 | fn add_coverage( 7 | &mut self, 8 | instance: rustc_middle::ty::Instance<'tcx>, 9 | kind: &rustc_middle::mir::coverage::CoverageKind, 10 | ) { 11 | todo!() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/arena.rs: -------------------------------------------------------------------------------- 1 | //! This module defines the memory arena for C AST nodes. 2 | 3 | use crate::decl::CDeclKind; 4 | use crate::expr::CExprKind; 5 | use crate::func::CFuncKind; 6 | use crate::stmt::CStmtKind; 7 | use crate::ty::CTyKind; 8 | 9 | rustc_arena::declare_arena!([ 10 | [] decl: CDeclKind<'tcx>, 11 | [] expr: CExprKind<'tcx>, 12 | [] func: CFuncKind<'tcx>, 13 | [] stmt: CStmtKind<'tcx>, 14 | [] ty: CTyKind<'tcx>, 15 | ]); 16 | -------------------------------------------------------------------------------- /tests/codegen/filename.rs: -------------------------------------------------------------------------------- 1 | //! Test that the generated code has the filename and function name in it 2 | 3 | //@ aux-build:mini_core.rs 4 | //@ run-pass 5 | //@ exit-code: 0 6 | 7 | // CHECK: filename 8 | 9 | #![feature(no_core)] 10 | #![no_core] 11 | #![no_main] 12 | 13 | extern crate mini_core; 14 | 15 | // CHECK: function_name 16 | #[no_mangle] 17 | pub fn function_name() -> i32 { 18 | 0 19 | } 20 | 21 | #[no_mangle] 22 | pub fn main() -> i32 { 23 | 0 24 | } 25 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/asm.rs: -------------------------------------------------------------------------------- 1 | use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; 2 | use rustc_codegen_ssa::traits::{AsmMethods, GlobalAsmOperandRef}; 3 | 4 | use crate::context::CodegenCx; 5 | 6 | impl<'tcx, 'mx> AsmMethods<'tcx> for CodegenCx<'tcx, 'mx> { 7 | fn codegen_global_asm( 8 | &self, 9 | template: &[InlineAsmTemplatePiece], 10 | operands: &[GlobalAsmOperandRef<'tcx>], 11 | options: InlineAsmOptions, 12 | line_spans: &[rustc_span::Span], 13 | ) { 14 | todo!() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/helper.h: -------------------------------------------------------------------------------- 1 | /* Some helper macros for the generated code */ 2 | 3 | /** Casts an unsigned integer to a signed integer of the same size. 4 | * This is used to avoid UB when do integer casting in Rust. 5 | * 6 | * The parameter `u` is the unsigned type, `s` is the signed type, 7 | * `v` is the value to cast, and `m` is the maximum value of the signed type.\ 8 | * 9 | * example: `__rust_utos(uint32_t, int32_t, x, INT32_MAX)` 10 | */ 11 | #define __rust_utos(u, s, v, m) \ 12 | ((v) <= (m) ? ((s)v) : ((s)((u)(v) - (u)(m) - 1))) 13 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/decl.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | use blessed_test::*; 4 | use rustc_codegen_c_ast::expr::CValue; 5 | use rustc_type_ir::IntTy; 6 | 7 | extern crate rustc_driver; 8 | extern crate rustc_type_ir; 9 | mod blessed_test; 10 | 11 | #[test] 12 | fn test_decl_var() { 13 | printer_test("test_decl_var", |ctx| { 14 | let ty = ctx.get_int_type(IntTy::I32); 15 | let name = CValue::Local(42); 16 | let value = ctx.value(CValue::Scalar(42)); 17 | Box::new(ctx.var(name, ty, Some(value))) 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /tests/codegen/func_call.rs: -------------------------------------------------------------------------------- 1 | //! Test that the generated code correctly handles function calls 2 | 3 | //@ aux-build:mini_core.rs 4 | //@ run-pass 5 | //@ exit-code: 1 6 | 7 | // CHECK-LABEL: single 8 | // CHECK: (int32_t {{[[:alnum:]_]*}}) 9 | 10 | #![feature(no_core)] 11 | #![no_core] 12 | #![no_main] 13 | 14 | extern crate mini_core; 15 | 16 | #[no_mangle] 17 | pub fn single(a: i32) -> i32 { 18 | a 19 | } 20 | 21 | // CHECK-LABEL: main 22 | // CHECK: int32_t {{[[:alnum:]_]*}} = single(1); 23 | // CHECK: return {{[[:alnum:]_]*}}; 24 | #[no_mangle] 25 | pub fn main() -> i32 { 26 | single(1) 27 | } 28 | -------------------------------------------------------------------------------- /tests/codegen/params_count.rs: -------------------------------------------------------------------------------- 1 | //! Test that the generated code has the right number of parameters 2 | 3 | //@ aux-build:mini_core.rs 4 | //@ run-pass 5 | //@ exit-code: 0 6 | 7 | #![feature(no_core)] 8 | #![no_core] 9 | #![no_main] 10 | 11 | extern crate mini_core; 12 | 13 | // CHECK-LABEL: foo 14 | // CHECK-LABEL: main 15 | 16 | // expect three int params 17 | // CHECK-LABEL: foo 18 | // CHECK: (int32_t {{[[:alnum:]_]*}}, int32_t {{[[:alnum:]_]*}}, int32_t {{[[:alnum:]_]*}}) 19 | // CHECK: return 0; 20 | #[no_mangle] 21 | pub fn foo(_x: i32, _y: i32, _z: i32) -> i32 { 22 | 0 23 | } 24 | 25 | #[no_mangle] 26 | pub fn main() -> i32 { 27 | 0 28 | } 29 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/static.rs: -------------------------------------------------------------------------------- 1 | use rustc_abi::Align; 2 | use rustc_codegen_ssa::traits::StaticMethods; 3 | use rustc_hir::def_id::DefId; 4 | 5 | use crate::context::CodegenCx; 6 | 7 | impl<'tcx, 'mx> StaticMethods for CodegenCx<'tcx, 'mx> { 8 | fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value { 9 | todo!() 10 | } 11 | 12 | fn codegen_static(&self, def_id: DefId) { 13 | todo!() 14 | } 15 | 16 | fn add_used_global(&self, global: Self::Value) { 17 | todo!() 18 | } 19 | 20 | fn add_compiler_used_global(&self, global: Self::Value) { 21 | todo!() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/builder/asm.rs: -------------------------------------------------------------------------------- 1 | use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; 2 | use rustc_codegen_ssa::traits::{AsmBuilderMethods, InlineAsmOperandRef}; 3 | use rustc_middle::ty::Instance; 4 | 5 | use crate::builder::Builder; 6 | 7 | impl<'tcx, 'mx> AsmBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> { 8 | fn codegen_inline_asm( 9 | &mut self, 10 | template: &[InlineAsmTemplatePiece], 11 | operands: &[InlineAsmOperandRef<'tcx, Self>], 12 | options: InlineAsmOptions, 13 | line_spans: &[rustc_span::Span], 14 | instance: Instance<'_>, 15 | dest: Option, 16 | catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>, 17 | ) { 18 | todo!() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bootstrap/src/clean.rs: -------------------------------------------------------------------------------- 1 | use clap::Args; 2 | 3 | use crate::manifest::Manifest; 4 | use crate::Run; 5 | 6 | /// Clean the build directory 7 | #[derive(Args, Debug)] 8 | pub struct CleanCommand { 9 | #[arg(short, long)] 10 | pub verbose: bool, 11 | } 12 | 13 | impl Run for CleanCommand { 14 | const STEP_DISPLAY_NAME: &'static str = "clean"; 15 | 16 | fn run(&self, manifest: &Manifest) { 17 | self.log_action_start("cleaning", "build directory"); 18 | let _ = std::fs::remove_dir_all("crates/target"); 19 | self.log_action_context("rm", "crates/target"); 20 | let _ = std::fs::remove_dir_all(&manifest.out_dir); 21 | self.log_action_context("rm", &manifest.out_dir.display()); 22 | } 23 | 24 | fn verbose(&self) -> bool { 25 | self.verbose 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rustc_codegen_c 2 | 3 | C based backend for rustc 4 | 5 | [![CI](https://github.com/rust-lang/rustc_codegen_c/actions/workflows/ci.yml/badge.svg)](https://github.com/rust-lang/rustc_codegen_c/actions/workflows/ci.yml) 6 | 7 | This a C codegen backend for rustc, which lowers Rust MIR to C code and compiles 8 | it with a C compiler. 9 | 10 | This code is still highly experimental and not ready for production use. 11 | 12 | ## Try it 13 | 14 | In the root directory of the project, run the following command: 15 | 16 | ```bash 17 | ./y rustc examples/basic_math.rs 18 | ./build/basic_math 19 | ``` 20 | 21 | The usage of `./y` can be viewed from `./y help`. 22 | 23 | Note: only Linux is supported at the moment. `clang` is required to compile C code, 24 | and LLVM FileCheck is required to test the codegen. 25 | 26 | ## License 27 | 28 | This project is licensed under a dual license: MIT or Apache 2.0. 29 | -------------------------------------------------------------------------------- /tests/bless/basic_math.c: -------------------------------------------------------------------------------- 1 | // file: basic_math.3cfc46df15d2d47-cgu.0.c 2 | #include 3 | 4 | /* Some helper macros for the generated code */ 5 | 6 | /** Casts an unsigned integer to a signed integer of the same size. 7 | * This is used to avoid UB when do integer casting in Rust. 8 | * 9 | * The parameter `u` is the unsigned type, `s` is the signed type, 10 | * `v` is the value to cast, and `m` is the maximum value of the signed type.\ 11 | * 12 | * example: `__rust_utos(uint32_t, int32_t, x, INT32_MAX)` 13 | */ 14 | #define __rust_utos(u, s, v, m) \ 15 | ((v) <= (m) ? ((s)v) : ((s)((u)(v) - (u)(m) - 1))) 16 | 17 | int32_t main(); 18 | int64_t foo(uint8_t _0, uint16_t _1, uint32_t _2); 19 | 20 | int32_t main() { return 0; } 21 | 22 | int64_t foo(uint8_t _0, uint16_t _1, uint32_t _2) 23 | { 24 | int64_t _3 = __rust_utos(uint64_t, int64_t, (int64_t) _0, INT64_MAX); 25 | return _3; 26 | } 27 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/archive.rs: -------------------------------------------------------------------------------- 1 | //! from rustc_codegen_cranelift 2 | 3 | use std::path::{Path, PathBuf}; 4 | 5 | use rustc_codegen_ssa::back::archive::{ 6 | get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, 7 | }; 8 | use rustc_session::Session; 9 | 10 | pub(crate) struct ArArchiveBuilderBuilder; 11 | 12 | impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { 13 | fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { 14 | Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) 15 | } 16 | 17 | fn create_dll_import_lib( 18 | &self, 19 | _sess: &Session, 20 | _lib_name: &str, 21 | _dll_imports: &[rustc_session::cstore::DllImport], 22 | _tmpdir: &Path, 23 | _is_direct_dependency: bool, 24 | ) -> PathBuf { 25 | unimplemented!("creating dll imports is not yet supported"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/func.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | use blessed_test::*; 4 | use rustc_codegen_c_ast::expr::CValue; 5 | use rustc_codegen_c_ast::func::{CFunc, CFuncKind}; 6 | use rustc_type_ir::IntTy; 7 | 8 | extern crate rustc_driver; 9 | extern crate rustc_type_ir; 10 | mod blessed_test; 11 | 12 | #[test] 13 | fn test_function() { 14 | printer_test("test_function", |ctx| { 15 | let func = ctx.func(CFuncKind::new( 16 | "foo", 17 | ctx.get_int_type(IntTy::I32), 18 | vec![ctx.get_int_type(IntTy::I32)], 19 | )); 20 | let x = func.next_local_var(); 21 | func.push_stmt(ctx.decl_stmt(ctx.var(x, ctx.get_int_type(IntTy::I32), None))); 22 | func.push_stmt(ctx.expr_stmt(ctx.binary(ctx.value(x), ctx.value(CValue::Scalar(1)), "="))); 23 | func.push_stmt(ctx.ret(Some(ctx.value(x)))); 24 | Box::new(CFunc::new_unchecked(func)) 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /bootstrap/src/rustc.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use clap::Args; 4 | 5 | use crate::manifest::Manifest; 6 | use crate::Run; 7 | 8 | /// Invoke rustc 9 | #[derive(Args, Debug)] 10 | pub struct RustcCommand { 11 | source: PathBuf, 12 | 13 | #[arg(last = true)] 14 | slop: Vec, 15 | 16 | #[arg(short, long)] 17 | pub verbose: bool, 18 | } 19 | 20 | impl Run for RustcCommand { 21 | const STEP_DISPLAY_NAME: &'static str = "RUSTC"; 22 | 23 | fn run(&self, manifest: &Manifest) { 24 | manifest.prepare(); 25 | 26 | let mut command = manifest.rustc(); 27 | command 28 | .arg(&self.source) 29 | .args(["--crate-type", "bin"]) 30 | .arg("--out-dir") 31 | .arg(&manifest.out_dir) 32 | .args(&self.slop); 33 | if self.verbose { 34 | command.env("RUST_BACKTRACE", "full"); 35 | } 36 | 37 | self.command_status("rustc", &mut command); 38 | } 39 | 40 | fn verbose(&self) -> bool { 41 | self.verbose 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/builder/debug_info.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_ssa::traits::DebugInfoBuilderMethods; 2 | 3 | use crate::builder::Builder; 4 | 5 | impl DebugInfoBuilderMethods for Builder<'_, '_, '_> { 6 | fn dbg_var_addr( 7 | &mut self, 8 | dbg_var: Self::DIVariable, 9 | dbg_loc: Self::DILocation, 10 | variable_alloca: Self::Value, 11 | direct_offset: rustc_abi::Size, 12 | // NB: each offset implies a deref (i.e. they're steps in a pointer chain). 13 | indirect_offsets: &[rustc_abi::Size], 14 | // Byte range in the `dbg_var` covered by this fragment, 15 | // if this is a fragment of a composite `DIVariable`. 16 | fragment: Option>, 17 | ) { 18 | todo!() 19 | } 20 | 21 | fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { 22 | todo!() 23 | } 24 | 25 | fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { 26 | todo!() 27 | } 28 | 29 | fn set_var_name(&mut self, value: Self::Value, name: &str) { 30 | todo!() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/module.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | use blessed_test::*; 4 | use rustc_codegen_c_ast::expr::CValue; 5 | use rustc_codegen_c_ast::func::{CFunc, CFuncKind}; 6 | use rustc_type_ir::IntTy; 7 | 8 | extern crate rustc_driver; 9 | extern crate rustc_type_ir; 10 | mod blessed_test; 11 | 12 | #[test] 13 | fn test_module() { 14 | printer_test("test_module", |ctx| { 15 | let module = ctx.module(); 16 | module.push_include("stdio.h"); 17 | 18 | module.push_decl(ctx.var(CValue::Local(42), ctx.get_int_type(IntTy::I32), None)); 19 | 20 | let func = ctx.func(CFuncKind::new( 21 | "foo", 22 | ctx.get_int_type(IntTy::I32), 23 | vec![ctx.get_int_type(IntTy::I32)], 24 | )); 25 | let x = func.next_local_var(); 26 | func.push_stmt(ctx.decl_stmt(ctx.var(x, ctx.get_int_type(IntTy::I32), None))); 27 | func.push_stmt(ctx.expr_stmt(ctx.binary(ctx.value(x), ctx.value(CValue::Scalar(1)), "="))); 28 | func.push_stmt(ctx.ret(Some(ctx.value(x)))); 29 | module.push_func(CFunc::new_unchecked(func)); 30 | Box::new(module.clone()) 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/builder/abi.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_c_ast::expr::CValue; 2 | use rustc_codegen_ssa::mir::place::PlaceRef; 3 | use rustc_codegen_ssa::traits::{AbiBuilderMethods, ArgAbiMethods}; 4 | use rustc_middle::ty::Ty; 5 | use rustc_target::abi::call::ArgAbi; 6 | 7 | use crate::builder::Builder; 8 | 9 | impl<'tcx, 'mx> AbiBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> { 10 | fn get_param(&mut self, index: usize) -> Self::Value { 11 | // Params are first n variables in the function 12 | CValue::Local(index) 13 | } 14 | } 15 | 16 | impl<'tcx, 'mx> ArgAbiMethods<'tcx> for Builder<'_, 'tcx, 'mx> { 17 | fn store_fn_arg( 18 | &mut self, 19 | arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, 20 | idx: &mut usize, 21 | dst: PlaceRef<'tcx, Self::Value>, 22 | ) { 23 | todo!() 24 | } 25 | 26 | fn store_arg( 27 | &mut self, 28 | arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, 29 | val: Self::Value, 30 | dst: PlaceRef<'tcx, Self::Value>, 31 | ) { 32 | todo!() 33 | } 34 | 35 | fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type { 36 | todo!() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/auxiliary/mini_core.rs: -------------------------------------------------------------------------------- 1 | #![feature(no_core, lang_items, rustc_attrs, intrinsics, decl_macro)] 2 | #![no_core] 3 | #![allow(internal_features)] 4 | 5 | #[lang = "sized"] 6 | pub trait Sized {} 7 | 8 | #[lang = "copy"] 9 | pub unsafe trait Copy {} 10 | 11 | unsafe impl Copy for bool {} 12 | unsafe impl Copy for u8 {} 13 | unsafe impl Copy for u16 {} 14 | unsafe impl Copy for u32 {} 15 | unsafe impl Copy for u64 {} 16 | unsafe impl Copy for usize {} 17 | unsafe impl Copy for i8 {} 18 | unsafe impl Copy for i16 {} 19 | unsafe impl Copy for i32 {} 20 | unsafe impl Copy for isize {} 21 | unsafe impl Copy for f32 {} 22 | unsafe impl Copy for f64 {} 23 | unsafe impl Copy for char {} 24 | unsafe impl<'a, T: ?Sized> Copy for &'a T {} 25 | unsafe impl Copy for *const T {} 26 | unsafe impl Copy for *mut T {} 27 | 28 | pub mod libc { 29 | #[link(name = "c")] 30 | extern "C" { 31 | pub fn puts(s: *const u8) -> i32; 32 | pub fn printf(format: *const i8, ...) -> i32; 33 | pub fn malloc(size: usize) -> *mut u8; 34 | pub fn free(ptr: *mut u8); 35 | pub fn memcpy(dst: *mut u8, src: *const u8, size: usize); 36 | pub fn memmove(dst: *mut u8, src: *const u8, size: usize); 37 | pub fn strncpy(dst: *mut u8, src: *const u8, size: usize); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/pre_define.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_c_ast::func::CFuncKind; 2 | use rustc_codegen_ssa::traits::{LayoutTypeMethods, PreDefineMethods}; 3 | use rustc_data_structures::intern::Interned; 4 | use rustc_hir::def_id::DefId; 5 | use rustc_middle::mir::mono::{Linkage, Visibility}; 6 | use rustc_middle::ty::layout::FnAbiOf; 7 | use rustc_middle::ty::{self, Instance}; 8 | 9 | use crate::context::CodegenCx; 10 | 11 | impl<'tcx, 'mx> PreDefineMethods<'tcx> for CodegenCx<'tcx, 'mx> { 12 | fn predefine_static( 13 | &self, 14 | def_id: DefId, 15 | linkage: Linkage, 16 | visibility: Visibility, 17 | symbol_name: &str, 18 | ) { 19 | todo!() 20 | } 21 | 22 | fn predefine_fn( 23 | &self, 24 | instance: Instance<'tcx>, 25 | linkage: Linkage, 26 | visibility: Visibility, 27 | symbol_name: &str, 28 | ) { 29 | let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); 30 | 31 | let args = fn_abi.args.iter().map(|arg| self.immediate_backend_type(arg.layout)); 32 | let ret = self.immediate_backend_type(fn_abi.ret.layout); 33 | 34 | let func = CFuncKind::new(self.mcx.alloc_str(symbol_name), ret, args); 35 | let func = Interned::new_unchecked(self.mcx.func(func)); 36 | self.mcx.module().push_func(func); 37 | self.function_instances.borrow_mut().insert(instance, func); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/builder/intrinsic_call.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_ssa::mir::operand::OperandRef; 2 | use rustc_codegen_ssa::traits::IntrinsicCallMethods; 3 | use rustc_middle::ty::{Instance, Ty}; 4 | use rustc_target::abi::call::FnAbi; 5 | 6 | use crate::builder::Builder; 7 | 8 | impl<'tcx, 'mx> IntrinsicCallMethods<'tcx> for Builder<'_, 'tcx, 'mx> { 9 | fn codegen_intrinsic_call( 10 | &mut self, 11 | instance: Instance<'tcx>, 12 | fn_abi: &FnAbi<'tcx, Ty<'tcx>>, 13 | args: &[OperandRef<'tcx, Self::Value>], 14 | llresult: Self::Value, 15 | span: rustc_span::Span, 16 | ) -> Result<(), Instance<'tcx>> { 17 | todo!() 18 | } 19 | 20 | fn abort(&mut self) { 21 | todo!() 22 | } 23 | 24 | fn assume(&mut self, val: Self::Value) { 25 | todo!() 26 | } 27 | 28 | fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value { 29 | todo!() 30 | } 31 | 32 | fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value { 33 | todo!() 34 | } 35 | 36 | fn type_checked_load( 37 | &mut self, 38 | llvtable: Self::Value, 39 | vtable_byte_offset: u64, 40 | typeid: Self::Value, 41 | ) -> Self::Value { 42 | todo!() 43 | } 44 | 45 | fn va_start(&mut self, val: Self::Value) -> Self::Value { 46 | todo!() 47 | } 48 | 49 | fn va_end(&mut self, val: Self::Value) -> Self::Value { 50 | todo!() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bootstrap/src/fmt.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | use clap::Args; 4 | use glob::glob; 5 | 6 | use crate::Run; 7 | 8 | /// Format code, examples and tests 9 | #[derive(Args, Debug)] 10 | pub struct FmtCommand { 11 | #[arg(short, long)] 12 | pub check: bool, 13 | 14 | #[arg(short, long)] 15 | pub verbose: bool, 16 | } 17 | 18 | impl Run for FmtCommand { 19 | const STEP_DISPLAY_NAME: &'static str = "FMT"; 20 | 21 | fn run(&self, _manifest: &crate::manifest::Manifest) { 22 | self.perform( 23 | Command::new("cargo").arg("fmt").args(["--manifest-path", "bootstrap/Cargo.toml"]), 24 | ); 25 | self.perform( 26 | Command::new("cargo") 27 | .arg("fmt") 28 | .args(["--manifest-path", "crates/Cargo.toml"]) 29 | .arg("--all"), 30 | ); 31 | for file in glob("examples/**/*.rs").unwrap() { 32 | self.perform(Command::new("rustfmt").args(["--edition", "2021"]).arg(file.unwrap())); 33 | } 34 | for file in glob("tests/**/*.rs").unwrap() { 35 | self.perform(Command::new("rustfmt").args(["--edition", "2021"]).arg(file.unwrap())); 36 | } 37 | } 38 | 39 | fn verbose(&self) -> bool { 40 | self.verbose 41 | } 42 | } 43 | 44 | impl FmtCommand { 45 | pub fn perform(&self, command: &mut Command) { 46 | if self.check { 47 | command.arg("--check"); 48 | } 49 | 50 | self.command_status("format code", command); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/blessed_test/mod.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | use rustc_codegen_c_ast::pretty::{Print, PrinterCtx}; 4 | use rustc_codegen_c_ast::{ModuleArena, ModuleCtx}; 5 | 6 | /// Run a blessed test. 7 | /// 8 | /// When the environment variable `RUST_BLESS` is set, this function will store 9 | /// the output of the test case in the corresponding file, otherwise it will 10 | /// compare the output of the test case with the stored output, making sure they 11 | /// are the same. 12 | #[track_caller] 13 | pub fn blessed_test(name: &str, bless: impl Fn() -> String) { 14 | let test_case_path = Path::new("tests/blessed").join(name).with_extension("out"); 15 | test_case_path.parent().map(std::fs::create_dir_all); 16 | 17 | let mut output = bless(); 18 | if !output.ends_with('\n') { 19 | output.push('\n'); // Ensure the output ends with a newline 20 | } 21 | 22 | let expected_output = std::fs::read_to_string(&test_case_path).unwrap_or_default(); 23 | if std::env::var("RUST_BLESS").is_ok() { 24 | std::fs::write(test_case_path, output).unwrap(); 25 | } else { 26 | assert_eq!(output, expected_output, "blessed test '{name}' failed"); 27 | } 28 | } 29 | 30 | /// Run a blessed test for a printable value. 31 | pub fn printer_test(name: &str, test: F) 32 | where 33 | F: for<'mx> Fn(ModuleCtx<'mx>) -> Box, // anyway to avoid the Box? 34 | { 35 | blessed_test(name, || { 36 | let module = ModuleArena::new("// blessed test"); 37 | let ctx = ModuleCtx(&module); 38 | 39 | let mut pp = PrinterCtx::new(); 40 | test(ctx).print_to(&mut pp); 41 | pp.finish() 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/stmt.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | use blessed_test::*; 4 | use rustc_codegen_c_ast::expr::CValue; 5 | use rustc_type_ir::IntTy; 6 | 7 | extern crate rustc_driver; 8 | extern crate rustc_type_ir; 9 | mod blessed_test; 10 | 11 | #[test] 12 | fn test_stmt_expr() { 13 | printer_test("test_stmt_expr", |ctx| { 14 | let callee = ctx.value(CValue::Func("foo")); 15 | let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))]; 16 | let expr = ctx.call(callee, args); 17 | Box::new(ctx.expr_stmt(expr)) 18 | }); 19 | } 20 | 21 | #[test] 22 | fn test_stmt_decl() { 23 | printer_test("test_stmt_decl", |ctx| { 24 | let ty = ctx.get_int_type(IntTy::I32); 25 | let name = CValue::Local(42); 26 | let value = ctx.value(CValue::Scalar(42)); 27 | let decl = ctx.var(name, ty, Some(value)); 28 | Box::new(ctx.decl_stmt(decl)) 29 | }); 30 | } 31 | 32 | #[test] 33 | fn test_stmt_block() { 34 | printer_test("test_stmt_block", |ctx| { 35 | let callee = ctx.value(CValue::Func("foo")); 36 | let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))]; 37 | let expr = ctx.call(callee, args); 38 | let stmt = ctx.expr_stmt(expr); 39 | Box::new(ctx.compound(vec![stmt])) 40 | }); 41 | } 42 | 43 | #[test] 44 | fn test_stmt_ret() { 45 | printer_test("test_stmt_if", |ctx| { 46 | let callee = ctx.value(CValue::Func("foo")); 47 | let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))]; 48 | let expr = ctx.call(callee, args); 49 | Box::new(ctx.ret(Some(expr))) 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/misc.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use rustc_codegen_c_ast::expr::CValue; 4 | use rustc_codegen_ssa::traits::MiscMethods; 5 | use rustc_hash::FxHashMap; 6 | use rustc_middle::mir::mono::CodegenUnit; 7 | use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; 8 | 9 | use crate::context::CodegenCx; 10 | 11 | impl<'tcx, 'mx> MiscMethods<'tcx> for CodegenCx<'tcx, 'mx> { 12 | fn vtables( 13 | &self, 14 | ) -> &RefCell, Option>), Self::Value>> { 15 | todo!() 16 | } 17 | 18 | fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function { 19 | *self.function_instances.borrow().get(&instance).unwrap() 20 | } 21 | 22 | fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value { 23 | let funcs = self.mcx.module().funcs.borrow(); 24 | let path = self.tcx.def_path_debug_str(instance.def_id()); 25 | let name = path.split("::").last().unwrap(); 26 | let func = funcs.iter().find(|f| f.0.name == name).unwrap(); 27 | CValue::Func(func.0.name) 28 | } 29 | 30 | fn eh_personality(&self) -> Self::Value { 31 | todo!() 32 | } 33 | 34 | fn sess(&self) -> &rustc_session::Session { 35 | self.tcx.sess 36 | } 37 | 38 | fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { 39 | todo!() 40 | } 41 | 42 | fn set_frame_pointer_type(&self, llfn: Self::Function) { 43 | todo!() 44 | } 45 | 46 | fn apply_target_cpu_attr(&self, llfn: Self::Function) { 47 | todo!() 48 | } 49 | 50 | fn declare_c_main(&self, fn_type: Self::Type) -> Option { 51 | todo!() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/decl.rs: -------------------------------------------------------------------------------- 1 | //! This module defines AST nodes for C declarations. 2 | 3 | use crate::expr::{CExpr, CValue}; 4 | use crate::pretty::{Print, PrinterCtx, INDENT}; 5 | use crate::ty::{print_declarator, CTy}; 6 | use crate::ModuleCtx; 7 | 8 | /// C declarations. 9 | pub type CDecl<'mx> = &'mx CDeclKind<'mx>; 10 | 11 | /// C declaration kinds. 12 | #[derive(Debug, Clone)] 13 | pub enum CDeclKind<'mx> { 14 | /// Variable declaration consisting of a name, type, and optional initializer. 15 | /// 16 | /// Example: 17 | /// - `int foo;` // `ty val` 18 | /// - `int foo = bar` `ty val = expr` 19 | Var { name: CValue<'mx>, ty: CTy<'mx>, init: Option> }, 20 | } 21 | 22 | impl<'mx> ModuleCtx<'mx> { 23 | /// Create a new declaration. 24 | pub fn decl(self, decl: CDeclKind<'mx>) -> CDecl<'mx> { 25 | self.arena().alloc(decl) 26 | } 27 | 28 | /// Create a new variable declaration. 29 | pub fn var(self, name: CValue<'mx>, ty: CTy<'mx>, init: Option>) -> CDecl<'mx> { 30 | self.decl(CDeclKind::Var { name, ty, init }) 31 | } 32 | } 33 | 34 | impl Print for CDecl<'_> { 35 | fn print_to(&self, ctx: &mut PrinterCtx) { 36 | match self { 37 | CDeclKind::Var { name, ty, init } => { 38 | ctx.ibox(INDENT, |ctx| { 39 | print_declarator(*ty, Some(*name), ctx); 40 | if let Some(init) = init { 41 | ctx.word(" ="); 42 | ctx.softbreak(); 43 | init.print_to(ctx); 44 | } 45 | ctx.word(";"); 46 | }); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/layout_type.rs: -------------------------------------------------------------------------------- 1 | use rustc_abi::Abi; 2 | use rustc_codegen_c_ast::ty::CTy; 3 | use rustc_codegen_ssa::traits::LayoutTypeMethods; 4 | use rustc_middle::ty::layout::TyAndLayout; 5 | use rustc_middle::ty::Ty; 6 | use rustc_target::abi::call::FnAbi; 7 | use rustc_type_ir::TyKind; 8 | 9 | use crate::context::CodegenCx; 10 | 11 | impl<'tcx, 'mx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx, 'mx> { 12 | fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type { 13 | todo!() 14 | } 15 | 16 | fn cast_backend_type(&self, ty: &rustc_target::abi::call::CastTarget) -> Self::Type { 17 | todo!() 18 | } 19 | 20 | fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type { 21 | CTy::Void 22 | } 23 | 24 | fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type { 25 | todo!() 26 | } 27 | 28 | fn reg_backend_type(&self, ty: &rustc_target::abi::call::Reg) -> Self::Type { 29 | todo!() 30 | } 31 | 32 | fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type { 33 | match layout.ty.kind() { 34 | TyKind::Int(int) => self.mcx.get_int_type(*int), 35 | TyKind::Uint(uint) => self.mcx.get_uint_type(*uint), 36 | _ => todo!(), 37 | } 38 | } 39 | 40 | fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool { 41 | match layout.abi { 42 | Abi::Scalar(_) | Abi::Vector { .. } => true, 43 | Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, 44 | } 45 | } 46 | 47 | fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool { 48 | todo!() 49 | } 50 | 51 | fn scalar_pair_element_backend_type( 52 | &self, 53 | layout: TyAndLayout<'tcx>, 54 | index: usize, 55 | immediate: bool, 56 | ) -> Self::Type { 57 | todo!() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/base_type.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_ssa::traits::BaseTypeMethods; 2 | 3 | use crate::context::CodegenCx; 4 | 5 | impl<'tcx, 'mx> BaseTypeMethods<'tcx> for CodegenCx<'tcx, 'mx> { 6 | fn type_i8(&self) -> Self::Type { 7 | todo!() 8 | } 9 | 10 | fn type_i16(&self) -> Self::Type { 11 | todo!() 12 | } 13 | 14 | fn type_i32(&self) -> Self::Type { 15 | todo!() 16 | } 17 | 18 | fn type_i64(&self) -> Self::Type { 19 | todo!() 20 | } 21 | 22 | fn type_i128(&self) -> Self::Type { 23 | todo!() 24 | } 25 | 26 | fn type_isize(&self) -> Self::Type { 27 | todo!() 28 | } 29 | 30 | fn type_f16(&self) -> Self::Type { 31 | todo!() 32 | } 33 | 34 | fn type_f32(&self) -> Self::Type { 35 | todo!() 36 | } 37 | 38 | fn type_f64(&self) -> Self::Type { 39 | todo!() 40 | } 41 | 42 | fn type_f128(&self) -> Self::Type { 43 | todo!() 44 | } 45 | 46 | fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type { 47 | todo!() 48 | } 49 | 50 | fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type { 51 | todo!() 52 | } 53 | 54 | fn type_kind(&self, ty: Self::Type) -> rustc_codegen_ssa::common::TypeKind { 55 | todo!() 56 | } 57 | 58 | fn type_ptr(&self) -> Self::Type { 59 | todo!() 60 | } 61 | 62 | fn type_ptr_ext(&self, address_space: rustc_abi::AddressSpace) -> Self::Type { 63 | todo!() 64 | } 65 | 66 | fn element_type(&self, ty: Self::Type) -> Self::Type { 67 | todo!() 68 | } 69 | 70 | fn vector_length(&self, ty: Self::Type) -> usize { 71 | todo!() 72 | } 73 | 74 | fn float_width(&self, ty: Self::Type) -> usize { 75 | todo!() 76 | } 77 | 78 | fn int_width(&self, ty: Self::Type) -> u64 { 79 | todo!() 80 | } 81 | 82 | fn val_ty(&self, v: Self::Value) -> Self::Type { 83 | todo!() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/debug_info.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; 2 | use rustc_codegen_ssa::traits::DebugInfoMethods; 3 | use rustc_middle::mir::Body; 4 | use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; 5 | use rustc_target::abi::call::FnAbi; 6 | 7 | use crate::context::CodegenCx; 8 | 9 | impl<'tcx, 'mx> DebugInfoMethods<'tcx> for CodegenCx<'tcx, 'mx> { 10 | fn create_vtable_debuginfo( 11 | &self, 12 | ty: Ty<'tcx>, 13 | trait_ref: Option>, 14 | vtable: Self::Value, 15 | ) { 16 | todo!() 17 | } 18 | 19 | fn create_function_debug_context( 20 | &self, 21 | instance: Instance<'tcx>, 22 | fn_abi: &FnAbi<'tcx, Ty<'tcx>>, 23 | llfn: Self::Function, 24 | mir: &Body<'tcx>, 25 | ) -> Option> { 26 | None 27 | } 28 | 29 | fn dbg_scope_fn( 30 | &self, 31 | instance: Instance<'tcx>, 32 | fn_abi: &FnAbi<'tcx, Ty<'tcx>>, 33 | maybe_definition_llfn: Option, 34 | ) -> Self::DIScope { 35 | todo!() 36 | } 37 | 38 | fn dbg_loc( 39 | &self, 40 | scope: Self::DIScope, 41 | inlined_at: Option, 42 | span: rustc_span::Span, 43 | ) -> Self::DILocation { 44 | todo!() 45 | } 46 | 47 | fn extend_scope_to_file( 48 | &self, 49 | scope_metadata: Self::DIScope, 50 | file: &rustc_span::SourceFile, 51 | ) -> Self::DIScope { 52 | todo!() 53 | } 54 | 55 | fn debuginfo_finalize(&self) { 56 | todo!() 57 | } 58 | 59 | fn create_dbg_var( 60 | &self, 61 | variable_name: rustc_span::Symbol, 62 | variable_type: Ty<'tcx>, 63 | scope_metadata: Self::DIScope, 64 | variable_kind: VariableKind, 65 | span: rustc_span::Span, 66 | ) -> Self::DIVariable { 67 | todo!() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/base.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | use rustc_codegen_c_ast::{ModuleArena, ModuleCtx}; 4 | use rustc_codegen_ssa::mono_item::MonoItemExt; 5 | use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; 6 | use rustc_middle::dep_graph; 7 | use rustc_middle::ty::TyCtxt; 8 | 9 | use crate::builder::Builder; 10 | use crate::context::CodegenCx; 11 | 12 | /// Needed helper functions 13 | const HELPER: &str = include_str!("./helper.h"); 14 | 15 | // note: parallel 16 | // it seems this function will be invoked parallelly (if parallel codegen is enabled) 17 | 18 | pub fn compile_codegen_unit( 19 | tcx: TyCtxt<'_>, 20 | cgu_name: rustc_span::Symbol, 21 | ) -> (ModuleCodegen, u64) { 22 | let start_time = Instant::now(); 23 | 24 | let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); 25 | let (module, _) = tcx.dep_graph.with_task( 26 | dep_node, 27 | tcx, 28 | cgu_name, 29 | module_codegen, 30 | Some(dep_graph::hash_result), 31 | ); 32 | 33 | let time_to_codegen = start_time.elapsed(); 34 | let cost = time_to_codegen 35 | .as_secs() 36 | .saturating_mul(1_000_000_000) 37 | .saturating_add(time_to_codegen.subsec_nanos() as u64); 38 | 39 | (module, cost) 40 | } 41 | 42 | fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegen { 43 | let cgu = tcx.codegen_unit(cgu_name); 44 | 45 | let mcx = ModuleArena::new(HELPER); 46 | let mcx = ModuleCtx(&mcx); 47 | let cx = CodegenCx::new(tcx, mcx); 48 | 49 | let mono_items = cgu.items_in_deterministic_order(tcx); 50 | for &(mono_item, data) in &mono_items { 51 | mono_item.predefine::>(&cx, data.linkage, data.visibility); 52 | } 53 | 54 | // ... and now that we have everything pre-defined, fill out those definitions. 55 | for &(mono_item, _) in &mono_items { 56 | mono_item.define::>(&cx); 57 | } 58 | 59 | let module = mcx.to_string(); 60 | ModuleCodegen { name: cgu_name.to_string(), module_llvm: module, kind: ModuleKind::Regular } 61 | } 62 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate defines the subset of the C AST used by the C codegen backend. 2 | //! 3 | //! Its primary purpose is to facilitate the construction and pretty-printing of C code. 4 | //! Note that parsing is not included in this crate. 5 | //! 6 | //! It also provides utilities to assist with building the C AST and integrating 7 | //! with the `rustc_codegen_ssa` backend. 8 | #![feature(rustc_private)] 9 | 10 | use std::fmt::{self, Display}; 11 | 12 | use crate::pretty::Print; 13 | 14 | extern crate rustc_arena; 15 | extern crate rustc_ast_pretty; 16 | extern crate rustc_data_structures; 17 | extern crate rustc_driver; 18 | extern crate rustc_type_ir; 19 | 20 | pub mod arena; 21 | pub mod decl; 22 | pub mod expr; 23 | pub mod func; 24 | pub mod module; 25 | pub mod pretty; 26 | pub mod stmt; 27 | pub mod ty; 28 | 29 | /// A context containing a C file's AST nodes which are under construction. 30 | #[derive(Clone, Copy)] 31 | pub struct ModuleCtx<'mx>(pub &'mx ModuleArena<'mx>); 32 | 33 | impl<'mx> ModuleCtx<'mx> { 34 | /// Get the memory arena for the context. 35 | pub fn arena(&self) -> &'mx arena::Arena<'mx> { 36 | &self.0.arena 37 | } 38 | 39 | /// Get the AST node for the module. 40 | pub fn module(&self) -> &'mx module::Module<'mx> { 41 | &self.0.module 42 | } 43 | 44 | /// Allocate a string in the arena. 45 | pub fn alloc_str(&self, s: &str) -> &'mx str { 46 | self.arena().alloc_str(s) 47 | } 48 | } 49 | 50 | impl<'mx> Display for ModuleCtx<'mx> { 51 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 52 | let mut printer = pretty::PrinterCtx::new(); 53 | self.module().print_to(&mut printer); 54 | write!(f, "{}", printer.finish()) 55 | } 56 | } 57 | 58 | pub struct ModuleArena<'mx> { 59 | /// The memory arena for the module. 60 | pub arena: arena::Arena<'mx>, 61 | /// The module's AST node. 62 | pub module: module::Module<'mx>, 63 | } 64 | 65 | impl<'mx> ModuleArena<'mx> { 66 | pub fn new(helper: &'static str) -> Self { 67 | Self { arena: arena::Arena::default(), module: module::Module::new(helper) } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | env: 5 | RUSTDOCFLAGS: -D warnings 6 | RUSTFLAGS: -D warnings 7 | 8 | jobs: 9 | clippy: 10 | name: clippy 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Install Rust 15 | run: rustup show 16 | - uses: Swatinem/rust-cache@v2 17 | - name: Install packages 18 | run: | 19 | sudo apt-get install llvm-14-tools 20 | - run: cargo clippy --manifest-path crates/Cargo.toml --all-features --all-targets -- -D warnings 21 | 22 | test: 23 | name: test 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Install Rust 28 | run: rustup show 29 | - uses: Swatinem/rust-cache@v2 30 | - name: Install packages 31 | run: | 32 | sudo apt-get install llvm-14-tools 33 | - run: ./y test 34 | 35 | rustfmt: 36 | name: rustfmt 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v4 40 | - name: Install Rust 41 | run: rustup show 42 | - uses: Swatinem/rust-cache@v2 43 | - name: Install packages 44 | run: | 45 | sudo apt-get install llvm-14-tools 46 | - run: ./y fmt --check 47 | 48 | doc: 49 | name: docs 50 | runs-on: ubuntu-latest 51 | steps: 52 | - uses: actions/checkout@v4 53 | - name: Install Rust 54 | run: rustup show 55 | - uses: Swatinem/rust-cache@v2 56 | - name: Install packages 57 | run: | 58 | sudo apt-get install llvm-14-tools 59 | - run: cargo doc --manifest-path crates/Cargo.toml 60 | 61 | success: 62 | needs: 63 | - clippy 64 | - test 65 | - rustfmt 66 | - doc 67 | runs-on: ubuntu-latest 68 | # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency 69 | # failed" as success. So we have to do some contortions to ensure the job fails if any of its 70 | # dependencies fails. 71 | if: always() # make sure this is never "skipped" 72 | steps: 73 | # Manually check the status of all dependencies. `if: failure()` does not work. 74 | - name: check if any dependency failed 75 | run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' 76 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/tests/expr.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | use blessed_test::*; 4 | use rustc_codegen_c_ast::expr::CValue; 5 | use rustc_type_ir::IntTy; 6 | 7 | extern crate rustc_driver; 8 | extern crate rustc_type_ir; 9 | mod blessed_test; 10 | 11 | #[test] 12 | fn test_value_scalar() { 13 | printer_test("test_value_scalar", |_| Box::new(CValue::Scalar(42))); 14 | } 15 | 16 | #[test] 17 | fn test_value_local() { 18 | printer_test("test_value_local", |_| Box::new(CValue::Local(42))); 19 | } 20 | 21 | #[test] 22 | fn test_value_func() { 23 | printer_test("test_value_func", |_| Box::new(CValue::Func("foo"))); 24 | } 25 | 26 | #[test] 27 | fn test_expr_raw() { 28 | printer_test("test_expr_raw", |ctx| Box::new(ctx.raw("42"))); 29 | } 30 | 31 | #[test] 32 | fn test_expr_binary() { 33 | printer_test("test_expr_binary", |ctx| { 34 | let lhs = ctx.value(CValue::Scalar(1)); 35 | let rhs = ctx.value(CValue::Scalar(2)); 36 | Box::new(ctx.binary(lhs, rhs, "+")) 37 | }); 38 | } 39 | 40 | #[test] 41 | fn test_expr_cast() { 42 | printer_test("test_expr_cast", |ctx| { 43 | let ty = ctx.get_int_type(IntTy::I32); 44 | let expr = ctx.value(CValue::Scalar(42)); 45 | Box::new(ctx.cast(ty, expr)) 46 | }); 47 | } 48 | 49 | #[test] 50 | fn test_expr_call() { 51 | printer_test("test_expr_call", |ctx| { 52 | let callee = ctx.value(CValue::Func("foo")); 53 | let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))]; 54 | Box::new(ctx.call(callee, args)) 55 | }); 56 | } 57 | 58 | #[test] 59 | fn test_expr_member() { 60 | printer_test("test_expr_member", |ctx| { 61 | let expr = ctx.value(CValue::Local(42)); 62 | Box::new(ctx.member(expr, "foo")) 63 | }); 64 | } 65 | 66 | #[test] 67 | fn test_expr_complex() { 68 | printer_test("test_expr_complex", |ctx| { 69 | let lhs = ctx.value(CValue::Scalar(1)); 70 | let rhs = ctx.value(CValue::Scalar(2)); 71 | let expr = ctx.binary(lhs, rhs, "+"); 72 | 73 | let ty = ctx.get_int_type(IntTy::I32); 74 | let cast = ctx.cast(ty, expr); 75 | 76 | let callee = ctx.value(CValue::Func("foo")); 77 | let args = vec![ctx.value(CValue::Scalar(1)), cast]; 78 | let call = ctx.call(callee, args); 79 | 80 | let member = ctx.member(call, "bar"); 81 | 82 | Box::new(member) 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/write.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io::Write; 3 | use std::process::Stdio; 4 | 5 | use rustc_codegen_ssa::back::command::Command; 6 | use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig}; 7 | use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; 8 | use rustc_errors::{DiagCtxtHandle, FatalError}; 9 | use rustc_session::config::OutputType; 10 | use tracing::error; 11 | 12 | pub(crate) unsafe fn codegen( 13 | cgcx: &CodegenContext, 14 | _dcx: DiagCtxtHandle<'_>, 15 | module: ModuleCodegen, 16 | _config: &ModuleConfig, 17 | ) -> Result { 18 | let module_name = module.name.clone(); 19 | let module_name = Some(&module_name[..]); 20 | let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); 21 | let c_out = obj_out.with_extension("c"); 22 | 23 | // output c source code 24 | let c_out_file = fs::File::create(&c_out).map_err(|_| FatalError)?; 25 | writeln!(&c_out_file, "// file: {}.c", module.name).map_err(|_| FatalError)?; 26 | write!(&c_out_file, "{}", module.module_llvm).map_err(|_| FatalError)?; 27 | 28 | // invoke cc to compile 29 | // FIXME: configure cc 30 | // FIXME: handle long command line (windows) 31 | // FIXME: flush_linked_file (windows) 32 | let mut cmd = Command::new("clang"); 33 | cmd.arg(&c_out).arg("-o").arg(&obj_out).arg("-c"); 34 | let mut cmd = cmd.command(); 35 | let output = match cmd 36 | .stdout(Stdio::piped()) 37 | .stderr(Stdio::piped()) 38 | .spawn() 39 | .and_then(|child| child.wait_with_output()) 40 | { 41 | Ok(output) => output, 42 | Err(e) => { 43 | error!("failed to spawn C compiler: {}", e); 44 | return Err(FatalError); 45 | } 46 | }; 47 | 48 | if !output.status.success() { 49 | error!("compiler stderr:\n{}", String::from_utf8_lossy(&output.stderr)); 50 | error!("compiler stdout:\n{}", String::from_utf8_lossy(&output.stdout)); 51 | return Err(FatalError); 52 | } 53 | 54 | Ok(module.into_compiled_module(true, false, false, false, false, &cgcx.output_filenames)) 55 | } 56 | 57 | pub(crate) fn link( 58 | _cgcx: &CodegenContext, 59 | _dcx: DiagCtxtHandle<'_>, 60 | mut _modules: Vec>, 61 | ) -> Result, FatalError> { 62 | unimplemented!(); 63 | } 64 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/module.rs: -------------------------------------------------------------------------------- 1 | //! This module defines AST nodes for C modules. 2 | 3 | use std::cell::RefCell; 4 | 5 | use crate::decl::CDecl; 6 | use crate::func::{print_func_decl, CFunc}; 7 | use crate::pretty::{Print, PrinterCtx}; 8 | 9 | /// C module definition. 10 | #[derive(Debug, Clone)] 11 | pub struct Module<'mx> { 12 | /// Includes. Only the file name is recorded, without the angle brackets. 13 | pub includes: RefCell>, 14 | /// A piece of helper code to be included at the beginning of the file. 15 | pub helper: &'static str, 16 | /// Declarations. 17 | pub decls: RefCell>>, 18 | /// Function definitions. 19 | pub funcs: RefCell>>, 20 | } 21 | 22 | impl<'mx> Module<'mx> { 23 | /// Make a new module definition. 24 | pub fn new(helper: &'static str) -> Self { 25 | Self { 26 | includes: RefCell::new(Vec::new()), 27 | helper, 28 | decls: RefCell::new(Vec::new()), 29 | funcs: RefCell::new(Vec::new()), 30 | } 31 | } 32 | 33 | /// Push an include directive to the end of the includes list. 34 | pub fn push_include(&self, include: &'static str) { 35 | self.includes.borrow_mut().push(include); 36 | } 37 | 38 | /// Push a declaration to the end of the declarations list. 39 | pub fn push_decl(&self, decl: CDecl<'mx>) { 40 | self.decls.borrow_mut().push(decl); 41 | } 42 | 43 | /// Push a function definition to the end of the function definitions list. 44 | pub fn push_func(&self, func: CFunc<'mx>) { 45 | self.funcs.borrow_mut().push(func); 46 | } 47 | } 48 | 49 | impl Print for Module<'_> { 50 | fn print_to(&self, ctx: &mut PrinterCtx) { 51 | ctx.cbox(0, |ctx| { 52 | for &include in self.includes.borrow().iter() { 53 | ctx.word("#include <"); 54 | ctx.word(include); 55 | ctx.word(">"); 56 | ctx.hardbreak(); 57 | } 58 | 59 | ctx.hardbreak(); 60 | 61 | ctx.word(self.helper); 62 | 63 | for &decl in self.decls.borrow().iter() { 64 | ctx.hardbreak(); 65 | ctx.hardbreak(); 66 | decl.print_to(ctx); 67 | } 68 | 69 | for &func in self.funcs.borrow().iter() { 70 | ctx.hardbreak(); 71 | print_func_decl(func, ctx); 72 | } 73 | 74 | for &func in self.funcs.borrow().iter() { 75 | ctx.hardbreak(); 76 | ctx.hardbreak(); 77 | func.print_to(ctx); 78 | } 79 | 80 | ctx.hardbreak(); 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/stmt.rs: -------------------------------------------------------------------------------- 1 | //! This module defines the AST nodes for C statements. 2 | 3 | use crate::decl::CDecl; 4 | use crate::expr::CExpr; 5 | use crate::pretty::{Print, PrinterCtx, INDENT}; 6 | use crate::ModuleCtx; 7 | 8 | /// C statement. 9 | pub type CStmt<'mx> = &'mx CStmtKind<'mx>; 10 | 11 | /// C statement. 12 | #[derive(Debug, Clone)] 13 | pub enum CStmtKind<'mx> { 14 | /// Compound statement, which is a sequence of statements enclosed in braces. 15 | Compound(Vec>), 16 | /// Return statement. 17 | Return(Option>), 18 | /// Declaration statement, e.g. `int x = 42;`. 19 | Decl(CDecl<'mx>), 20 | /// Expression statement, e.g. `foo(x + 1);`. 21 | Expr(CExpr<'mx>), 22 | } 23 | 24 | impl<'mx> ModuleCtx<'mx> { 25 | /// Create a new statement. 26 | pub fn stmt(self, stmt: CStmtKind<'mx>) -> CStmt<'mx> { 27 | self.arena().alloc(stmt) 28 | } 29 | 30 | /// Create a compound statement. 31 | pub fn compound(self, stmts: Vec>) -> CStmt<'mx> { 32 | self.stmt(CStmtKind::Compound(stmts)) 33 | } 34 | 35 | /// Create a return statement. 36 | pub fn ret(self, expr: Option>) -> CStmt<'mx> { 37 | self.stmt(CStmtKind::Return(expr)) 38 | } 39 | 40 | /// Create a declaration statement. 41 | pub fn decl_stmt(self, decl: CDecl<'mx>) -> CStmt<'mx> { 42 | self.stmt(CStmtKind::Decl(decl)) 43 | } 44 | 45 | /// Create an expression statement. 46 | pub fn expr_stmt(self, expr: CExpr<'mx>) -> CStmt<'mx> { 47 | self.stmt(CStmtKind::Expr(expr)) 48 | } 49 | } 50 | 51 | impl Print for CStmt<'_> { 52 | fn print_to(&self, ctx: &mut PrinterCtx) { 53 | match self { 54 | CStmtKind::Compound(stmts) => print_compound(stmts, ctx), 55 | CStmtKind::Return(ret) => { 56 | ctx.ibox(INDENT, |ctx| { 57 | ctx.word("return"); 58 | if let Some(ret) = ret { 59 | ctx.softbreak(); 60 | ret.print_to(ctx); 61 | } 62 | ctx.word(";"); 63 | }); 64 | } 65 | CStmtKind::Decl(decl) => decl.print_to(ctx), 66 | CStmtKind::Expr(expr) => { 67 | expr.print_to(ctx); 68 | ctx.word(";"); 69 | } 70 | } 71 | } 72 | } 73 | 74 | /// Print a compound statement. 75 | pub(crate) fn print_compound(stmts: &[CStmt], ctx: &mut PrinterCtx) { 76 | ctx.cbox_delim(INDENT, ("{", "}"), 1, |ctx| { 77 | if let Some((first, rest)) = stmts.split_first() { 78 | first.print_to(ctx); 79 | for stmt in rest { 80 | ctx.hardbreak(); 81 | stmt.print_to(ctx); 82 | } 83 | } 84 | }); 85 | } 86 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context/const.rs: -------------------------------------------------------------------------------- 1 | use rustc_codegen_c_ast::expr::CValue; 2 | use rustc_codegen_ssa::traits::ConstMethods; 3 | use rustc_const_eval::interpret::{ConstAllocation, Scalar}; 4 | 5 | use crate::context::CodegenCx; 6 | 7 | impl<'tcx, 'mx> ConstMethods<'tcx> for CodegenCx<'tcx, 'mx> { 8 | fn const_null(&self, t: Self::Type) -> Self::Value { 9 | todo!() 10 | } 11 | 12 | fn const_undef(&self, t: Self::Type) -> Self::Value { 13 | todo!() 14 | } 15 | 16 | fn const_poison(&self, t: Self::Type) -> Self::Value { 17 | todo!() 18 | } 19 | 20 | fn const_int(&self, t: Self::Type, i: i64) -> Self::Value { 21 | todo!() 22 | } 23 | 24 | fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value { 25 | todo!() 26 | } 27 | 28 | fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value { 29 | todo!() 30 | } 31 | 32 | fn const_bool(&self, val: bool) -> Self::Value { 33 | todo!() 34 | } 35 | 36 | fn const_i16(&self, i: i16) -> Self::Value { 37 | todo!() 38 | } 39 | 40 | fn const_i32(&self, i: i32) -> Self::Value { 41 | todo!() 42 | } 43 | 44 | fn const_i8(&self, i: i8) -> Self::Value { 45 | todo!() 46 | } 47 | 48 | fn const_u32(&self, i: u32) -> Self::Value { 49 | todo!() 50 | } 51 | 52 | fn const_u64(&self, i: u64) -> Self::Value { 53 | todo!() 54 | } 55 | 56 | fn const_u128(&self, i: u128) -> Self::Value { 57 | todo!() 58 | } 59 | 60 | fn const_usize(&self, i: u64) -> Self::Value { 61 | todo!() 62 | } 63 | 64 | fn const_u8(&self, i: u8) -> Self::Value { 65 | todo!() 66 | } 67 | 68 | fn const_real(&self, t: Self::Type, val: f64) -> Self::Value { 69 | todo!() 70 | } 71 | 72 | fn const_str(&self, s: &str) -> (Self::Value, Self::Value) { 73 | todo!() 74 | } 75 | 76 | fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value { 77 | todo!() 78 | } 79 | 80 | fn const_to_opt_uint(&self, v: Self::Value) -> Option { 81 | todo!() 82 | } 83 | 84 | fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option { 85 | todo!() 86 | } 87 | 88 | fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { 89 | todo!() 90 | } 91 | 92 | fn scalar_to_backend( 93 | &self, 94 | cv: Scalar, 95 | layout: rustc_target::abi::Scalar, 96 | llty: Self::Type, 97 | ) -> Self::Value { 98 | match cv { 99 | Scalar::Int(scalar) => CValue::Scalar(scalar.to_int(scalar.size())), 100 | Scalar::Ptr(_, _) => todo!(), 101 | } 102 | } 103 | 104 | fn const_ptr_byte_offset( 105 | &self, 106 | val: Self::Value, 107 | offset: rustc_target::abi::Size, 108 | ) -> Self::Value { 109 | todo!() 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/func.rs: -------------------------------------------------------------------------------- 1 | //! This module defines AST nodes for C functions. 2 | 3 | use std::cell::{Cell, RefCell}; 4 | 5 | use rustc_data_structures::intern::Interned; 6 | 7 | use crate::expr::CValue; 8 | use crate::pretty::{Print, PrinterCtx}; 9 | use crate::stmt::{print_compound, CStmt}; 10 | use crate::ty::{print_declarator, CTy}; 11 | use crate::ModuleCtx; 12 | 13 | /// C functions definition. 14 | pub type CFunc<'mx> = Interned<'mx, CFuncKind<'mx>>; 15 | 16 | /// C function definition. 17 | #[derive(Debug, Clone)] 18 | pub struct CFuncKind<'mx> { 19 | /// Function name. 20 | pub name: &'mx str, 21 | /// Return type. 22 | pub ty: CTy<'mx>, 23 | /// Function parameters. 24 | pub params: Vec<(CTy<'mx>, CValue<'mx>)>, 25 | /// Function body. 26 | pub body: RefCell>>, 27 | /// A counter for local variables, for generating unique names. 28 | local_var_counter: Cell, 29 | } 30 | 31 | impl<'mx> CFuncKind<'mx> { 32 | /// Make a new function definition. 33 | pub fn new(name: &'mx str, ty: CTy<'mx>, params: impl IntoIterator>) -> Self { 34 | let params = params 35 | .into_iter() 36 | .enumerate() 37 | .map(|(i, ty)| (ty, CValue::Local(i))) 38 | .collect::>(); 39 | let local_var_counter = Cell::new(params.len()); 40 | 41 | Self { name, ty, params, body: RefCell::new(Vec::new()), local_var_counter } 42 | } 43 | 44 | /// Push a statement to the end of the function body. 45 | pub fn push_stmt(&self, stmt: CStmt<'mx>) { 46 | self.body.borrow_mut().push(stmt); 47 | } 48 | 49 | /// Get a new unique local variable. 50 | pub fn next_local_var(&self) -> CValue { 51 | let val = CValue::Local(self.local_var_counter.get()); 52 | self.local_var_counter.set(self.local_var_counter.get() + 1); 53 | val 54 | } 55 | } 56 | 57 | impl<'mx> ModuleCtx<'mx> { 58 | /// Create a new function definition. 59 | pub fn func(&self, func: CFuncKind<'mx>) -> &'mx CFuncKind<'mx> { 60 | self.arena().alloc(func) 61 | } 62 | } 63 | 64 | impl Print for CFunc<'_> { 65 | fn print_to(&self, ctx: &mut PrinterCtx) { 66 | ctx.ibox(0, |ctx| { 67 | print_signature(*self, ctx); 68 | ctx.softbreak(); // I don't know how to avoid a newline here 69 | print_compound(&self.0.body.borrow(), ctx); 70 | }) 71 | } 72 | } 73 | 74 | pub(crate) fn print_func_decl(func: CFunc, ctx: &mut PrinterCtx) { 75 | print_signature(func, ctx); 76 | ctx.word(";"); 77 | } 78 | 79 | fn print_signature(func: CFunc, ctx: &mut PrinterCtx) { 80 | ctx.ibox(0, |ctx| { 81 | print_declarator(func.0.ty, Some(CValue::Func(func.0.name)), ctx); 82 | 83 | ctx.valign_delim(("(", ")"), |ctx| { 84 | ctx.seperated(",", &func.0.params, |ctx, (ty, name)| { 85 | ctx.ibox(0, |ctx| { 86 | print_declarator(*ty, Some(*name), ctx); 87 | }) 88 | }) 89 | }); 90 | }); 91 | } 92 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/context.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] // TODO 2 | 3 | use std::cell::RefCell; 4 | 5 | use rustc_abi::{HasDataLayout, TargetDataLayout}; 6 | use rustc_codegen_c_ast::expr::CValue; 7 | use rustc_codegen_c_ast::func::CFunc; 8 | use rustc_codegen_c_ast::ty::CTy; 9 | use rustc_codegen_c_ast::ModuleCtx; 10 | use rustc_codegen_ssa::traits::BackendTypes; 11 | use rustc_hash::FxHashMap; 12 | use rustc_middle::ty::layout::{ 13 | FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, 14 | TyAndLayout, 15 | }; 16 | use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; 17 | use rustc_target::abi::call::FnAbi; 18 | use rustc_target::spec::{HasTargetSpec, Target}; 19 | 20 | mod asm; 21 | mod base_type; 22 | mod r#const; 23 | mod debug_info; 24 | mod layout_type; 25 | mod misc; 26 | mod pre_define; 27 | mod r#static; 28 | mod type_membership; 29 | 30 | /// Codegen context. 31 | /// 32 | /// It provides the global context for code generation. 33 | pub struct CodegenCx<'tcx, 'mx> { 34 | /// The type context. See [`TyCtxt`]. 35 | pub tcx: TyCtxt<'tcx>, 36 | /// The output and context for the outputed module. 37 | pub mcx: ModuleCtx<'mx>, 38 | /// Mapping from Rust function instances to their corresponding C functions. 39 | pub function_instances: RefCell, CFunc<'mx>>>, 40 | } 41 | 42 | impl<'tcx, 'mx> CodegenCx<'tcx, 'mx> { 43 | pub fn new(tcx: TyCtxt<'tcx>, mcx: ModuleCtx<'mx>) -> Self { 44 | mcx.module().push_include("stdint.h"); 45 | Self { tcx, mcx, function_instances: RefCell::new(FxHashMap::default()) } 46 | } 47 | } 48 | 49 | impl<'tcx, 'mx> BackendTypes for CodegenCx<'tcx, 'mx> { 50 | type Value = CValue<'mx>; 51 | type Function = CFunc<'mx>; 52 | type BasicBlock = CFunc<'mx>; 53 | type Type = CTy<'mx>; 54 | type Funclet = (); 55 | type DIScope = (); 56 | type DILocation = (); 57 | type DIVariable = (); 58 | } 59 | 60 | impl<'tcx, 'mx> HasTargetSpec for CodegenCx<'tcx, 'mx> { 61 | fn target_spec(&self) -> &Target { 62 | todo!() 63 | } 64 | } 65 | 66 | impl<'tcx, 'mx> HasParamEnv<'tcx> for CodegenCx<'tcx, 'mx> { 67 | fn param_env(&self) -> ParamEnv<'tcx> { 68 | ParamEnv::reveal_all() 69 | } 70 | } 71 | 72 | impl<'tcx, 'mx> HasTyCtxt<'tcx> for CodegenCx<'tcx, 'mx> { 73 | fn tcx(&self) -> TyCtxt<'tcx> { 74 | self.tcx 75 | } 76 | } 77 | 78 | impl<'tcx, 'mx> HasDataLayout for CodegenCx<'tcx, 'mx> { 79 | fn data_layout(&self) -> &TargetDataLayout { 80 | todo!() 81 | } 82 | } 83 | 84 | impl<'tcx, 'mx> LayoutOfHelpers<'tcx> for CodegenCx<'tcx, 'mx> { 85 | type LayoutOfResult = TyAndLayout<'tcx>; 86 | 87 | fn handle_layout_err(&self, err: LayoutError<'tcx>, span: rustc_span::Span, ty: Ty<'tcx>) -> ! { 88 | todo!() 89 | } 90 | } 91 | 92 | impl<'tcx, 'mx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx, 'mx> { 93 | type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; 94 | 95 | fn handle_fn_abi_err( 96 | &self, 97 | err: FnAbiError<'tcx>, 98 | span: rustc_span::Span, 99 | fn_abi_request: FnAbiRequest<'tcx>, 100 | ) -> ! { 101 | todo!() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /bootstrap/src/manifest.rs: -------------------------------------------------------------------------------- 1 | use std::path::{Path, PathBuf}; 2 | use std::process::Command; 3 | 4 | use anstream::eprintln as println; 5 | use color_print::cprintln; 6 | 7 | use crate::Run; 8 | 9 | #[derive(Debug)] 10 | pub struct Manifest { 11 | pub verbose: bool, 12 | pub release: bool, 13 | pub out_dir: PathBuf, 14 | } 15 | 16 | impl Manifest { 17 | /// Builds the rustc codegen c library 18 | pub fn prepare(&self) { 19 | let prepare = PrepareAction { verbose: self.verbose }; 20 | prepare.run(&self); 21 | } 22 | 23 | /// The path to the rustc codegen c library 24 | pub fn codegen_backend(&self) -> &'static Path { 25 | if self.release { 26 | Path::new("crates/target/release/librustc_codegen_c.so") 27 | } else { 28 | Path::new("crates/target/debug/librustc_codegen_c.so") 29 | } 30 | } 31 | 32 | /// The command to run rustc with the codegen backend 33 | pub fn rustc(&self) -> Command { 34 | let mut command = Command::new("rustc"); 35 | command 36 | .args(["--edition", "2021"]) 37 | .arg("-Z") 38 | .arg(format!("codegen-backend={}", self.codegen_backend().display())) 39 | .args(["-C", "panic=abort"]) 40 | .args(["-C", "lto=false"]) 41 | .arg(format!("-Lall={}", self.out_dir.display())) 42 | .env("CFLAGS", "-Irust_runtime") 43 | .arg("-lc") 44 | .arg("-lrust_runtime"); 45 | if self.verbose { 46 | command.env("RUST_BACKTRACE", "full"); 47 | } 48 | command 49 | } 50 | } 51 | 52 | struct PrepareAction { 53 | verbose: bool, 54 | } 55 | 56 | impl Run for PrepareAction { 57 | const STEP_DISPLAY_NAME: &'static str = "prepare"; 58 | 59 | fn run(&self, manifest: &Manifest) { 60 | // action: Build codegen backend 61 | self.log_action_start("building", "codegen backend"); 62 | self.log_action_context("target", manifest.codegen_backend().display()); 63 | 64 | let mut command = Command::new("cargo"); 65 | command.arg("build").args(["--manifest-path", "crates/Cargo.toml"]); 66 | if manifest.verbose { 67 | command.args(["-v"]); 68 | } 69 | if manifest.release { 70 | command.arg("--release"); 71 | } 72 | self.command_status("build", &mut command); 73 | 74 | // action: Build runtime library 75 | self.log_action_start("building", "librust_runtime"); 76 | self.log_action_context("output dir", &manifest.out_dir.to_path_buf().display()); 77 | 78 | // cmd: Create output directory 79 | if let Err(e) = std::fs::create_dir_all(&manifest.out_dir) { 80 | cprintln!(" failed to create output directory: {}", e); 81 | std::process::exit(1); 82 | } 83 | 84 | let cc = std::env::var("CC").unwrap_or("clang".to_string()); 85 | 86 | // cmd: Compile runtime.c 87 | let mut command = Command::new(&cc); 88 | command 89 | .arg("rust_runtime/rust_runtime.c") 90 | .arg("-o") 91 | .arg(manifest.out_dir.join("rust_runtime.o")) 92 | .arg("-c"); 93 | self.command_status("build", &mut command); 94 | 95 | // cmd: Create static library 96 | let mut command = Command::new("ar"); 97 | command 98 | .arg("rcs") 99 | .arg(manifest.out_dir.join("librust_runtime.a")) 100 | .arg(manifest.out_dir.join("rust_runtime.o")); 101 | self.command_status("archive", &mut command); 102 | } 103 | 104 | fn verbose(&self) -> bool { 105 | self.verbose 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /bootstrap/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | use std::process::{self, ExitStatus}; 3 | 4 | use clap::{Parser, Subcommand}; 5 | use color_print::cprintln; 6 | 7 | use crate::manifest::Manifest; 8 | 9 | mod clean; 10 | mod fmt; 11 | mod manifest; 12 | mod rustc; 13 | mod test; 14 | 15 | /// Bootstrap system for the rustc codegen c 16 | #[derive(Parser, Debug)] 17 | #[command(about, long_about = None)] 18 | pub struct Cli { 19 | /// Build the codegen backend in release mode 20 | #[arg(short, long)] 21 | pub release: bool, 22 | 23 | /// The output directory 24 | #[arg(short, long)] 25 | pub out_dir: Option, 26 | 27 | /// verbose output 28 | #[arg(short, long)] 29 | pub verbose: bool, 30 | 31 | #[command(subcommand)] 32 | pub command: Command, 33 | } 34 | 35 | #[derive(Subcommand, Debug)] 36 | pub enum Command { 37 | Test(test::TestCommand), 38 | Clean(clean::CleanCommand), 39 | Rustc(rustc::RustcCommand), 40 | Fmt(fmt::FmtCommand), 41 | } 42 | 43 | trait Run { 44 | // The name like "BUILD" or "TEST" for logs. 45 | const STEP_DISPLAY_NAME: &'static str; 46 | fn run(&self, manifest: &Manifest); 47 | 48 | /// True if verbose output should be enabled. 49 | fn verbose(&self) -> bool; 50 | 51 | /// Record that the step has started a new action. 52 | fn log_action_start(&self, action: &str, item: impl Display) { 53 | let name = Self::STEP_DISPLAY_NAME; 54 | cprintln!("[{name}] {action} {item}"); 55 | } 56 | 57 | /// Record context associated with the current action. Only use if there has been a preceding 58 | /// call to `log_action_start`. 59 | fn log_action_context(&self, key: impl Display, value: impl Display) { 60 | if self.verbose() { 61 | cprintln!(" {key}: {value}"); 62 | } 63 | } 64 | 65 | /// Run a command and ensure it succeeds, capturing output. 66 | fn command_output(&self, action: &str, command: &mut process::Command) -> process::Output { 67 | if self.verbose() { 68 | cprintln!(" {action}: {command:?}"); 69 | } 70 | 71 | match command.output() { 72 | // Command ran and completed successfully 73 | Ok(output) if output.status.success() => { 74 | if self.verbose() { 75 | cprintln!(" success"); 76 | } 77 | output 78 | } 79 | // Command ran but did not complete 80 | Ok(output) => panic!("command failed: {}", String::from_utf8_lossy(&output.stderr)), 81 | Err(e) => panic!("command failed: {e:?}"), 82 | } 83 | } 84 | 85 | /// Run a command and ensure it succeeds. 86 | fn command_status(&self, action: &str, command: &mut process::Command) -> ExitStatus { 87 | if self.verbose() { 88 | cprintln!(" {}: {}", action, format!("{:?}", command).replace('"', "")); 89 | } 90 | match command.status() { 91 | // Command ran and completed successfully 92 | Ok(status) if status.success() => { 93 | if self.verbose() { 94 | cprintln!(" success"); 95 | } 96 | status 97 | } 98 | // Command ran but did not complete 99 | Ok(status) => panic!("command failed: {status:?}"), 100 | Err(e) => panic!("command failed: {e:?}"), 101 | } 102 | } 103 | } 104 | 105 | fn main() { 106 | env_logger::init(); 107 | let cli = Cli::parse(); 108 | 109 | let manifest = Manifest { 110 | verbose: cli.verbose, 111 | release: cli.release, 112 | out_dir: cli.out_dir.unwrap_or("build".to_string()).into(), 113 | }; 114 | 115 | match cli.command { 116 | Command::Test(mut test) => { 117 | test.verbose |= cli.verbose; 118 | test.run(&manifest) 119 | } 120 | Command::Clean(mut clean) => { 121 | clean.verbose |= cli.verbose; 122 | clean.run(&manifest) 123 | } 124 | Command::Rustc(mut rustc) => { 125 | rustc.verbose |= cli.verbose; 126 | rustc.run(&manifest) 127 | } 128 | Command::Fmt(mut fmt) => { 129 | fmt.verbose |= cli.verbose; 130 | fmt.run(&manifest) 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/pretty.rs: -------------------------------------------------------------------------------- 1 | //! Pretty printing support for C AST nodes. 2 | 3 | use std::borrow::Cow; 4 | 5 | use rustc_ast_pretty::pp; 6 | 7 | /// Default indentation size. 8 | pub const INDENT: isize = 2; 9 | 10 | /// Pretty printer, see [`rustc_ast_pretty::pp::Printer`] for details. 11 | pub struct PrinterCtx { 12 | pp: pp::Printer, 13 | } 14 | 15 | impl Default for PrinterCtx { 16 | fn default() -> Self { 17 | Self::new() 18 | } 19 | } 20 | 21 | impl PrinterCtx { 22 | pub fn new() -> Self { 23 | Self { pp: pp::Printer::new() } 24 | } 25 | 26 | pub fn finish(self) -> String { 27 | self.pp.eof() 28 | } 29 | 30 | pub(crate) fn seperated( 31 | &mut self, 32 | sep: &'static str, 33 | elements: &[T], 34 | mut op: impl FnMut(&mut Self, &T), 35 | ) { 36 | if let Some((first, rest)) = elements.split_first() { 37 | op(self, first); 38 | for elt in rest { 39 | self.pp.word_space(sep); 40 | op(self, elt); 41 | } 42 | } 43 | } 44 | 45 | /// Inconsistent breaking box 46 | /// 47 | /// See the module document of [`rustc_ast_pretty::pp`] for details. 48 | pub(crate) fn ibox(&mut self, indent: isize, op: impl FnOnce(&mut Self)) { 49 | self.pp.ibox(indent); 50 | op(self); 51 | self.pp.end(); 52 | } 53 | 54 | /// Inconsistent breaking box, with delimiters surrounding the inner content 55 | /// 56 | /// This is often used for printing content inside parentheses, e.g. function 57 | /// arguments. 58 | pub(crate) fn ibox_delim( 59 | &mut self, 60 | indent: isize, 61 | delim: (&'static str, &'static str), 62 | padding: usize, 63 | op: impl FnOnce(&mut Self), 64 | ) { 65 | self.ibox(indent, |this| { 66 | this.word(delim.0); 67 | this.pp.break_offset(padding, 0); 68 | op(this); 69 | this.word(delim.1); 70 | }); 71 | } 72 | 73 | /// Consistent breaking box 74 | /// 75 | /// See the module document of [`rustc_ast_pretty::pp`] for details. 76 | pub(crate) fn cbox(&mut self, indent: isize, op: impl FnOnce(&mut Self)) { 77 | self.pp.cbox(indent); 78 | op(self); 79 | self.pp.end(); 80 | } 81 | 82 | /// Consistent breaking box, with delimiters surrounding the inner content 83 | /// 84 | /// This is often used for printing content inside braces, e.g. a block of 85 | /// statements. 86 | pub(crate) fn cbox_delim( 87 | &mut self, 88 | indent: isize, 89 | delim: (&'static str, &'static str), 90 | padding: usize, 91 | op: impl FnOnce(&mut Self), 92 | ) { 93 | self.cbox(indent, |this| { 94 | this.word(delim.0); 95 | this.pp.break_offset(padding, 0); 96 | op(this); 97 | this.pp.break_offset(padding, -indent); 98 | this.word(delim.1); 99 | }); 100 | } 101 | 102 | pub(crate) fn valign(&mut self, op: impl FnOnce(&mut Self)) { 103 | self.pp.visual_align(); 104 | op(self); 105 | self.pp.end(); 106 | } 107 | 108 | pub(crate) fn valign_delim( 109 | &mut self, 110 | delim: (&'static str, &'static str), 111 | op: impl FnOnce(&mut Self), 112 | ) { 113 | self.valign(|this| { 114 | this.word(delim.0); 115 | op(this); 116 | this.word(delim.1); 117 | }); 118 | } 119 | 120 | /// Soft break: space if fits, otherwise newline 121 | pub(crate) fn softbreak(&mut self) { 122 | self.pp.space() 123 | } 124 | 125 | /// Hard break: always newline 126 | pub(crate) fn hardbreak(&mut self) { 127 | self.pp.hardbreak(); 128 | } 129 | 130 | /// Zero break: nothing if fits, otherwise newline 131 | pub(crate) fn zerobreak(&mut self) { 132 | self.pp.zerobreak(); 133 | } 134 | 135 | /// Print a string 136 | pub(crate) fn word(&mut self, s: impl Into>) { 137 | self.pp.word(s) 138 | } 139 | 140 | /// Non-breaking space, the same as `word(" ")` 141 | pub(crate) fn nbsp(&mut self) { 142 | self.pp.nbsp() 143 | } 144 | } 145 | 146 | /// Trait for a type that can be pretty printed. 147 | pub trait Print { 148 | fn print_to(&self, ctx: &mut PrinterCtx); 149 | } 150 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/expr.rs: -------------------------------------------------------------------------------- 1 | //! This module defines the AST nodes for C expressions. 2 | 3 | use crate::pretty::{Print, PrinterCtx, INDENT}; 4 | use crate::ty::{print_declarator, CTy}; 5 | use crate::ModuleCtx; 6 | 7 | /// Represents the values of C variables, parameters, and scalars. 8 | /// 9 | /// There are two variants to distinguish between constants and variables, 10 | /// as is done in LLVM IR. We follow the `rustc_codegen_ssa` convention for this representation. 11 | #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] 12 | pub enum CValue<'mx> { 13 | /// A constant scalar 14 | Scalar(i128), 15 | /// A local variable indexed by a number, in the form `_0`, `_1`, etc. 16 | Local(usize), 17 | /// A function name 18 | Func(&'mx str), 19 | } 20 | 21 | /// C expressions. 22 | pub type CExpr<'mx> = &'mx CExprKind<'mx>; 23 | 24 | /// C expressions. 25 | #[derive(Debug, Clone)] 26 | pub enum CExprKind<'mx> { 27 | /// A "raw" C expression, simply a string of C code, which is printed as-is. 28 | Raw(&'static str), 29 | /// A value, such as a constant, variable, or function name. 30 | Value(CValue<'mx>), 31 | /// A binary operation expression, e.g. `lhs + rhs`. 32 | Binary { lhs: CExpr<'mx>, rhs: CExpr<'mx>, op: &'static str }, 33 | /// A type cast expression, e.g. `(int) x`. 34 | Cast { ty: CTy<'mx>, expr: CExpr<'mx> }, 35 | /// A function call expression, e.g. `foo(x, y)`. 36 | Call { callee: CExpr<'mx>, args: Vec> }, 37 | /// A member access expression, e.g. `foo.bar` or `foo->bar`. 38 | Member { 39 | expr: CExpr<'mx>, 40 | /// Whether to use the `->` operator instead of `.`. 41 | arrow: bool, 42 | field: &'mx str, 43 | }, 44 | } 45 | 46 | impl<'mx> ModuleCtx<'mx> { 47 | /// Create a new expression. 48 | pub fn expr(&self, expr: CExprKind<'mx>) -> CExpr<'mx> { 49 | self.arena().alloc(expr) 50 | } 51 | 52 | /// Create a new raw expression. 53 | pub fn raw(&self, raw: &'static str) -> CExpr<'mx> { 54 | self.expr(CExprKind::Raw(raw)) 55 | } 56 | 57 | /// Create a new value expression. 58 | pub fn value(&self, value: CValue<'mx>) -> CExpr<'mx> { 59 | self.expr(CExprKind::Value(value)) 60 | } 61 | 62 | /// Create a new binary expression. 63 | pub fn binary(&self, lhs: CExpr<'mx>, rhs: CExpr<'mx>, op: &'static str) -> CExpr<'mx> { 64 | self.expr(CExprKind::Binary { lhs, rhs, op }) 65 | } 66 | 67 | /// Create a new cast expression. 68 | pub fn cast(&self, ty: CTy<'mx>, expr: CExpr<'mx>) -> CExpr<'mx> { 69 | self.expr(CExprKind::Cast { ty, expr }) 70 | } 71 | 72 | /// Create a new function call expression. 73 | pub fn call(&self, callee: CExpr<'mx>, args: Vec>) -> CExpr<'mx> { 74 | self.expr(CExprKind::Call { callee, args }) 75 | } 76 | 77 | /// Create a new member access expression. 78 | pub fn member(&self, expr: CExpr<'mx>, field: &'mx str) -> CExpr<'mx> { 79 | self.expr(CExprKind::Member { expr, field, arrow: false }) 80 | } 81 | } 82 | 83 | impl Print for CValue<'_> { 84 | fn print_to(&self, ctx: &mut PrinterCtx) { 85 | match self { 86 | CValue::Scalar(i) => ctx.word(i.to_string()), 87 | CValue::Local(i) => ctx.word(format!("_{}", i)), 88 | CValue::Func(name) => ctx.word(name.to_string()), 89 | } 90 | } 91 | } 92 | 93 | impl Print for CExpr<'_> { 94 | fn print_to(&self, ctx: &mut PrinterCtx) { 95 | match self { 96 | CExprKind::Raw(raw) => ctx.word(*raw), 97 | CExprKind::Value(value) => value.print_to(ctx), 98 | CExprKind::Binary { lhs, rhs, op } => ctx.ibox_delim(INDENT, ("(", ")"), 0, |ctx| { 99 | ctx.ibox(-INDENT, |ctx| lhs.print_to(ctx)); 100 | 101 | ctx.softbreak(); 102 | ctx.word(*op); 103 | ctx.nbsp(); 104 | 105 | rhs.print_to(ctx); 106 | }), 107 | CExprKind::Cast { ty, expr } => ctx.ibox(INDENT, |ctx| { 108 | ctx.word("("); 109 | print_declarator(*ty, None, ctx); 110 | ctx.word(")"); 111 | 112 | ctx.nbsp(); 113 | expr.print_to(ctx); 114 | }), 115 | CExprKind::Call { callee, args } => ctx.ibox(INDENT, |ctx| { 116 | callee.print_to(ctx); 117 | ctx.cbox_delim(INDENT, ("(", ")"), 0, |ctx| { 118 | ctx.seperated(",", args, |ctx, arg| arg.print_to(ctx)); 119 | }); 120 | }), 121 | CExprKind::Member { expr, arrow, field } => ctx.cbox(INDENT, |ctx| { 122 | expr.print_to(ctx); 123 | ctx.zerobreak(); 124 | if *arrow { 125 | ctx.word("->"); 126 | } else { 127 | ctx.word("."); 128 | } 129 | ctx.word(field.to_string()); 130 | }), 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | extern crate rustc_abi; 4 | extern crate rustc_ast; 5 | extern crate rustc_codegen_ssa; 6 | extern crate rustc_const_eval; 7 | extern crate rustc_data_structures; 8 | extern crate rustc_driver; 9 | extern crate rustc_errors; 10 | extern crate rustc_fluent_macro; 11 | extern crate rustc_hash; 12 | extern crate rustc_hir; 13 | extern crate rustc_metadata; 14 | extern crate rustc_middle; 15 | extern crate rustc_session; 16 | extern crate rustc_span; 17 | extern crate rustc_target; 18 | extern crate rustc_type_ir; 19 | extern crate tracing; 20 | 21 | use std::sync::Arc; 22 | 23 | use rustc_ast::expand::allocator::AllocatorKind; 24 | use rustc_codegen_ssa::back::link::link_binary; 25 | use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; 26 | use rustc_codegen_ssa::back::write::{ 27 | CodegenContext, FatLtoInput, ModuleConfig, OngoingCodegen, TargetMachineFactoryFn, 28 | }; 29 | use rustc_codegen_ssa::base::codegen_crate; 30 | pub use rustc_codegen_ssa::traits::CodegenBackend; 31 | use rustc_codegen_ssa::traits::{ 32 | ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods, 33 | }; 34 | use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; 35 | use rustc_data_structures::fx::FxIndexMap; 36 | use rustc_errors::{DiagCtxtHandle, FatalError}; 37 | use rustc_metadata::EncodedMetadata; 38 | use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; 39 | use rustc_middle::ty::TyCtxt; 40 | use rustc_middle::util::Providers; 41 | use rustc_session::config::{OptLevel, OutputFilenames}; 42 | use rustc_session::Session; 43 | use rustc_span::ErrorGuaranteed; 44 | 45 | mod archive; 46 | mod base; 47 | mod builder; 48 | mod context; 49 | mod write; 50 | 51 | rustc_fluent_macro::fluent_messages! { "../messages.ftl" } 52 | 53 | #[derive(Clone)] 54 | pub struct CCodegen {} 55 | 56 | impl CodegenBackend for CCodegen { 57 | fn locale_resource(&self) -> &'static str { 58 | crate::DEFAULT_LOCALE_RESOURCE 59 | } 60 | 61 | fn provide(&self, providers: &mut Providers) { 62 | providers.global_backend_features = |_tcx, ()| vec![] 63 | } 64 | 65 | fn codegen_crate( 66 | &self, 67 | tcx: TyCtxt<'_>, 68 | metadata: EncodedMetadata, 69 | need_metadata_module: bool, 70 | ) -> Box { 71 | let target_cpu = match tcx.sess.opts.cg.target_cpu { 72 | Some(ref name) => name, 73 | None => tcx.sess.target.cpu.as_ref(), 74 | } 75 | .to_owned(); 76 | 77 | let ongoing_codegen = 78 | codegen_crate(self.clone(), tcx, target_cpu, metadata, need_metadata_module); 79 | Box::new(ongoing_codegen) 80 | } 81 | 82 | fn join_codegen( 83 | &self, 84 | ongoing_codegen: Box, 85 | sess: &Session, 86 | _outputs: &OutputFilenames, 87 | ) -> (CodegenResults, FxIndexMap) { 88 | ongoing_codegen.downcast::>().expect("expected CCodegen").join(sess) 89 | } 90 | 91 | fn link( 92 | &self, 93 | sess: &Session, 94 | codegen_results: CodegenResults, 95 | outputs: &OutputFilenames, 96 | ) -> Result<(), ErrorGuaranteed> { 97 | link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs) 98 | } 99 | 100 | fn supports_parallel(&self) -> bool { 101 | false 102 | } 103 | } 104 | 105 | impl ExtraBackendMethods for CCodegen { 106 | fn codegen_allocator( 107 | &self, 108 | _tcx: TyCtxt<'_>, 109 | _module_name: &str, 110 | _kind: AllocatorKind, 111 | _alloc_error_handler_kind: AllocatorKind, 112 | ) -> Self::Module { 113 | todo!() 114 | } 115 | 116 | fn compile_codegen_unit( 117 | &self, 118 | tcx: TyCtxt<'_>, 119 | cgu_name: rustc_span::Symbol, 120 | ) -> (ModuleCodegen, u64) { 121 | base::compile_codegen_unit(tcx, cgu_name) 122 | } 123 | 124 | fn target_machine_factory( 125 | &self, 126 | _sess: &Session, 127 | _opt_level: OptLevel, 128 | _target_features: &[String], 129 | ) -> TargetMachineFactoryFn { 130 | Arc::new(|_| Ok(())) 131 | } 132 | } 133 | 134 | pub struct ModuleBuffer; 135 | 136 | impl ModuleBufferMethods for ModuleBuffer { 137 | fn data(&self) -> &[u8] { 138 | unimplemented!() 139 | } 140 | } 141 | 142 | pub struct ThinBuffer; 143 | 144 | impl ThinBufferMethods for ThinBuffer { 145 | fn data(&self) -> &[u8] { 146 | unimplemented!() 147 | } 148 | 149 | fn thin_link_data(&self) -> &[u8] { 150 | unimplemented!() 151 | } 152 | } 153 | 154 | impl WriteBackendMethods for CCodegen { 155 | type Module = String; 156 | type TargetMachine = (); 157 | type TargetMachineError = (); 158 | type ModuleBuffer = ModuleBuffer; 159 | type ThinData = (); 160 | type ThinBuffer = ThinBuffer; 161 | 162 | fn run_link( 163 | cgcx: &CodegenContext, 164 | dcx: DiagCtxtHandle<'_>, 165 | modules: Vec>, 166 | ) -> Result, FatalError> { 167 | write::link(cgcx, dcx, modules) 168 | } 169 | 170 | fn run_fat_lto( 171 | _cgcx: &CodegenContext, 172 | _modules: Vec>, 173 | _cached_modules: Vec<(SerializedModule, WorkProduct)>, 174 | ) -> Result, FatalError> { 175 | unimplemented!() 176 | } 177 | 178 | fn run_thin_lto( 179 | _cgcx: &CodegenContext, 180 | _modules: Vec<(String, Self::ThinBuffer)>, 181 | _cached_modules: Vec<( 182 | SerializedModule, 183 | rustc_middle::dep_graph::WorkProduct, 184 | )>, 185 | ) -> Result<(Vec>, Vec), rustc_errors::FatalError> { 186 | unimplemented!() 187 | } 188 | 189 | fn print_pass_timings(&self) { 190 | unimplemented!() 191 | } 192 | 193 | fn print_statistics(&self) { 194 | unimplemented!() 195 | } 196 | 197 | unsafe fn optimize( 198 | _cgcx: &CodegenContext, 199 | _dcx: DiagCtxtHandle<'_>, 200 | _module: &ModuleCodegen, 201 | _config: &ModuleConfig, 202 | ) -> Result<(), FatalError> { 203 | Ok(()) 204 | } 205 | 206 | fn optimize_fat( 207 | _cgcx: &CodegenContext, 208 | _llmod: &mut ModuleCodegen, 209 | ) -> Result<(), FatalError> { 210 | unimplemented!() 211 | } 212 | 213 | unsafe fn optimize_thin( 214 | _cgcx: &CodegenContext, 215 | _thin: ThinModule, 216 | ) -> Result, FatalError> { 217 | unimplemented!() 218 | } 219 | 220 | unsafe fn codegen( 221 | cgcx: &CodegenContext, 222 | dcx: DiagCtxtHandle<'_>, 223 | module: ModuleCodegen, 224 | config: &ModuleConfig, 225 | ) -> Result { 226 | write::codegen(cgcx, dcx, module, config) 227 | } 228 | 229 | fn prepare_thin( 230 | _module: ModuleCodegen, 231 | _want_summary: bool, 232 | ) -> (String, Self::ThinBuffer) { 233 | unimplemented!() 234 | } 235 | 236 | fn serialize_module( 237 | _module: rustc_codegen_ssa::ModuleCodegen, 238 | ) -> (String, Self::ModuleBuffer) { 239 | unimplemented!() 240 | } 241 | } 242 | 243 | /// This is the entrypoint for a hot plugged codegen backend. 244 | #[no_mangle] 245 | pub fn __rustc_codegen_backend() -> Box { 246 | Box::new(CCodegen {}) 247 | } 248 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c_ast/src/ty.rs: -------------------------------------------------------------------------------- 1 | //! This module defines the AST nodes for C types. 2 | 3 | use rustc_data_structures::intern::Interned; 4 | use rustc_type_ir::{IntTy, UintTy}; 5 | 6 | use crate::expr::CValue; 7 | use crate::pretty::{Print, PrinterCtx}; 8 | use crate::ModuleCtx; 9 | 10 | /// C types. 11 | /// 12 | /// A C type is either a primitive type or a complex type. Primitive types are 13 | /// the basic types like `int` and `char`, while complex types are types that 14 | /// are built from primitive types, like pointers and arrays. 15 | /// 16 | /// Complex types are always interned, and thus should be unique in a specific 17 | /// context. See [`CTyKind`] for more information. 18 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 19 | pub enum CTy<'mx> { 20 | /// The C `void` type. 21 | Void, 22 | /// The C boolean type. 23 | Bool, 24 | /// The C `char` type. 25 | Char, 26 | /// A signed integer type. 27 | Int(CIntTy), 28 | /// An unsigned integer type. 29 | UInt(CUintTy), 30 | /// A non-primitive C type, e.g. a pointer type. 31 | /// 32 | /// This is an interned reference to a complex type. 33 | Ref(Interned<'mx, CTyKind<'mx>>), 34 | } 35 | 36 | impl<'mx> CTy<'mx> { 37 | /// Whether the type is a signed integer. 38 | pub fn is_signed(self) -> bool { 39 | matches!(self, CTy::Int(_)) 40 | } 41 | 42 | /// The unsigned version of this type. 43 | /// 44 | /// ## Panic 45 | /// 46 | /// Panics if the type is not a signed integer. 47 | pub fn to_unsigned(self) -> Self { 48 | match self { 49 | CTy::Int(ty) => CTy::UInt(ty.to_unsigned()), 50 | _ => unreachable!(), 51 | } 52 | } 53 | 54 | /// Get the corresponding C type name. 55 | /// 56 | /// This function should be only used for primitive types. 57 | /// 58 | /// ## Panic 59 | /// 60 | /// Panics if the type is not a primitive type. 61 | pub fn to_str(self) -> &'static str { 62 | match self { 63 | CTy::Void => "void", 64 | CTy::Bool => "_Bool", 65 | CTy::Char => "char", 66 | CTy::Int(ty) => ty.to_str(), 67 | CTy::UInt(ty) => ty.to_str(), 68 | CTy::Ref(_) => unreachable!(), 69 | } 70 | } 71 | 72 | /// The maximum value of this type. From ``. 73 | /// 74 | /// This function should be only used for integer types (signed or unsigned). 75 | /// 76 | /// ## Panic 77 | /// 78 | /// Panics if the type is not an integer type. 79 | pub fn max_value(self) -> &'static str { 80 | match self { 81 | CTy::Int(ty) => ty.max_value(), 82 | CTy::UInt(ty) => ty.max_value(), 83 | _ => unreachable!(), 84 | } 85 | } 86 | 87 | pub fn is_primitive(&self) -> bool { 88 | matches!(self, CTy::Void | CTy::Bool | CTy::Char | CTy::Int(_) | CTy::UInt(_)) 89 | } 90 | pub fn is_array(&self) -> bool { 91 | matches!(self, CTy::Ref(Interned(CTyKind::Array(_, _), _))) 92 | } 93 | } 94 | 95 | /// C primitive types. 96 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 97 | pub enum CIntTy { 98 | Isize, 99 | I8, 100 | I16, 101 | I32, 102 | I64, 103 | } 104 | 105 | impl CIntTy { 106 | /// Get the unsigned version of this type. 107 | pub fn to_unsigned(self) -> CUintTy { 108 | match self { 109 | CIntTy::Isize => CUintTy::Usize, 110 | CIntTy::I8 => CUintTy::U8, 111 | CIntTy::I16 => CUintTy::U16, 112 | CIntTy::I32 => CUintTy::U32, 113 | CIntTy::I64 => CUintTy::U64, 114 | } 115 | } 116 | 117 | /// Get the corresponding C type name. 118 | pub fn to_str(self) -> &'static str { 119 | match self { 120 | CIntTy::Isize => "size_t", 121 | CIntTy::I8 => "int8_t", 122 | CIntTy::I16 => "int16_t", 123 | CIntTy::I32 => "int32_t", 124 | CIntTy::I64 => "int64_t", 125 | } 126 | } 127 | 128 | /// The maximum value of this type. From ``. 129 | pub fn max_value(self) -> &'static str { 130 | match self { 131 | CIntTy::Isize => "SIZE_MAX", 132 | CIntTy::I8 => "INT8_MAX", 133 | CIntTy::I16 => "INT16_MAX", 134 | CIntTy::I32 => "INT32_MAX", 135 | CIntTy::I64 => "INT64_MAX", 136 | } 137 | } 138 | } 139 | 140 | /// C primitive types. 141 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 142 | pub enum CUintTy { 143 | Usize, 144 | U8, 145 | U16, 146 | U32, 147 | U64, 148 | } 149 | 150 | impl CUintTy { 151 | /// Get the corresponding C type name. 152 | pub fn to_str(self) -> &'static str { 153 | match self { 154 | CUintTy::Usize => "size_t", 155 | CUintTy::U8 => "uint8_t", 156 | CUintTy::U16 => "uint16_t", 157 | CUintTy::U32 => "uint32_t", 158 | CUintTy::U64 => "uint64_t", 159 | } 160 | } 161 | 162 | /// The maximum value of this type. From ``. 163 | pub fn max_value(self) -> &'static str { 164 | match self { 165 | CUintTy::Usize => "SIZE_MAX", 166 | CUintTy::U8 => "UINT8_MAX", 167 | CUintTy::U16 => "UINT16_MAX", 168 | CUintTy::U32 => "UINT32_MAX", 169 | CUintTy::U64 => "UINT64_MAX", 170 | } 171 | } 172 | } 173 | 174 | /// Complex C types, e.g. pointers and arrays. 175 | /// 176 | /// This type is interned, and thus should be unique in a specific context. 177 | #[derive(Clone, Debug, PartialEq, Eq)] 178 | pub enum CTyKind<'mx> { 179 | /// A pointer type. 180 | Pointer(CTy<'mx>), 181 | /// An array type with element type and size. 182 | Array(CTy<'mx>, usize), 183 | } 184 | 185 | impl<'mx> ModuleCtx<'mx> { 186 | /// Get the type of an signed integer 187 | pub fn get_int_type(&self, int: IntTy) -> CTy<'mx> { 188 | match int { 189 | IntTy::Isize => CTy::Int(CIntTy::Isize), 190 | IntTy::I8 => CTy::Int(CIntTy::I8), 191 | IntTy::I16 => CTy::Int(CIntTy::I16), 192 | IntTy::I32 => CTy::Int(CIntTy::I32), 193 | IntTy::I64 => CTy::Int(CIntTy::I64), 194 | IntTy::I128 => unimplemented!("i128 not supported yet"), 195 | } 196 | } 197 | 198 | /// Get the type of an unsigned integer 199 | pub fn get_uint_type(&self, uint: UintTy) -> CTy<'mx> { 200 | match uint { 201 | UintTy::Usize => CTy::UInt(CUintTy::Usize), 202 | UintTy::U8 => CTy::UInt(CUintTy::U8), 203 | UintTy::U16 => CTy::UInt(CUintTy::U16), 204 | UintTy::U32 => CTy::UInt(CUintTy::U32), 205 | UintTy::U64 => CTy::UInt(CUintTy::U64), 206 | UintTy::U128 => unimplemented!("u128 not supported yet"), 207 | } 208 | } 209 | } 210 | 211 | /// Print a C declarator. 212 | /// 213 | /// A declarator is a type with an optional identifier and pointer indirections, 214 | /// e.g. `int *x`. 215 | /// 216 | /// This function is necessary because the C declarator syntax is quite complex 217 | /// when the type becomes more complex, e.g. `int (*x)[10]`. 218 | /// 219 | /// When `val` is `None`, this prints an abstract declarator, or in other words, 220 | /// a standalone type without an identifier. 221 | pub(crate) fn print_declarator(mut ty: CTy, val: Option, ctx: &mut PrinterCtx) { 222 | enum DeclaratorPart<'mx> { 223 | Ident(CValue<'mx>), 224 | Ptr, 225 | ArrayDim(usize), 226 | Lp, 227 | Rp, 228 | } 229 | 230 | impl Print for DeclaratorPart<'_> { 231 | fn print_to(&self, ctx: &mut PrinterCtx) { 232 | match self { 233 | DeclaratorPart::Ident(val) => { 234 | val.print_to(ctx); 235 | } 236 | DeclaratorPart::Ptr => { 237 | ctx.word("*"); 238 | } 239 | DeclaratorPart::ArrayDim(dim) => { 240 | ctx.word(format!("[{}]", dim)); 241 | } 242 | DeclaratorPart::Lp => ctx.word("("), 243 | DeclaratorPart::Rp => ctx.word(")"), 244 | } 245 | } 246 | } 247 | 248 | let mut decl_parts = std::collections::VecDeque::new(); 249 | if let Some(val) = val { 250 | decl_parts.push_front(DeclaratorPart::Ident(val)); 251 | } 252 | while let CTy::Ref(kind) = ty { 253 | match kind.0 { 254 | CTyKind::Pointer(ty) => { 255 | decl_parts.push_front(DeclaratorPart::Ptr); 256 | if ty.is_array() { 257 | decl_parts.push_front(DeclaratorPart::Lp); 258 | decl_parts.push_back(DeclaratorPart::Rp); 259 | } 260 | } 261 | CTyKind::Array(_, dim) => decl_parts.push_back(DeclaratorPart::ArrayDim(*dim)), 262 | } 263 | ty = match kind.0 { 264 | CTyKind::Pointer(ty) => *ty, 265 | CTyKind::Array(ty, _) => *ty, 266 | }; 267 | } 268 | 269 | ctx.word(ty.to_str()); // `ty` should be a primitive type here 270 | if val.is_some() || !decl_parts.is_empty() { 271 | ctx.nbsp(); 272 | } 273 | for part in decl_parts { 274 | part.print_to(ctx); 275 | } 276 | } 277 | 278 | #[cfg(test)] 279 | mod tests { 280 | use super::*; 281 | use crate::expr::CValue; 282 | use rustc_data_structures::intern::Interned; 283 | 284 | fn setup_printer_ctx() -> PrinterCtx { 285 | PrinterCtx::new() 286 | } 287 | 288 | #[test] 289 | fn test_print_declarator_primitive() { 290 | let mut ctx = setup_printer_ctx(); 291 | // Test void type without identifier 292 | print_declarator(CTy::Void, None, &mut ctx); 293 | assert_eq!(ctx.finish(), "void"); 294 | 295 | // Test int type with identifier 296 | ctx = setup_printer_ctx(); 297 | let val = CValue::Local(0); 298 | print_declarator(CTy::Int(CIntTy::I32), Some(val), &mut ctx); 299 | assert_eq!(ctx.finish(), "int32_t _0"); 300 | } 301 | 302 | #[test] 303 | fn test_print_declarator_pointer() { 304 | let mut ctx = setup_printer_ctx(); 305 | // Test pointer type without identifier 306 | let ptr_kind = CTyKind::Pointer(CTy::Int(CIntTy::I32)); 307 | let ptr_type = CTy::Ref(Interned::new_unchecked(&ptr_kind)); 308 | print_declarator(ptr_type, None, &mut ctx); 309 | assert_eq!(ctx.finish(), "int32_t *"); 310 | 311 | // Test pointer type with identifier 312 | ctx = setup_printer_ctx(); 313 | let val = CValue::Local(1); 314 | print_declarator(ptr_type, Some(val), &mut ctx); 315 | assert_eq!(ctx.finish(), "int32_t *_1"); 316 | 317 | // Test multi-level pointer type 318 | ctx = setup_printer_ctx(); 319 | let ptr2_kind = CTyKind::Pointer(ptr_type); 320 | let ptr2_type = CTy::Ref(Interned::new_unchecked(&ptr2_kind)); 321 | print_declarator(ptr2_type, None, &mut ctx); 322 | assert_eq!(ctx.finish(), "int32_t **"); 323 | 324 | // Test multi-level pointer type with identifier 325 | ctx = setup_printer_ctx(); 326 | let val = CValue::Local(2); 327 | print_declarator(ptr2_type, Some(val), &mut ctx); 328 | assert_eq!(ctx.finish(), "int32_t **_2"); 329 | } 330 | 331 | #[test] 332 | fn test_print_declarator_array() { 333 | let mut ctx = setup_printer_ctx(); 334 | // Test array type without identifier 335 | let i32_ty = CTy::Int(CIntTy::I32); 336 | let array_kind = CTyKind::Array(i32_ty, 10); 337 | let array_type = CTy::Ref(Interned::new_unchecked(&array_kind)); 338 | print_declarator(array_type, None, &mut ctx); 339 | assert_eq!(ctx.finish(), "int32_t [10]"); 340 | 341 | // Test array type with identifier 342 | ctx = setup_printer_ctx(); 343 | let val = CValue::Local(2); 344 | print_declarator(array_type, Some(val), &mut ctx); 345 | assert_eq!(ctx.finish(), "int32_t _2[10]"); 346 | } 347 | 348 | #[test] 349 | fn test_print_declarator_complex() { 350 | let mut ctx = setup_printer_ctx(); 351 | // Test pointer to array 352 | let array_kind = CTyKind::Array(CTy::Int(CIntTy::I32), 10); 353 | let array_type = CTy::Ref(Interned::new_unchecked(&array_kind)); 354 | let ptr_kind = CTyKind::Pointer(array_type); 355 | let ptr_type = CTy::Ref(Interned::new_unchecked(&ptr_kind)); 356 | let val = CValue::Local(3); 357 | print_declarator(ptr_type, Some(val), &mut ctx); 358 | assert_eq!(ctx.finish(), "int32_t (*_3)[10]"); 359 | 360 | // Test array of pointers to array 361 | ctx = setup_printer_ctx(); 362 | let inner_array_kind = CTyKind::Array(CTy::Int(CIntTy::I32), 5); 363 | let inner_array_type = CTy::Ref(Interned::new_unchecked(&inner_array_kind)); 364 | let ptr_to_array_kind = CTyKind::Pointer(inner_array_type); 365 | let ptr_to_array_type = CTy::Ref(Interned::new_unchecked(&ptr_to_array_kind)); 366 | let array_of_ptrs_kind = CTyKind::Array(ptr_to_array_type, 3); 367 | let array_of_ptrs_type = CTy::Ref(Interned::new_unchecked(&array_of_ptrs_kind)); 368 | let val = CValue::Local(4); 369 | print_declarator(array_of_ptrs_type, Some(val), &mut ctx); 370 | assert_eq!(ctx.finish(), "int32_t (*_4[3])[5]"); 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /bootstrap/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anstream" 16 | version = "0.6.14" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 19 | dependencies = [ 20 | "anstyle", 21 | "anstyle-parse", 22 | "anstyle-query", 23 | "anstyle-wincon", 24 | "colorchoice", 25 | "is_terminal_polyfill", 26 | "utf8parse", 27 | ] 28 | 29 | [[package]] 30 | name = "anstyle" 31 | version = "1.0.7" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 34 | 35 | [[package]] 36 | name = "anstyle-parse" 37 | version = "0.2.4" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 40 | dependencies = [ 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-query" 46 | version = "1.1.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" 49 | dependencies = [ 50 | "windows-sys", 51 | ] 52 | 53 | [[package]] 54 | name = "anstyle-wincon" 55 | version = "3.0.3" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 58 | dependencies = [ 59 | "anstyle", 60 | "windows-sys", 61 | ] 62 | 63 | [[package]] 64 | name = "bitflags" 65 | version = "2.6.0" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 68 | 69 | [[package]] 70 | name = "clap" 71 | version = "4.5.9" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" 74 | dependencies = [ 75 | "clap_builder", 76 | "clap_derive", 77 | ] 78 | 79 | [[package]] 80 | name = "clap_builder" 81 | version = "4.5.9" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" 84 | dependencies = [ 85 | "anstream", 86 | "anstyle", 87 | "clap_lex", 88 | "strsim", 89 | ] 90 | 91 | [[package]] 92 | name = "clap_derive" 93 | version = "4.5.8" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" 96 | dependencies = [ 97 | "heck", 98 | "proc-macro2", 99 | "quote", 100 | "syn", 101 | ] 102 | 103 | [[package]] 104 | name = "clap_lex" 105 | version = "0.7.1" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" 108 | 109 | [[package]] 110 | name = "color-print" 111 | version = "0.3.6" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" 114 | dependencies = [ 115 | "color-print-proc-macro", 116 | ] 117 | 118 | [[package]] 119 | name = "color-print-proc-macro" 120 | version = "0.3.6" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" 123 | dependencies = [ 124 | "nom", 125 | "proc-macro2", 126 | "quote", 127 | "syn", 128 | ] 129 | 130 | [[package]] 131 | name = "colorchoice" 132 | version = "1.0.1" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 135 | 136 | [[package]] 137 | name = "either" 138 | version = "1.13.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 141 | 142 | [[package]] 143 | name = "env_filter" 144 | version = "0.1.2" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" 147 | dependencies = [ 148 | "log", 149 | "regex", 150 | ] 151 | 152 | [[package]] 153 | name = "env_logger" 154 | version = "0.11.5" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" 157 | dependencies = [ 158 | "anstream", 159 | "anstyle", 160 | "env_filter", 161 | "humantime", 162 | "log", 163 | ] 164 | 165 | [[package]] 166 | name = "errno" 167 | version = "0.3.9" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 170 | dependencies = [ 171 | "libc", 172 | "windows-sys", 173 | ] 174 | 175 | [[package]] 176 | name = "glob" 177 | version = "0.3.1" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 180 | 181 | [[package]] 182 | name = "heck" 183 | version = "0.5.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 186 | 187 | [[package]] 188 | name = "home" 189 | version = "0.5.9" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 192 | dependencies = [ 193 | "windows-sys", 194 | ] 195 | 196 | [[package]] 197 | name = "humantime" 198 | version = "2.1.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 201 | 202 | [[package]] 203 | name = "is_terminal_polyfill" 204 | version = "1.70.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 207 | 208 | [[package]] 209 | name = "libc" 210 | version = "0.2.155" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 213 | 214 | [[package]] 215 | name = "linux-raw-sys" 216 | version = "0.4.14" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 219 | 220 | [[package]] 221 | name = "log" 222 | version = "0.4.22" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 225 | 226 | [[package]] 227 | name = "memchr" 228 | version = "2.7.4" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 231 | 232 | [[package]] 233 | name = "minimal-lexical" 234 | version = "0.2.1" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 237 | 238 | [[package]] 239 | name = "nom" 240 | version = "7.1.3" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 243 | dependencies = [ 244 | "memchr", 245 | "minimal-lexical", 246 | ] 247 | 248 | [[package]] 249 | name = "proc-macro2" 250 | version = "1.0.86" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 253 | dependencies = [ 254 | "unicode-ident", 255 | ] 256 | 257 | [[package]] 258 | name = "quote" 259 | version = "1.0.36" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 262 | dependencies = [ 263 | "proc-macro2", 264 | ] 265 | 266 | [[package]] 267 | name = "regex" 268 | version = "1.11.1" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 271 | dependencies = [ 272 | "aho-corasick", 273 | "memchr", 274 | "regex-automata", 275 | "regex-syntax", 276 | ] 277 | 278 | [[package]] 279 | name = "regex-automata" 280 | version = "0.4.8" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 283 | dependencies = [ 284 | "aho-corasick", 285 | "memchr", 286 | "regex-syntax", 287 | ] 288 | 289 | [[package]] 290 | name = "regex-syntax" 291 | version = "0.8.5" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 294 | 295 | [[package]] 296 | name = "rustix" 297 | version = "0.38.34" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 300 | dependencies = [ 301 | "bitflags", 302 | "errno", 303 | "libc", 304 | "linux-raw-sys", 305 | "windows-sys", 306 | ] 307 | 308 | [[package]] 309 | name = "similar" 310 | version = "2.6.0" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" 313 | 314 | [[package]] 315 | name = "strsim" 316 | version = "0.11.1" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 319 | 320 | [[package]] 321 | name = "syn" 322 | version = "2.0.71" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" 325 | dependencies = [ 326 | "proc-macro2", 327 | "quote", 328 | "unicode-ident", 329 | ] 330 | 331 | [[package]] 332 | name = "unicode-ident" 333 | version = "1.0.12" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 336 | 337 | [[package]] 338 | name = "utf8parse" 339 | version = "0.2.2" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 342 | 343 | [[package]] 344 | name = "which" 345 | version = "6.0.1" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" 348 | dependencies = [ 349 | "either", 350 | "home", 351 | "rustix", 352 | "winsafe", 353 | ] 354 | 355 | [[package]] 356 | name = "windows-sys" 357 | version = "0.52.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 360 | dependencies = [ 361 | "windows-targets", 362 | ] 363 | 364 | [[package]] 365 | name = "windows-targets" 366 | version = "0.52.6" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 369 | dependencies = [ 370 | "windows_aarch64_gnullvm", 371 | "windows_aarch64_msvc", 372 | "windows_i686_gnu", 373 | "windows_i686_gnullvm", 374 | "windows_i686_msvc", 375 | "windows_x86_64_gnu", 376 | "windows_x86_64_gnullvm", 377 | "windows_x86_64_msvc", 378 | ] 379 | 380 | [[package]] 381 | name = "windows_aarch64_gnullvm" 382 | version = "0.52.6" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 385 | 386 | [[package]] 387 | name = "windows_aarch64_msvc" 388 | version = "0.52.6" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 391 | 392 | [[package]] 393 | name = "windows_i686_gnu" 394 | version = "0.52.6" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 397 | 398 | [[package]] 399 | name = "windows_i686_gnullvm" 400 | version = "0.52.6" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 403 | 404 | [[package]] 405 | name = "windows_i686_msvc" 406 | version = "0.52.6" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 409 | 410 | [[package]] 411 | name = "windows_x86_64_gnu" 412 | version = "0.52.6" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 415 | 416 | [[package]] 417 | name = "windows_x86_64_gnullvm" 418 | version = "0.52.6" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 421 | 422 | [[package]] 423 | name = "windows_x86_64_msvc" 424 | version = "0.52.6" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 427 | 428 | [[package]] 429 | name = "winsafe" 430 | version = "0.0.19" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" 433 | 434 | [[package]] 435 | name = "y" 436 | version = "0.0.0" 437 | dependencies = [ 438 | "anstream", 439 | "clap", 440 | "color-print", 441 | "env_logger", 442 | "glob", 443 | "log", 444 | "regex", 445 | "similar", 446 | "which", 447 | ] 448 | -------------------------------------------------------------------------------- /bootstrap/src/test.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::path::{Path, PathBuf}; 3 | 4 | use anstream::{eprint as print, eprintln as println}; 5 | use clap::Args; 6 | use color_print::{cprint, cprintln}; 7 | use glob::glob; 8 | use similar::{ChangeTag, TextDiff}; 9 | use which::which; 10 | 11 | use crate::manifest::Manifest; 12 | use crate::Run; 13 | 14 | /// Run tests 15 | #[derive(Args, Debug)] 16 | pub struct TestCommand { 17 | /// Update the blessed output 18 | #[arg(long)] 19 | pub bless: bool, 20 | 21 | /// Whether to show verbose output 22 | #[arg(short, long)] 23 | pub verbose: bool, 24 | } 25 | 26 | impl Run for TestCommand { 27 | const STEP_DISPLAY_NAME: &'static str = "TEST"; 28 | 29 | fn run(&self, manifest: &Manifest) { 30 | manifest.prepare(); 31 | 32 | std::panic::set_hook(Box::new(|info| { 33 | cprintln!("Test failed: {}", info); 34 | })); 35 | 36 | // action: Run cargo test 37 | self.log_action_start("running", "cargo test"); 38 | let mut command = std::process::Command::new("cargo"); 39 | command.args(["test", "--manifest-path", "crates/Cargo.toml"]); 40 | self.command_status("cargo", &mut command); 41 | 42 | let testcases = self.collect_testcases(manifest); 43 | self.log_action_start(&format!("found {} testcases", testcases.len()), ""); 44 | testcases.iter().for_each(|t| self.log_action_context(t.test.as_str(), t.name.as_str())); 45 | 46 | let filechecker = FileChecker::new(self.verbose); 47 | for testcase in testcases { 48 | match testcase.test { 49 | TestType::FileCheck => { 50 | self.log_action_start("TEST file checking", &testcase.name); 51 | self.log_action_context("source", &testcase.source.display()); 52 | self.log_action_context("output", &testcase.output_file.display()); 53 | testcase.build(manifest); 54 | filechecker.check_testcase(&testcase); 55 | } 56 | TestType::Bless => { 57 | self.log_action_start("TEST Bless", &testcase.name); 58 | self.log_action_context("source", &testcase.source.display()); 59 | self.log_action_context("output", &testcase.output_file.display()); 60 | testcase.build(manifest); 61 | self.bless(self.bless, &testcase); 62 | } 63 | TestType::Compile => { 64 | self.log_action_start("TEST Compile", &testcase.name); 65 | self.log_action_context("source", &testcase.source.display()); 66 | self.log_action_context("output", &testcase.output_file.display()); 67 | testcase.build(manifest); 68 | } 69 | TestType::CompileLib => { 70 | self.log_action_start("TEST CompileLib", &testcase.name); 71 | self.log_action_context("source", &testcase.source.display()); 72 | self.log_action_context("output", &testcase.output_file.display()); 73 | testcase.build_lib(manifest); 74 | } 75 | } 76 | self.check_and_run_directives(&testcase); 77 | } 78 | } 79 | 80 | fn verbose(&self) -> bool { 81 | self.verbose 82 | } 83 | } 84 | 85 | impl TestCommand { 86 | pub fn collect_testcases(&self, manifest: &Manifest) -> Vec { 87 | let mut cases = vec![]; 88 | let verbose = self.verbose; 89 | 90 | // Examples 91 | for case in glob("examples/*.rs").unwrap() { 92 | let case = case.unwrap(); 93 | let filename = case.file_stem().unwrap(); 94 | let name = format!("examples/{}", filename.to_string_lossy()); 95 | let output_file = manifest.out_dir.join("examples").join(filename); 96 | let testcase = TestCase::new(name, case, output_file, TestType::Compile, verbose); 97 | cases.push(testcase); 98 | } 99 | 100 | // Codegen tests 101 | for case in glob("tests/codegen/*.rs").unwrap() { 102 | let case = case.unwrap(); 103 | let filename = case.file_stem().unwrap(); 104 | let name = format!("codegen/{}", filename.to_string_lossy()); 105 | let output_file = manifest.out_dir.join("tests/codegen").join(filename); 106 | let testcase = TestCase::new(name, case, output_file, TestType::FileCheck, verbose); 107 | cases.push(testcase); 108 | } 109 | 110 | // Bless tests 111 | for case in glob("tests/bless/*.rs").unwrap() { 112 | let case = case.unwrap(); 113 | let filename = case.file_stem().unwrap(); 114 | let name = format!("bless/{}", filename.to_string_lossy()); 115 | let output_file = manifest.out_dir.join("tests/bless").join(filename); 116 | let testcase = TestCase::new(name, case, output_file, TestType::Bless, verbose); 117 | cases.push(testcase); 118 | } 119 | 120 | // Collect and process auxiliary builds from directives 121 | let mut auxiliaries = vec![]; 122 | for case in cases.iter() { 123 | let directives = case.parse_directives(); 124 | for directive in directives { 125 | if let TestDirective::AuxBuild(fname) = directive { 126 | let source = Path::new("tests/auxiliary").join(&fname); 127 | let filename = source.file_stem().unwrap(); 128 | let name = format!("auxiliary/{}", filename.to_string_lossy()); 129 | 130 | // deduplication 131 | if auxiliaries.iter().any(|aux: &TestCase| aux.name == name) { 132 | continue; 133 | } 134 | 135 | let output_file = manifest.out_dir.join(filename); // aux files are output to the base directory 136 | let testcase = 137 | TestCase::new(name, source, output_file, TestType::CompileLib, verbose); 138 | auxiliaries.push(testcase); 139 | } 140 | } 141 | } 142 | 143 | // Compile auxiliary before the tests 144 | let mut testcases = auxiliaries; 145 | testcases.extend(cases); 146 | testcases 147 | } 148 | 149 | fn bless(&self, update: bool, case: &TestCase) { 150 | let output = case.generated(); 151 | let blessed = case.source.with_extension("c"); 152 | 153 | self.log_action_context("checking", &blessed.display()); 154 | if update { 155 | self.log_action_context("updating", &blessed.display()); 156 | std::fs::copy(output, &blessed).unwrap(); 157 | self.log_action_context("result", "updated"); 158 | } else { 159 | let output = std::fs::read_to_string(output).unwrap(); 160 | let blessed = std::fs::read_to_string(&blessed).unwrap(); 161 | 162 | let diff = TextDiff::from_lines(&blessed, &output); 163 | if diff.ratio() < 1.0 { 164 | cprintln!("output does not match blessed output"); 165 | for change in diff.iter_all_changes() { 166 | let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0)); 167 | match change.tag() { 168 | ChangeTag::Equal => print!(" {:4}| {}", lineno, change), 169 | ChangeTag::Insert => cprint!("+{:4}| {}", lineno, change), 170 | ChangeTag::Delete => cprint!("-{:4}| {}", lineno, change), 171 | } 172 | } 173 | std::process::exit(1); 174 | } 175 | self.log_action_context("result", "passed"); 176 | } 177 | } 178 | 179 | /// Run a runtime test and check its output against directives 180 | fn check_and_run_directives(&self, testcase: &TestCase) { 181 | // Parse directives from source 182 | let directives = testcase.parse_directives(); 183 | self.log_action_context("directives", &format!("found {} directives", directives.len())); 184 | 185 | let mut runpass = false; 186 | let mut exitcode = None; 187 | let mut stdout = None; 188 | let mut stderr = None; 189 | 190 | // Check each directive 191 | for directive in directives { 192 | match directive { 193 | TestDirective::RunPass => runpass = true, 194 | TestDirective::CheckStdout(expected) => stdout = Some(expected), 195 | TestDirective::CheckStderr(expected) => stderr = Some(expected), 196 | TestDirective::ExitCode(expected) => exitcode = Some(expected), 197 | TestDirective::AuxBuild(_) => { 198 | // AuxBuild directives are handled during test collection 199 | // No need to check them during test execution 200 | } 201 | } 202 | } 203 | 204 | if !runpass && (exitcode.is_some() | stdout.is_some() | stderr.is_some()) { 205 | panic!("Directives conflicts, lack of '//@ run-pass'"); 206 | } 207 | 208 | if runpass { 209 | self.run_and_check_output(testcase, exitcode, stdout, stderr); 210 | } 211 | 212 | self.log_action_context("result", "all checks passed"); 213 | } 214 | 215 | fn run_and_check_output( 216 | &self, 217 | testcase: &TestCase, 218 | expected_exit: Option, 219 | expected_stdout: Option, 220 | expected_stderr: Option, 221 | ) { 222 | // Run the test 223 | self.log_action_context("running", &testcase.output_file.display()); 224 | let output = std::process::Command::new(&testcase.output_file) 225 | .output() 226 | .unwrap_or_else(|e| panic!("failed to run {}: {}", testcase.output_file.display(), e)); 227 | 228 | // Get actual outputs 229 | let actual_return = output.status.code().unwrap_or_else(|| { 230 | panic!("Process terminated by signal: {}", testcase.output_file.display()) 231 | }); 232 | let actual_stdout = String::from_utf8_lossy(&output.stdout).into_owned(); 233 | let actual_stderr = String::from_utf8_lossy(&output.stderr).into_owned(); 234 | 235 | { 236 | let expected_exit = expected_exit.unwrap_or(0); 237 | self.log_action_context("checking exit code", &expected_exit.to_string()); 238 | if actual_return != expected_exit { 239 | cprintln!("exit code does not match expected value"); 240 | cprintln!("expected: {}", expected_exit); 241 | cprintln!("actual: {}", actual_return); 242 | std::process::exit(1); 243 | } 244 | self.log_action_context("exit code", "passed"); 245 | } 246 | 247 | if let Some(expected_stdout) = expected_stdout { 248 | self.log_action_context("checking stdout", &expected_stdout); 249 | let diff = TextDiff::from_lines(&expected_stdout, &actual_stdout); 250 | if diff.ratio() < 1.0 { 251 | cprintln!("stdout does not match expected output"); 252 | for change in diff.iter_all_changes() { 253 | let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0)); 254 | match change.tag() { 255 | ChangeTag::Equal => print!(" {:4}| {}", lineno, change), 256 | ChangeTag::Insert => cprint!("+{:4}| {}", lineno, change), 257 | ChangeTag::Delete => cprint!("-{:4}| {}", lineno, change), 258 | } 259 | } 260 | std::process::exit(1); 261 | } 262 | self.log_action_context("stdout", "passed"); 263 | } 264 | 265 | if let Some(expected_stderr) = expected_stderr { 266 | self.log_action_context("checking stderr", &expected_stderr); 267 | let diff = TextDiff::from_lines(&expected_stderr, &actual_stderr); 268 | if diff.ratio() < 1.0 { 269 | cprintln!("stderr does not match expected output"); 270 | for change in diff.iter_all_changes() { 271 | let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0)); 272 | match change.tag() { 273 | ChangeTag::Equal => print!(" {:4}| {}", lineno, change), 274 | ChangeTag::Insert => cprint!("+{:4}| {}", lineno, change), 275 | ChangeTag::Delete => cprint!("-{:4}| {}", lineno, change), 276 | } 277 | } 278 | std::process::exit(1); 279 | } 280 | self.log_action_context("stderr", "passed"); 281 | } 282 | } 283 | } 284 | 285 | #[derive(Debug)] 286 | pub enum TestType { 287 | /// Test an executable can be compiled 288 | Compile, 289 | /// Test a library can be compiled 290 | CompileLib, 291 | /// Run LLVM FileCheck on the generated code 292 | FileCheck, 293 | /// Bless test - the output should be the same as the last run 294 | Bless, 295 | } 296 | 297 | impl TestType { 298 | pub fn as_str(&self) -> &'static str { 299 | match self { 300 | TestType::Compile => "compile", 301 | TestType::CompileLib => "compile-lib", 302 | TestType::FileCheck => "filecheck", 303 | TestType::Bless => "bless", 304 | } 305 | } 306 | } 307 | 308 | pub struct TestCase { 309 | pub name: String, 310 | pub source: PathBuf, 311 | pub output_file: PathBuf, 312 | pub test: TestType, 313 | pub verbose: bool, 314 | } 315 | 316 | impl Run for TestCase { 317 | const STEP_DISPLAY_NAME: &'static str = "TESTCASE"; 318 | fn run(&self, manifest: &Manifest) { 319 | self.build(manifest); 320 | } 321 | 322 | fn verbose(&self) -> bool { 323 | self.verbose 324 | } 325 | } 326 | 327 | impl TestCase { 328 | pub fn new( 329 | name: String, 330 | source: PathBuf, 331 | output_file: PathBuf, 332 | test: TestType, 333 | verbose: bool, 334 | ) -> Self { 335 | Self { name, source, output_file, test, verbose } 336 | } 337 | 338 | pub fn build(&self, manifest: &Manifest) { 339 | let output_dir = self.output_file.parent().unwrap(); 340 | std::fs::create_dir_all(output_dir).unwrap(); 341 | let mut command = manifest.rustc(); 342 | command 343 | .args(["--crate-type", "bin"]) 344 | .arg("-O") 345 | .arg(&self.source) 346 | .arg("-o") 347 | .arg(&self.output_file); 348 | self.command_status("compile", &mut command); 349 | } 350 | 351 | pub fn build_lib(&self, manifest: &Manifest) { 352 | let output_dir = self.output_file.parent().unwrap(); 353 | std::fs::create_dir_all(output_dir).unwrap(); 354 | let mut command = manifest.rustc(); 355 | command 356 | .args(["--crate-type", "lib"]) 357 | .arg("-O") 358 | .arg(&self.source) 359 | .arg("--out-dir") 360 | .arg(output_dir); 361 | self.command_status("compile lib", &mut command); 362 | } 363 | 364 | /// Get the generated C file f 365 | pub fn generated(&self) -> PathBuf { 366 | let case = self.source.file_stem().unwrap().to_string_lossy(); 367 | let generated = std::fs::read_dir(self.output_file.parent().unwrap()) 368 | .unwrap() 369 | .filter_map(|entry| entry.ok()) 370 | .find(|entry| { 371 | let filename = entry.file_name(); 372 | let filename = filename.to_string_lossy(); 373 | filename.ends_with(".c") && filename.starts_with(case.as_ref()) 374 | }); 375 | 376 | assert!(generated.is_some(), "could not find {case}'s generated file"); 377 | generated.unwrap().path() 378 | } 379 | 380 | /// Parse test directives from the source file 381 | fn parse_directives(&self) -> Vec { 382 | let source = std::fs::read_to_string(&self.source) 383 | .unwrap_or_else(|e| panic!("failed to read {}: {}", self.source.display(), e)); 384 | 385 | let mut directives = Vec::new(); 386 | 387 | // Regular expressions for matching directives 388 | let run_pass = regex::Regex::new(r"^//@\s*run-pass").unwrap(); 389 | let stdout_re = regex::Regex::new(r"^//@\s*check-stdout:\s*(.*)").unwrap(); 390 | let stderr_re = regex::Regex::new(r"^//@\s*check-stderr:\s*(.*)").unwrap(); 391 | let exit_re = regex::Regex::new(r"^//@\s*exit-code:\s*(\d+)").unwrap(); 392 | let aux_re = regex::Regex::new(r"^//@\s*aux-build:\s*(.*)").unwrap(); 393 | // Regex to match any directive pattern 394 | let directive_re = regex::Regex::new(r"^//@\s*([^:]+)").unwrap(); 395 | 396 | for (line_num, line) in source.lines().enumerate() { 397 | if let Some(_cap) = run_pass.captures(line) { 398 | directives.push(TestDirective::RunPass); 399 | } else if let Some(cap) = stdout_re.captures(line) { 400 | let content = cap[1].trim().to_string(); 401 | directives.push(TestDirective::CheckStdout(content)); 402 | } else if let Some(cap) = stderr_re.captures(line) { 403 | let content = cap[1].trim().to_string(); 404 | directives.push(TestDirective::CheckStderr(content)); 405 | } else if let Some(cap) = exit_re.captures(line) { 406 | if let Ok(code) = cap[1].parse() { 407 | directives.push(TestDirective::ExitCode(code)); 408 | } else { 409 | panic!( 410 | "{}:{}: invalid exit code in directive", 411 | self.source.display(), 412 | line_num + 1 413 | ); 414 | } 415 | } else if let Some(cap) = aux_re.captures(line) { 416 | let fname = cap[1].trim().to_string(); 417 | directives.push(TestDirective::AuxBuild(fname)); 418 | } else if let Some(cap) = directive_re.captures(line) { 419 | let directive_name = cap[1].trim(); 420 | panic!( 421 | "{}:{}: unknown directive '{}', supported directives are: check-stdout, check-stderr, exit-code, aux-build", 422 | self.source.display(), 423 | line_num + 1, 424 | directive_name 425 | ); 426 | } 427 | } 428 | 429 | directives 430 | } 431 | } 432 | 433 | struct FileChecker { 434 | filecheck: PathBuf, 435 | verbose: bool, 436 | } 437 | 438 | impl Run for FileChecker { 439 | const STEP_DISPLAY_NAME: &'static str = "FILECHECK"; 440 | 441 | fn run(&self, _manifest: &Manifest) {} 442 | 443 | fn verbose(&self) -> bool { 444 | self.verbose 445 | } 446 | } 447 | 448 | impl FileChecker { 449 | pub fn new(verbose: bool) -> Self { 450 | let filecheck = [ 451 | "FileCheck-18", 452 | "FileCheck-17", 453 | "FileCheck-16", 454 | "FileCheck-15", 455 | "FileCheck-14", 456 | "FileCheck", 457 | ] 458 | .into_iter() 459 | .find_map(|filecheck| which(filecheck).ok()) 460 | .expect("`FileCheck` not found"); 461 | 462 | Self { filecheck, verbose } 463 | } 464 | 465 | fn check_testcase(&self, case: &TestCase) { 466 | let generated = File::open(case.generated()).unwrap(); 467 | let mut command = std::process::Command::new(&self.filecheck); 468 | command.arg(&case.source).stdin(generated); 469 | let output = self.command_output("filecheck", &mut command); 470 | assert!( 471 | output.status.success(), 472 | "failed to run FileCheck on {}", 473 | case.source.file_stem().unwrap().to_string_lossy() 474 | ); 475 | } 476 | } 477 | 478 | /// Test directives that can appear in source files 479 | #[derive(Debug)] 480 | enum TestDirective { 481 | /// Compile and run a testcase, 482 | /// expect a success (exit with 0) 483 | RunPass, 484 | /// Expected stdout content 485 | CheckStdout(String), 486 | /// Expected stderr content 487 | CheckStderr(String), 488 | /// Expected exit code 489 | ExitCode(i32), 490 | /// Auxiliary build requirement 491 | AuxBuild(String), 492 | } 493 | -------------------------------------------------------------------------------- /crates/rustc_codegen_c/src/builder.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] // TODO 2 | 3 | use std::ops::Deref; 4 | 5 | use rustc_abi::{HasDataLayout, TargetDataLayout}; 6 | use rustc_codegen_c_ast::func::CFunc; 7 | use rustc_codegen_ssa::traits::{BackendTypes, BuilderMethods, HasCodegen}; 8 | use rustc_middle::ty::layout::{ 9 | FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, 10 | TyAndLayout, 11 | }; 12 | use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; 13 | use rustc_target::abi::call::FnAbi; 14 | use rustc_target::spec::{HasTargetSpec, Target}; 15 | 16 | use crate::context::CodegenCx; 17 | 18 | mod abi; 19 | mod asm; 20 | mod coverage_info; 21 | mod debug_info; 22 | mod intrinsic_call; 23 | mod r#static; 24 | 25 | /// Codegen builder. 26 | /// 27 | /// It is created for each function and provides the local context for code generation. 28 | pub struct Builder<'a, 'tcx, 'mx> { 29 | /// The associated codegen context. 30 | pub cx: &'a CodegenCx<'tcx, 'mx>, 31 | bb: CFunc<'mx>, 32 | } 33 | 34 | impl<'a, 'tcx, 'mx> Deref for Builder<'a, 'tcx, 'mx> { 35 | type Target = CodegenCx<'tcx, 'mx>; 36 | 37 | fn deref<'b>(&'b self) -> &'a Self::Target { 38 | self.cx 39 | } 40 | } 41 | 42 | impl<'tcx, 'mx> HasCodegen<'tcx> for Builder<'_, 'tcx, 'mx> { 43 | type CodegenCx = CodegenCx<'tcx, 'mx>; 44 | } 45 | 46 | impl<'tcx, 'mx> HasDataLayout for Builder<'_, 'tcx, 'mx> { 47 | fn data_layout(&self) -> &TargetDataLayout { 48 | todo!() 49 | } 50 | } 51 | 52 | impl<'tcx, 'mx> HasTyCtxt<'tcx> for Builder<'_, 'tcx, 'mx> { 53 | fn tcx(&self) -> TyCtxt<'tcx> { 54 | self.cx.tcx() 55 | } 56 | } 57 | 58 | impl<'tcx, 'mx> HasParamEnv<'tcx> for Builder<'_, 'tcx, 'mx> { 59 | fn param_env(&self) -> ParamEnv<'tcx> { 60 | self.cx.param_env() 61 | } 62 | } 63 | 64 | impl<'tcx, 'mx> BackendTypes for Builder<'_, 'tcx, 'mx> { 65 | type Value = as BackendTypes>::Value; 66 | type Function = as BackendTypes>::Function; 67 | type BasicBlock = as BackendTypes>::BasicBlock; 68 | type Type = as BackendTypes>::Type; 69 | type Funclet = as BackendTypes>::Funclet; 70 | 71 | type DIScope = as BackendTypes>::DIScope; 72 | type DILocation = as BackendTypes>::DILocation; 73 | type DIVariable = as BackendTypes>::DIVariable; 74 | } 75 | 76 | impl<'tcx, 'mx> HasTargetSpec for Builder<'_, 'tcx, 'mx> { 77 | fn target_spec(&self) -> &Target { 78 | todo!() 79 | } 80 | } 81 | 82 | impl<'tcx, 'mx> LayoutOfHelpers<'tcx> for Builder<'_, 'tcx, 'mx> { 83 | type LayoutOfResult = TyAndLayout<'tcx>; 84 | 85 | fn handle_layout_err(&self, err: LayoutError<'tcx>, span: rustc_span::Span, ty: Ty<'tcx>) -> ! { 86 | todo!() 87 | } 88 | } 89 | 90 | impl<'tcx, 'mx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx, 'mx> { 91 | type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; 92 | 93 | fn handle_fn_abi_err( 94 | &self, 95 | err: FnAbiError<'tcx>, 96 | span: rustc_span::Span, 97 | fn_abi_request: FnAbiRequest<'tcx>, 98 | ) -> ! { 99 | todo!() 100 | } 101 | } 102 | 103 | impl<'a, 'tcx, 'mx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx, 'mx> { 104 | fn build(cx: &'a Self::CodegenCx, llbb: Self::BasicBlock) -> Self { 105 | Self { cx, bb: llbb } 106 | } 107 | 108 | fn cx(&self) -> &Self::CodegenCx { 109 | self.cx 110 | } 111 | 112 | fn llbb(&self) -> Self::BasicBlock { 113 | todo!() 114 | } 115 | 116 | fn set_span(&mut self, _span: rustc_span::Span) {} 117 | 118 | fn append_block(cx: &'a Self::CodegenCx, llfn: Self::Function, name: &str) -> Self::BasicBlock { 119 | // assume there is only one basic block 120 | // more complicated cases will be handled in the future 121 | llfn 122 | } 123 | 124 | fn append_sibling_block(&mut self, name: &str) -> Self::BasicBlock { 125 | todo!() 126 | } 127 | 128 | fn switch_to_block(&mut self, llbb: Self::BasicBlock) { 129 | todo!() 130 | } 131 | 132 | fn ret_void(&mut self) { 133 | self.bb.0.push_stmt(self.cx.mcx.ret(None)); 134 | } 135 | 136 | fn ret(&mut self, v: Self::Value) { 137 | self.bb.0.push_stmt(self.cx.mcx.ret(Some(self.cx.mcx.value(v)))) 138 | } 139 | 140 | fn br(&mut self, dest: Self::BasicBlock) { 141 | todo!() 142 | } 143 | 144 | fn cond_br( 145 | &mut self, 146 | cond: Self::Value, 147 | then_llbb: Self::BasicBlock, 148 | else_llbb: Self::BasicBlock, 149 | ) { 150 | todo!() 151 | } 152 | 153 | fn switch( 154 | &mut self, 155 | v: Self::Value, 156 | else_llbb: Self::BasicBlock, 157 | cases: impl ExactSizeIterator, 158 | ) { 159 | todo!() 160 | } 161 | 162 | fn invoke( 163 | &mut self, 164 | llty: Self::Type, 165 | fn_attrs: Option<&rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs>, 166 | fn_abi: Option<&rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>>, 167 | llfn: Self::Value, 168 | args: &[Self::Value], 169 | then: Self::BasicBlock, 170 | catch: Self::BasicBlock, 171 | funclet: Option<&Self::Funclet>, 172 | instance: Option>, 173 | ) -> Self::Value { 174 | todo!() 175 | } 176 | 177 | fn unreachable(&mut self) { 178 | todo!() 179 | } 180 | 181 | fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 182 | todo!() 183 | } 184 | 185 | fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 186 | todo!() 187 | } 188 | 189 | fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 190 | todo!() 191 | } 192 | 193 | fn fadd_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 194 | todo!() 195 | } 196 | 197 | fn sub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 198 | todo!() 199 | } 200 | 201 | fn fsub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 202 | todo!() 203 | } 204 | 205 | fn fsub_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 206 | todo!() 207 | } 208 | 209 | fn fsub_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 210 | todo!() 211 | } 212 | 213 | fn mul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 214 | todo!() 215 | } 216 | 217 | fn fmul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 218 | todo!() 219 | } 220 | 221 | fn fmul_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 222 | todo!() 223 | } 224 | 225 | fn fmul_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 226 | todo!() 227 | } 228 | 229 | fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 230 | todo!() 231 | } 232 | 233 | fn exactudiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 234 | todo!() 235 | } 236 | 237 | fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 238 | todo!() 239 | } 240 | 241 | fn exactsdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 242 | todo!() 243 | } 244 | 245 | fn fdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 246 | todo!() 247 | } 248 | 249 | fn fdiv_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 250 | todo!() 251 | } 252 | 253 | fn fdiv_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 254 | todo!() 255 | } 256 | 257 | fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 258 | todo!() 259 | } 260 | 261 | fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 262 | todo!() 263 | } 264 | 265 | fn frem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 266 | todo!() 267 | } 268 | 269 | fn frem_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 270 | todo!() 271 | } 272 | 273 | fn frem_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 274 | todo!() 275 | } 276 | 277 | fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 278 | todo!() 279 | } 280 | 281 | fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 282 | todo!() 283 | } 284 | 285 | fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 286 | todo!() 287 | } 288 | 289 | fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 290 | todo!() 291 | } 292 | 293 | fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 294 | todo!() 295 | } 296 | 297 | fn unchecked_ssub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 298 | todo!() 299 | } 300 | 301 | fn unchecked_usub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 302 | todo!() 303 | } 304 | 305 | fn unchecked_smul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 306 | todo!() 307 | } 308 | 309 | fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 310 | todo!() 311 | } 312 | 313 | fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 314 | todo!() 315 | } 316 | 317 | fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 318 | todo!() 319 | } 320 | 321 | fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { 322 | todo!() 323 | } 324 | 325 | fn neg(&mut self, v: Self::Value) -> Self::Value { 326 | todo!() 327 | } 328 | 329 | fn fneg(&mut self, v: Self::Value) -> Self::Value { 330 | todo!() 331 | } 332 | 333 | fn not(&mut self, v: Self::Value) -> Self::Value { 334 | todo!() 335 | } 336 | 337 | fn checked_binop( 338 | &mut self, 339 | oop: rustc_codegen_ssa::traits::OverflowOp, 340 | ty: rustc_middle::ty::Ty<'_>, 341 | lhs: Self::Value, 342 | rhs: Self::Value, 343 | ) -> (Self::Value, Self::Value) { 344 | todo!() 345 | } 346 | 347 | fn from_immediate(&mut self, val: Self::Value) -> Self::Value { 348 | todo!() 349 | } 350 | 351 | fn to_immediate_scalar(&mut self, val: Self::Value, scalar: rustc_abi::Scalar) -> Self::Value { 352 | todo!() 353 | } 354 | 355 | fn alloca(&mut self, size: rustc_abi::Size, align: rustc_abi::Align) -> Self::Value { 356 | todo!() 357 | } 358 | 359 | fn dynamic_alloca(&mut self, size: Self::Value, align: rustc_abi::Align) -> Self::Value { 360 | todo!() 361 | } 362 | 363 | fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: rustc_abi::Align) -> Self::Value { 364 | todo!() 365 | } 366 | 367 | fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value { 368 | todo!() 369 | } 370 | 371 | fn atomic_load( 372 | &mut self, 373 | ty: Self::Type, 374 | ptr: Self::Value, 375 | order: rustc_codegen_ssa::common::AtomicOrdering, 376 | size: rustc_abi::Size, 377 | ) -> Self::Value { 378 | todo!() 379 | } 380 | 381 | fn load_operand( 382 | &mut self, 383 | place: rustc_codegen_ssa::mir::place::PlaceRef<'tcx, Self::Value>, 384 | ) -> rustc_codegen_ssa::mir::operand::OperandRef<'tcx, Self::Value> { 385 | todo!() 386 | } 387 | 388 | fn write_operand_repeatedly( 389 | &mut self, 390 | elem: rustc_codegen_ssa::mir::operand::OperandRef<'tcx, Self::Value>, 391 | count: u64, 392 | dest: rustc_codegen_ssa::mir::place::PlaceRef<'tcx, Self::Value>, 393 | ) { 394 | todo!() 395 | } 396 | 397 | fn range_metadata(&mut self, load: Self::Value, range: rustc_abi::WrappingRange) { 398 | todo!() 399 | } 400 | 401 | fn nonnull_metadata(&mut self, load: Self::Value) { 402 | todo!() 403 | } 404 | 405 | fn store( 406 | &mut self, 407 | val: Self::Value, 408 | ptr: Self::Value, 409 | align: rustc_abi::Align, 410 | ) -> Self::Value { 411 | todo!() 412 | } 413 | 414 | fn store_with_flags( 415 | &mut self, 416 | val: Self::Value, 417 | ptr: Self::Value, 418 | align: rustc_abi::Align, 419 | flags: rustc_codegen_ssa::MemFlags, 420 | ) -> Self::Value { 421 | todo!() 422 | } 423 | 424 | fn atomic_store( 425 | &mut self, 426 | val: Self::Value, 427 | ptr: Self::Value, 428 | order: rustc_codegen_ssa::common::AtomicOrdering, 429 | size: rustc_abi::Size, 430 | ) { 431 | todo!() 432 | } 433 | 434 | fn gep(&mut self, ty: Self::Type, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value { 435 | todo!() 436 | } 437 | 438 | fn inbounds_gep( 439 | &mut self, 440 | ty: Self::Type, 441 | ptr: Self::Value, 442 | indices: &[Self::Value], 443 | ) -> Self::Value { 444 | todo!() 445 | } 446 | 447 | fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 448 | todo!() 449 | } 450 | 451 | fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 452 | todo!() 453 | } 454 | 455 | fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 456 | todo!() 457 | } 458 | 459 | fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 460 | todo!() 461 | } 462 | 463 | fn fptoui(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 464 | todo!() 465 | } 466 | 467 | fn fptosi(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 468 | todo!() 469 | } 470 | 471 | fn uitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 472 | todo!() 473 | } 474 | 475 | fn sitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 476 | todo!() 477 | } 478 | 479 | fn fptrunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 480 | todo!() 481 | } 482 | 483 | fn fpext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 484 | todo!() 485 | } 486 | 487 | fn ptrtoint(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 488 | todo!() 489 | } 490 | 491 | fn inttoptr(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 492 | todo!() 493 | } 494 | 495 | fn bitcast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 496 | todo!() 497 | } 498 | 499 | /// Performs cast between integers, x as ty in Rust. 500 | /// 501 | /// If the bit width is different, a truncation or extension is required. 502 | /// The type of extension—sign-extension or zero-extension—depends on the 503 | /// signedness of the source type. 504 | /// 505 | /// According to the C17 standard, section "6.3.1.3 Signed and unsigned 506 | /// integers", casting to an unsigned integer behaves the same as in Rust. 507 | /// However, casting to a signed integer is implementation-defined. 508 | /// 509 | /// Therefore, a two-step cast is necessary. First, cast to an unsigned 510 | /// integer via explicit conversion. Then, use a helper function to cast the 511 | /// result to a signed integer. 512 | fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value { 513 | let mcx = self.cx.mcx; 514 | let ret = self.bb.0.next_local_var(); 515 | 516 | let mut cast = mcx.cast(dest_ty, mcx.value(val)); 517 | if dest_ty.is_signed() { 518 | cast = mcx.call( 519 | mcx.raw("__rust_utos"), 520 | vec![ 521 | mcx.raw(dest_ty.to_unsigned().to_str()), 522 | mcx.raw(dest_ty.to_str()), 523 | cast, 524 | mcx.raw(dest_ty.max_value()), 525 | ], 526 | ); 527 | } 528 | self.bb.0.push_stmt(mcx.decl_stmt(mcx.var(ret, dest_ty, Some(cast)))); 529 | ret 530 | } 531 | 532 | fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 533 | todo!() 534 | } 535 | 536 | fn icmp( 537 | &mut self, 538 | op: rustc_codegen_ssa::common::IntPredicate, 539 | lhs: Self::Value, 540 | rhs: Self::Value, 541 | ) -> Self::Value { 542 | todo!() 543 | } 544 | 545 | fn fcmp( 546 | &mut self, 547 | op: rustc_codegen_ssa::common::RealPredicate, 548 | lhs: Self::Value, 549 | rhs: Self::Value, 550 | ) -> Self::Value { 551 | todo!() 552 | } 553 | 554 | fn memcpy( 555 | &mut self, 556 | dst: Self::Value, 557 | dst_align: rustc_abi::Align, 558 | src: Self::Value, 559 | src_align: rustc_abi::Align, 560 | size: Self::Value, 561 | flags: rustc_codegen_ssa::MemFlags, 562 | ) { 563 | todo!() 564 | } 565 | 566 | fn memmove( 567 | &mut self, 568 | dst: Self::Value, 569 | dst_align: rustc_abi::Align, 570 | src: Self::Value, 571 | src_align: rustc_abi::Align, 572 | size: Self::Value, 573 | flags: rustc_codegen_ssa::MemFlags, 574 | ) { 575 | todo!() 576 | } 577 | 578 | fn memset( 579 | &mut self, 580 | ptr: Self::Value, 581 | fill_byte: Self::Value, 582 | size: Self::Value, 583 | align: rustc_abi::Align, 584 | flags: rustc_codegen_ssa::MemFlags, 585 | ) { 586 | todo!() 587 | } 588 | 589 | fn select( 590 | &mut self, 591 | cond: Self::Value, 592 | then_val: Self::Value, 593 | else_val: Self::Value, 594 | ) -> Self::Value { 595 | todo!() 596 | } 597 | 598 | fn va_arg(&mut self, list: Self::Value, ty: Self::Type) -> Self::Value { 599 | todo!() 600 | } 601 | 602 | fn extract_element(&mut self, vec: Self::Value, idx: Self::Value) -> Self::Value { 603 | todo!() 604 | } 605 | 606 | fn vector_splat(&mut self, num_elts: usize, elt: Self::Value) -> Self::Value { 607 | todo!() 608 | } 609 | 610 | fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value { 611 | todo!() 612 | } 613 | 614 | fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value { 615 | todo!() 616 | } 617 | 618 | fn set_personality_fn(&mut self, personality: Self::Value) { 619 | todo!() 620 | } 621 | 622 | fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value) { 623 | todo!() 624 | } 625 | 626 | fn filter_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value) { 627 | todo!() 628 | } 629 | 630 | fn resume(&mut self, exn0: Self::Value, exn1: Self::Value) { 631 | todo!() 632 | } 633 | 634 | fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet { 635 | todo!() 636 | } 637 | 638 | fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option) { 639 | todo!() 640 | } 641 | 642 | fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet { 643 | todo!() 644 | } 645 | 646 | fn catch_switch( 647 | &mut self, 648 | parent: Option, 649 | unwind: Option, 650 | handlers: &[Self::BasicBlock], 651 | ) -> Self::Value { 652 | todo!() 653 | } 654 | 655 | fn atomic_cmpxchg( 656 | &mut self, 657 | dst: Self::Value, 658 | cmp: Self::Value, 659 | src: Self::Value, 660 | order: rustc_codegen_ssa::common::AtomicOrdering, 661 | failure_order: rustc_codegen_ssa::common::AtomicOrdering, 662 | weak: bool, 663 | ) -> (Self::Value, Self::Value) { 664 | todo!() 665 | } 666 | 667 | fn atomic_rmw( 668 | &mut self, 669 | op: rustc_codegen_ssa::common::AtomicRmwBinOp, 670 | dst: Self::Value, 671 | src: Self::Value, 672 | order: rustc_codegen_ssa::common::AtomicOrdering, 673 | ) -> Self::Value { 674 | todo!() 675 | } 676 | 677 | fn atomic_fence( 678 | &mut self, 679 | order: rustc_codegen_ssa::common::AtomicOrdering, 680 | scope: rustc_codegen_ssa::common::SynchronizationScope, 681 | ) { 682 | todo!() 683 | } 684 | 685 | fn set_invariant_load(&mut self, load: Self::Value) { 686 | todo!() 687 | } 688 | 689 | fn lifetime_start(&mut self, ptr: Self::Value, size: rustc_abi::Size) { 690 | todo!() 691 | } 692 | 693 | fn lifetime_end(&mut self, ptr: Self::Value, size: rustc_abi::Size) { 694 | todo!() 695 | } 696 | 697 | fn instrprof_increment( 698 | &mut self, 699 | fn_name: Self::Value, 700 | hash: Self::Value, 701 | num_counters: Self::Value, 702 | index: Self::Value, 703 | ) { 704 | todo!() 705 | } 706 | 707 | fn call( 708 | &mut self, 709 | llty: Self::Type, 710 | fn_attrs: Option<&rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs>, 711 | fn_abi: Option<&rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>>, 712 | llfn: Self::Value, 713 | args: &[Self::Value], 714 | funclet: Option<&Self::Funclet>, 715 | instance: Option>, 716 | ) -> Self::Value { 717 | use crate::rustc_codegen_ssa::traits::LayoutTypeMethods; 718 | 719 | let fn_abi = fn_abi.unwrap(); 720 | let ret_ty = self.cx.immediate_backend_type(fn_abi.ret.layout); 721 | 722 | let args = args.iter().map(|v| self.mcx.value(*v)).collect(); 723 | 724 | let call = self.mcx.call(self.mcx.value(llfn), args); 725 | let ret = self.bb.0.next_local_var(); 726 | 727 | self.bb.0.push_stmt(self.mcx.decl_stmt(self.mcx.var(ret, ret_ty, Some(call)))); 728 | 729 | ret 730 | } 731 | 732 | fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { 733 | todo!() 734 | } 735 | 736 | fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value) { 737 | todo!() 738 | } 739 | } 740 | --------------------------------------------------------------------------------