21d94a3d2c
Stabilize associated type bounds (RFC 2289) This PR stabilizes associated type bounds, which were laid out in [RFC 2289]. This gives us a shorthand to express nested type bounds that would otherwise need to be expressed with nested `impl Trait` or broken into several `where` clauses. ### What are we stabilizing? We're stabilizing the associated item bounds syntax, which allows us to put bounds in associated type position within other bounds, i.e. `T: Trait<Assoc: Bounds...>`. See [RFC 2289] for motivation. In all position, the associated type bound syntax expands into a set of two (or more) bounds, and never anything else (see "How does this differ[...]" section for more info). Associated type bounds are stabilized in four positions: * **`where` clauses (and APIT)** - This is equivalent to breaking up the bound into two (or more) `where` clauses. For example, `where T: Trait<Assoc: Bound>` is equivalent to `where T: Trait, <T as Trait>::Assoc: Bound`. * **Supertraits** - Similar to above, `trait CopyIterator: Iterator<Item: Copy> {}`. This is almost equivalent to breaking up the bound into two (or more) `where` clauses; however, the bound on the associated item is implied whenever the trait is used. See #112573/#112629. * **Associated type item bounds** - This allows constraining the *nested* rigid projections that are associated with a trait's associated types. e.g. `trait Trait { type Assoc: Trait2<Assoc2: Copy>; }`. * **opaque item bounds (RPIT, TAIT)** - This allows constraining associated types that are associated with the opaque without having to *name* the opaque. For example, `impl Iterator<Item: Copy>` defines an iterator whose item is `Copy` without having to actually name that item bound. The latter three are not expressible in surface Rust (though for associated type item bounds, this will change in #120752, which I don't believe should block this PR), so this does represent a slight expansion of what can be expressed in trait bounds. ### How does this differ from the RFC? Compared to the RFC, the current implementation *always* desugars associated type bounds to sets of `ty::Clause`s internally. Specifically, it does *not* introduce a position-dependent desugaring as laid out in [RFC 2289], and in particular: * It does *not* desugar to anonymous associated items in associated type item bounds. * It does *not* desugar to nested RPITs in RPIT bounds, nor nested TAITs in TAIT bounds. This position-dependent desugaring laid out in the RFC existed simply to side-step limitations of the trait solver, which have mostly been fixed in #120584. The desugaring laid out in the RFC also added unnecessary complication to the design of the feature, and introduces its own limitations to, for example: * Conditionally lowering to nested `impl Trait` in certain positions such as RPIT and TAIT means that we inherit the limitations of RPIT/TAIT, namely lack of support for higher-ranked opaque inference. See this code example: https://github.com/rust-lang/rust/pull/120752#issuecomment-1979412531. * Introducing anonymous associated types makes traits no longer object safe, since anonymous associated types are not nameable, and all associated types must be named in `dyn` types. This last point motivates why this PR is *not* stabilizing support for associated type bounds in `dyn` types, e.g, `dyn Assoc<Item: Bound>`. Why? Because `dyn` types need to have *concrete* types for all associated items, this would necessitate a distinct lowering for associated type bounds, which seems both complicated and unnecessary compared to just requiring the user to write `impl Trait` themselves. See #120719. ### Implementation history: Limited to the significant behavioral changes and fixes and relevant PRs, ping me if I left something out-- * #57428 * #108063 * #110512 * #112629 * #120719 * #120584 Closes #52662 [RFC 2289]: https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html |
||
---|---|---|
.. | ||
.github/workflows | ||
build_sysroot | ||
build_system | ||
deps | ||
doc | ||
example | ||
patches | ||
src | ||
tests | ||
tools | ||
.gitignore | ||
.ignore | ||
.rustfmt.toml | ||
build.rs | ||
Cargo.lock | ||
Cargo.toml | ||
config.example.toml | ||
libgccjit.version | ||
LICENSE-APACHE | ||
LICENSE-MIT | ||
messages.ftl | ||
Readme.md | ||
rust-toolchain | ||
y.sh |
WIP libgccjit codegen backend for rust
This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used.
Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.
Motivation
The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM. A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc.
Building
This requires a patched libgccjit in order to work. You need to use my fork of gcc which already includes these patches.
$ cp config.example.toml config.toml
If don't need to test GCC patches you wrote in our GCC fork, then the default configuration should
be all you need. You can update the rustc_codegen_gcc
without worrying about GCC.
Building with your own GCC version
If you wrote a patch for GCC and want to test it without this backend, you will need to do a few more things.
To build it (most of these instructions come from here, so don't hesitate to take a look there if you encounter an issue):
$ git clone https://github.com/antoyo/gcc
$ sudo apt install flex libmpfr-dev libgmp-dev libmpc3 libmpc-dev
$ mkdir gcc-build gcc-install
$ cd gcc-build
$ ../gcc/configure \
--enable-host-shared \
--enable-languages=jit \
--enable-checking=release \ # it enables extra checks which allow to find bugs
--disable-bootstrap \
--disable-multilib \
--prefix=$(pwd)/../gcc-install
$ make -j4 # You can replace `4` with another number depending on how many cores you have.
If you want to run libgccjit tests, you will need to also enable the C++ language in the configure
:
--enable-languages=jit,c++
Then to run libgccjit tests:
$ cd gcc # from the `gcc-build` folder
$ make check-jit
# To run one specific test:
$ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-asm.cc"
Put the path to your custom build of libgccjit in the file config.toml
.
You now need to set the gcc-path
value in config.toml
with the result of this command:
$ dirname $(readlink -f `find . -name libgccjit.so`)
and to comment the download-gccjit
setting:
gcc-path = "[MY PATH]"
# download-gccjit = true
Then you can run commands like this:
$ ./y.sh prepare # download and patch sysroot src and install hyperfine for benchmarking
$ ./y.sh build --release
To run the tests:
$ ./y.sh test --release
Usage
$CG_GCCJIT_DIR
is the directory you cloned this repo into in the following instructions:
export CG_GCCJIT_DIR=[the full path to rustc_codegen_gcc]
Cargo
$ CHANNEL="release" $CG_GCCJIT_DIR/y.sh cargo run
If you compiled cg_gccjit in debug mode (aka you didn't pass --release
to ./y.sh test
) you should use CHANNEL="debug"
instead or omit CHANNEL="release"
completely.
LTO
To use LTO, you need to set the variable FAT_LTO=1
and EMBED_LTO_BITCODE=1
in addition to setting lto = "fat"
in the Cargo.toml
.
Don't set FAT_LTO
when compiling the sysroot, though: only set EMBED_LTO_BITCODE=1
.
Failing to set EMBED_LTO_BITCODE
will give you the following error:
error: failed to copy bitcode to object file: No such file or directory (os error 2)
Rustc
You should prefer using the Cargo method.
$ LIBRARY_PATH="[gcc-path value]" LD_LIBRARY_PATH="[gcc-path value]" rustc +$(cat $CG_GCCJIT_DIR/rust-toolchain | grep 'channel' | cut -d '=' -f 2 | sed 's/"//g' | sed 's/ //g') -Cpanic=abort -Zcodegen-backend=$CG_GCCJIT_DIR/target/release/librustc_codegen_gcc.so --sysroot $CG_GCCJIT_DIR/build_sysroot/sysroot my_crate.rs
Env vars
- CG_GCCJIT_INCR_CACHE_DISABLED
- Don't cache object files in the incremental cache. Useful during development of cg_gccjit to make it possible to use incremental mode for all analyses performed by rustc without caching object files when their content should have been changed by a change to cg_gccjit.
- CG_GCCJIT_DISPLAY_CG_TIME
- Display the time it took to perform codegen for a crate
- CG_RUSTFLAGS
- Send additional flags to rustc. Can be used to build the sysroot without unwinding by setting `CG_RUSTFLAGS=-Cpanic=abort`.
- CG_GCCJIT_DUMP_TO_FILE
- Dump a C-like representation to /tmp/gccjit_dumps and enable debug info in order to debug this C-like representation.
Extra documentation
More specific documentation is available in the doc
folder:
- Common errors
- Debugging GCC LTO
- Debugging libgccjit
- Git subtree sync
- List of useful commands
- Send a patch to GCC
Licensing
While this crate is licensed under a dual Apache/MIT license, it links to libgccjit
which is under the GPLv3+ and thus, the resulting toolchain (rustc + GCC codegen) will need to be released under the GPL license.
However, programs compiled with rustc_codegen_gcc
do not need to be released under a GPL license.