Hacker News new | past | comments | ask | show | jobs | submit login
GCC 13 and the State of Gccrs (rust-gcc.github.io)
154 points by jmillikin on April 25, 2023 | hide | past | favorite | 96 comments



The biggest problem Rust has is that "no_core" is so poorly understood at this point that i doubt a comprehensive spec is even possible to explain:

1. Type inference taking into account higher ranked trait bounds

  - Slices in libcore work via the Index lang item so its like taking an index operator overload to a range lang item but the generic types in the range need to be unified with the higher ranked trait bound to eventually figure out that they are meant to be of usize.
2. Method resolution its almost a joke at this point how complicated it is in Rust.

  - The autoderef cycle sounds simple when you read this: https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/deref-coercions.html

  - But this misses so much extra context information
3. Macro invocations there are really subtle rules on how you treat macro invocations such as this which is not documented at all https://github.com/Rust-GCC/gccrs/blob/master/gcc/rust/expan...

</rant>

Some day I personally want to write a blog post about how complicated and under spec'd Rust is, then write one about the stuff i do like it such as iterators being part of libcore so i don't need reactive extensions.


Hm... I'm not sure I understand. Why would you expect no_core to be specified? It's an implementation detail of rustc, not part of the language.


No core _is_ the Rust language, libcore is just a library which adds the "Rust abstractions" so you can actually write a for loop or create a slice or deref, add or anything else.

Libcore just gets compiled like any other rust crate just it does not have access to abstractions.

For example, you can still write C code without libc because C is a language libc is just a library libcore is pretty much the same. Though Rust makes alot of assumptions that libcore _should_ be there but its possible for it not to be.


> For example, you can still write C code without libc because C is a language libc is just a library libcore is pretty much the same. Though Rust makes alot of assumptions that libcore _should_ be there but its possible for it not to be.

The same core/std distinction exists in C. The headers float.h, iso646.h, limits.h, stdalign.h, stdarg.h, stdbit.h, stdbool.h, stddef.h, stdint.h, stdnoreturn.h, and parts of string.h, stdlib.h, fenv.h, and math.h are required to be supported in freestanding mode.

And, frankly, just about every language has this kind of core library/standard library distinction; at some point, parts of the compiler implementation of the language need to work with the library implementation details, and vice versa. Languages like Rust and C are somewhat unusual in actually identifying a subset of the standard library that is usable without a complete implementation of the standard library.


core is part of the language (or at least, many parts of it are).

The way that rustc currently splits this up is an implementation detail of rustc, not something that must be copied exactly. Rust without core is not Rust. It's not even usable.


You need to provide the langitems, it's true that core has a lot more than just the langitems, but the langitems are a lot and as somebody pointed to me on HN recently, they chase through into related stuff.

I was like, Option isn't special but, well, you do need to provide Some and None, and those are clearly two halves of an enum, so - that's Option is what that is.

You need Try, and unless you're going to write Try yourself to have some other behaviour that means you're writing ControlFlow and Result as well as Option.

I think that the work needed to make Ipv4Addr::is_documentation - a predicate which tells you whether the IPv4 Address you've got is, in fact, one reserved for documentation by the IETF RFC 5737 - is tiny compared to the struggle to get u32::is_power_of_two - a predicate which tells you if a 32-bit integer is a power of two - and so even though doubtless Rust doesn't care whether the former part of the core library works you might just as well.


A binary number is a power of two iff only a single bit is set, so pretty trivial to implement.


Sure, it's literally self.count_ones() == 1 -- so we just implement count_ones() and ah, well, we could do all this by hand but turns out (fill in name of CPU) has a CPU instruction specifically for this. Rust calls the intrinsic we're about to go write intrinsics::ctpop()

Now we're writing per-ISA intrinsics, what was our goal again? Maybe I was too oblique, this stuff is all rabbit holes is what I was getting at. We're lucky these people even re-surface periodically with work and a blog post.


Or (x & (x-1)) and let the compiler figure that out.


gcc-rs is one of two projects for bringing Rust to gcc. gcc-rs is the more ambitious of the two, with an entirely new frontend. There is also rustc_codegen_gcc (https://github.com/rust-lang/rustc_codegen_gcc) that keeps the rustc frontend, and only swaps out LLVM for GCC at the codegen stage.


IMO, rustc_codegen_gcc is much more reasonable in scope. It also stands a chance of actually keeping up with subsequent Rust releases. I would be surprised if gcc-rs ever achieved any traction. Not to say it's not a fun project, but I can't see it replicating rustc.


It doesn't has to match rustc on nightly, only the 3-yearly releases. That seems doable, considering Rust has slowed down a bit, compared to super fast pace of change in early years. Regardless, it is always good to have alternate implementations, C++ has only benefited from it.


I'm guessing you aren't a Rust programmer?

By "3-year releases" you're probably meaning Editions, but Rust Editions aren't like the C++ Standard, where they're bundling together a bunch of new features† the Edition changes language syntax, usually in small ways. The features people care about are released every six weeks and aren't saved up for new Editions.

For example, 1.69 released last week, so now: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080)

... is a constant, at compile time the data structure equivalent to 127.0.0.1:8080 is constructed and baked into your binary program.

If I write a Rust program which relies on this for a constant, it works fine, because it is constant, but if I try to compile it with Rust 1.68 (from earlier this year) it won't work. If an alternative compiler doesn't have the features of Rust 1.69, then code written for Rust 1.69 won't necessarily work with it. Sometimes such differences will be tiny, other times huge.

† And notice that just because say, Modules was a C++ 20 feature, did not mean that you woke up one day in 2020 and had working Modules, C++ 20 is just an ISO document, the features have to get implemented by vendors, and then tested, and then shipped, which can take weeks, or months, or years.


Bad example because that's a library feature and doesn't involve explicit compiler support - in general you're right though, backwards-compatible compiler features (say, GATs) are added regularly and are available for all editions, not just the newest one.


Except the library uses nightly features so to pull in newer versions, you have to be up to date with all the unstable compiler features.


That sounds a bit like using the latest features in the C or C++ standard, and then be surprised that many compilers cannot compile your code.

When a language develops quickly it is a good if people use the latest version to test new features to get experience.

When a language become mainstream, change will be much slower. Rust compilers will be shipped with operating systems, and people will write code that can be compiled by those older compilers.

There is a lot of C code that targets C99. Because that's what you can rely on if it has to run everywhere.


> When a language become mainstream, change will be much slower

I wouldn't assume that. JavaScript is about as mainstream as it gets, and that's also on a 6-weekly release schedule.

> Rust compilers will be shipped with operating systems, and people will write code that can be compiled by those older compilers.

Rust compilers are already shipped with operating systems, but for the most part (a few really foundational crates aside), people are not writing code that can be compiled by those older compilers. They're telling people to install a newer version of Rust. Which is pretty reasonable given how easy it is to manage rustc versions with rustup.

This may change with the creation of certified compilers for things like the automotive industry. But then, they're probably pretty used to maintaining their own library ecosystem anyway.

> There is a lot of C code that targets C99. Because that's what you can rely on if it has to run everywhere.

Yes, but one of the best things about Rust is that you can target the latest compiler version, and it still runs everywhere! That's why people don't like the possibility that this might change with the introduction of gcc-rs. We shouldn't accept crappy C toolchains as the standard.


I think there are a lot of people who don't want a new compiler every few months. Obviously, the people who arrive first at a new language are people like the latest greatest.

Take for example reproducible builds. Obviously, you only get the same binary output if you use the same compiler version. In that context, it doesn't make sense to keep around every version ever released of the Rust compiler.

In particular, if operating systems are going to use Rust in their kernels or base systems, then it is very unlikely that they are just going to use rustup to get the latest compiler. They will carefully vet each compiler release to make sure that everything that worked in the past, still works.

Rust being a compiler means that for every processor architecture somebody has to create the back-end. This means that if the current LLVM-based rust compiler will remain the only usable Rust compiler, there will be a lot of places where Rust cannot be used (unless LLVM will be the only compiler back-end in the future).


For now, at least, Rust for Linux actually requires Nightly features, so it's even less stable than the requirements of many relatively fast moving but popular Rust crates in userspace.

As with Firefox, Linux (ab)uses the compiler's own environment hack to say "No, I want nightly features, I don't care that this invalidates my warranty" despite using a stable compiler.

The actual version used is, I think, currently 1.66 (so, about three months old).


There is nothing crappy about stability. One of the most annoying things about more modern languages is this assumption that in so much of the ecosystem that I will go install the latest version of cool-lang compiler. I really like being able to build software with the tool chain that comes with my distro. Maintaining endless versions of all these things is a hassle.


> That sounds a bit like using the latest features in the C or C++ standard, and then be surprised that many compilers cannot compile your code.

Compiling the Firefox browser is often an exercise in futility because of this.

Rust might be the best but not being able to compile existing programs looks really bad.


Not parent, but not a rust programmer:

> If I write a Rust program which relies on this for a constant, it works fine, because it is constant, but if I try to compile it with Rust 1.68 (from earlier this year) it won't work.

How would it not work? If your program compiles and runs with 1.69, then surely that's because it never tries to modify the value. But if your program never tries to modify the value, how would it fail with 1.68?


`const` in Rust is for compile-time constants.

In this case, the fn `std::net::SocketAddr::new` was made a const fn recently--but was a regular fn before.

>that's because it never tries to modify the value

That's something different. If you want variables that are read-only, you don't need any extra keyword. It's the normal case:

let x = 5;

If you want a mutable variable, you add a `mut` keyword.

let mut x = 5;

But if you want a compile-time constant, you use `const` instead.

const x: u32 = 5;

The latter will be evaluated by the compiler at compile time (so interpreted) and substituted BEFORE the user runs the program. This is new-ish stuff and is slowly worming its way into the standard library.


The GP is missing a small bit of context: because this construct is now const, it can be used in const contexts, like to initialize a static variable. Doing so didn't work in 1.68, but does now in 1.69.


But older code will still work with the new compiler right?


That is the Rust stability commitment: Rust code will always* compile with any subsequent release.

* Modulo soundness bugs being fixed. I've personally encountered 2 instances of that since 1.0, and they all occurred before 2017.


Yes


> a Rust program which relies on this for a constant

https://godbolt.org/z/ceY3q3eW4


Sorry, I'm not reading 1100 words of privacy policy to get a chance to read whatever that is.


I recommend just reading or closing the privacy policy -- it's a single screen (on my device) and is quite reasonable. Because "whatever that is" is a godbolt link... and godbolt is one of the absolutely most valuable and greatest tools available for software developers who work in compiled languages. It's definitely worth becoming familiar with.


> godbolt is one of the absolutely most valuable and greatest tools available for software developers who work in compiled languages.

That's a bold claim for a tool that doesn't even have a Wikipedia entry.

Edit: or a subreddit.


Gosh, this website is becoming reddit more and more everyday. YOU don't have a wikipedia entry. Are you also now classified as "whatever that is"? Of course not.

I would implore you to open your mind up to resources that aren't popular social media because that's where the real gold/value is in development/engineering.


> YOU don't have a wikipedia entry.

I'm not claiming to be "one of the absolutely most valuable and greatest tools available" though. (Well, maybe the "greatest tool" part ;-) And if someone else claimed that about me, I'd think that either there was something very wrong with them, or that one of my parents had started using alt accounts I didn't know about.

Considering some of the software tools that do have dedicated wikipedia pages and subreddits, and that I'd never heard of godbolt before, I don't think it's out of line to be skeptical of such a hyperbolic claim.


(For what it's worth, I suspect if you took a random poll of Hacker News commenters, at least 90% would know what godbolt is. In fact, until I saw this thread, I thought it was just something like the C language which _everyone_ knows exists - it certainly deserves to be - although of course every day there's a new lucky 10000.)


Yes. I am comfortable depending this claim -- purely as a user, no association with the tool developers.


> (IpAddr::V4(Ipv4Addr::new(

Rust is so simple and clear :3


The C equivalent would be a bunch of `in_addr`/`sockaddr_in`/`sockaddr` handling where you can do something wrong at basically every step of the way. You can't mess up the types in Rust, there's only one way they fit together.

Of course if you just want to convert a string to a SocketAddr (returning an error at runtime if it's invalid), you just do `let addr = "127.0.0.1:8080".parse();`.


I'd like to point out the quality of the blog post. It is extremely well written. For me it gives a very good sign about where all of this is going.


Why is it necessary to do this? I get that having multiple implementations of a language is a good thing. But why does GCC in particular want to do it, and why with two separate efforts of different levels of ambition? Is it related to rust-in-kernel efforts? What stops using the normal rustc for that?


1. GCC supports more target platforms than LLVM, including many low-volume embedded systems that are unlikely to ever get upstream LLVM support.

2. The GCC developers are interested in supporting a broad set of languages that compile to native executables, and Rust is an increasingly popular language for systems programming.

3. Whether something is "necessary" or not has never been decisive in whether or not it happens. When presented with a programming challenge, why not try it and see what comes out?


4. Some would like to use th we same compiler for everything. Right now, building the Rust bit of Linux requires LLVM. Why shouldn't you be able to build everything using gcc alone?


Because they're different languages?

It's more insane to me that one wants the same tool to do everything rather than have different tools for different tasks.

Like should Perl be compiled with GCC just to satisfy that requirement because it's used during the kernel build? That's ridiculous!


Yeah, you start down this path and one day you end up with compilers for Go, or Ada, or Fortran, or who knows what else. How ridiculous would that be!

PS. GCC stands for “GNU Compiler Collection”. All of the above is already there.


GCC already compiles quite a lot of languages, why not add one to the toolbelt if contributors feel like it?


Even though I think it'd be a bad idea for users of the language to rely on gcc to compile their Rust code, what I'm replying to is the idea that having one compiler for all the languages used in a project is a good idea in the first place.

I don't think you should expect or want that.


I haven't been able to find a coherent comparison of what targets are supported by gcc vs llvm. Wasm ptx, and spirv seem to be llvm only? But the gcc list is kind of confusing. 8051 is mayne gcc only? Or is that even supported by gcc? Other than 8051, all the uc stuff I'm familiar with was in llvm. I'm not sure what 68k support means though, there have been so many variants. More simply, what machines will I be able to compile rust for once this hits that I couldn't before? Gameboy? C64?


Ancient big iron (SPARC, PA-RISC, Alpha), weird embedded with vendor-provided toolchains based on GCC, and recent architectures that don't have mature LLVM support (Longsoon).

m68k is already supported by LLVM and Rust supports it as a tier-3 target platform.


Yeah I saw 68k in there, rust also will target sparc and sparc64. And s930, but yeah, I can see how alpha and pa-risc support would be really important for linux to continue supporting.

Xtensa got upstream support, but so many embedd vendors seem to want to double dip and sell build tools, so they don't upstream their llvm based build tools. Shortsighted imo. Vendors that don't charge for build tools will make it up in sales volume.


Vendors not upstreaming their llvm-based build tools is exactly why you should support a GPL compiler like gcc.


GPL doesn't force upstreaming, just making the sources available. Plenty of small vendors are not upstreaming their gcc patches. It's more a question of man-hours than of license.



Loongson / LoongArch nowadays does have mature LLVM support.


For (1) there is a parallel effort to add a gcc backend to the rustc frontend.


Because competition and choice is good? Even though having to support multiple C/C++ compilers can be painful at times for programmers, the competition between GCC, Clang and MSVC is definitely a good thing (imagine being stuck with MSVC on Windows when MSVC was about 15 years behind the C standard until recently).

A separate Rust compiler may also uncover problems in the language or standard library design (e.g. if it's too much effort to write a Rust compiler from scratch that definitely isn't a good thing IMHO).


Yes that much I got. It's a thing that would be nice to have. But that doesn't explain exactly why the GCC would be the ones doing it nor why there would be two separate projects.


Because having a Free implementation which complements the Open Source one is a great way to keep the language alive, evolve it in a saner way, and improve ways we thought it's impossible to do.

clang made gcc and g++ better compilers. gcc-rs can do the same and help making rustc a better compiler and Rust a better language.

For the record, I don't write Rust, because GCC has no Rust support yet. More specifically, I don't use LLVM-Specific languages due to LLVM's license and stance against GCC.


> For the record, I don't write Rust, because GCC has no Rust support yet. More specifically, I don't use LLVM-Specific languages due to LLVM's license and stance against GCC.

As far as I can tell, GCC is licensed under GPLv3 these days. LLVM is under a variation of the Apache License.

https://www.apache.org/licenses/GPL-compatibility.html suggests that you can use code under Apache License in a project that's under GPLv3.

So someone could take legally LLVM, change the Readme and slap a GPLv3 license on it, and have the same license as GCC? (Assuming that the exceptions that LLVM's license has aren't a problem.)

Would that fix your issues? Or what is your specific problem?


What would be the point of that? Upstream will never accept GPL licensed patches and your fork is also available under the Apache license from the original source (except the readme changes that nobody cares about).


The point is that this way you can get an LLVM that's licensed the same way as GCC.

This whole exercise has a point, if and only if there's a point to insisting that GCC's license is fine, but LLVM's license ain't.

It's just a reduction. https://en.wikipedia.org/wiki/Reduction_(complexity)

If you don't have any problem with the license of LLVM in the first place, the reduction is obviously useless to you.


I thought the point of having something GPL licensed would be that you actually get to enjoy/enforce the copyleft clauses of the GPL. By just relicensing an existing non-copyleft project and not following up with any significant development you only get the illusion of a copyleft project. If you are happy with this license mirage you are essentially saying you only care about the GPL name and not about copyleft. It's just nerdy virtue signalling.


Anyone (sub-) licensing LLVM from you would be bound by the GPL.


I doubt it. Since you don't hold copyright over any part of LLVM you have no standing to sue for copyright infringement, so people using your GPL-but-otherwise-unmodified LLVM can ignore the GPL.


Well, people can always do illegal things.


You're opposed to even using LLVM just because of its pushover license? Isn't even RMS okay with that? Doesn't the usual guidance go like "copyleft free software is good to use and contribute upstream to, free but non-copyleft software is good to use but bad to contribute upstream to, and non-free software is bad to use and contribute upstream to"?


How is Rust not evolving in a sane way today?


I didn't say it's evolving in an insane way, however I believe the outcome improves when more people with different perspectives discuss on a matter.

In other words, "If you want to go fast, go alone. If you want to go far, go together".


Why GCC -> who else if not GCC? LLVM and GCC are more or less only big system programming compiler frameworks that support multiple programming languages and many backends. GCC already has frontends for Objective-C, Fortran, Ada, D, Go and few more not just C++ and C. It's much easier to add N+1 language to compiler that already supports N languages, instead of adding second language to a compiler which currently supports one. Rest of the compilers are mostly using LLVM as backend, or are made for single language and probably don't have enough resource to support more than 3 CPU architecture, not even talking about second language frontend.

Can you name even one other compiler which would match those requirements? Only thing that comes to my mind is Borland, although I have no idea whether their compilers shared common backend or where they completely independent. I guess at some point Microsoft might have shared some of the parts for their .NET CLR langauges (Basic, C#, F# and managed C++/CLI ). While you could make a Rust frontend for .NET it would be somewhat pointless. Rust makes certain sacrifices in terms of ease of use, for the purpose of safe low level memory management. In a VM made for higher level garbage collected languages thats just unnecessarily complexity, without the benefits. After looking more I was also able to find thing called "Amsterdam compiler kit", but that seems more like academic exercise.

Why two separate projects -> Think of it as short term vs long term solutions. Ideally in long term the multiple implementations for programing language would be completely independent, but it takes more work. In short term it's easier to glue together existing Rust frontend with GCC backend, while still getting many of the benefits of having multiple programming language implementations.


>Because competition and choice is good?

It is not that simple, there are pros and significant cons


We already have proprietary forks of LLVM. That's the whole reason Apple etc. started it instead of continuing with GCC.

It's unclear to me what negatives a new, independent, Free implementation brings.

On the other hand, the positives of it seem clear: an independent, Free implementation helps establish Rust the language and differentiate the language from a specific implementation of it.


The Rust... must... grow.


I would imagine this is a massive effort. Rust is not a simple language


I don't think this can end well.

Rust have too many underspecified behavior, and the only source of truth is the official implementation.

Everybody know the type system in rust is NP-complete. The compiler use different heuristics and hints to do a best effort solution. I can't imagine how this can be reimplemented


While I understand your position, none of this is new. I think this is one of the growing pains rust will have to survive.

I once read a text about someone implementing C++ before it was standardized. Whenever something wasn't clear, he tried it on CFront. CFront would generally crash. That's a lot worse than rust today, and there are a lot of C++ compilers nevertheless.

For the NP-complete problem, here is how Java solved this: The compiler has to validate that every function's execution ends with a valid return statement. This is literally the halting problem, impossible for the compiler to solve.

As a way out of this conundrum, the java standard dictates the algorithm. It is conservative, so it rejects some valid programs. But it is part of the standard, so if one java compiler accepts a program, you know all the other ones will too. So all java compilers make the same mistakes, as required by the java standard. A compiler is simply not allowed to implement a better algorithm.

While it is a huge effort, gccrs will probably succeed, and help clarify the rust standard in the process. Real risks are more long term: gcc java slowly petered out. For rust, things seem better, as gccrs has a stable funding source.

Update: Java's problem/algorithm is not (only) the return statement. It is the requirement that every variable is defined before being used. You find it as 'definite assignement' in the compiler standard.


> The compiler has to validate that every function's execution ends with a valid return statement. This is literally the halting problem, impossible for the compiler to solve.

It is not the halting problem though. The compiler does not have to prove the return is ever reached. Just that the instruction pointer does not fall off the end of the function. Just check the branch targets one by one?


See the update at the end. The halting aspect comes from checking if a value is defined: when a return statement is executed, check that the expression being returned is filled in. In fact, it goes much wider, it has to check that every variable used has been defined and nothing final gets redefined.

See for some interesting cases the examples at the start of https://docs.oracle.com/javase/specs/jls/se17/html/jls-16.ht...

Update: come to think of it, it probably is the halting problem simply for returning:

  int somefunc(){
    if(this_returns_true()){
      throw Something();
    }else{
       // No throw here
    }
  // Do I need return 1 here?
  }
The famous Sufficiently Smart Compiler can decide the function always throws, and does not need a return statement. Let this_returns_true depend on deciding the halting problem, and there you are. Clearly, this level of analysis is out of reach for javac. The standard in this case just claims the then and else side can both be executed, so the return is required. If the else had a second throw, the compiler would not need the return.


GCC is first and foremost a compiler for GNU C, which is a set of unspecified extensions to C, which is a language that achieved near-universal adoption despite decades of competing mutually-incompatible implementations.

C++ templates are Turing-complete, and GCC implements them just fine.

The idea that Rust requires a formal specification (outside very rare situations, like aeronautic firmware) is silly.


You forgot the </sarcasm> tag. Or are you actually serious with your comment?

GCC supports various "flavors" of C, including fully standard compliant versions.

GNU extensions are all documented.


GCC by default runs in GNU C mode, which accepts constructs that are not valid in any version of ISO C. Its extensions are not part of the language spec, and the only way to discover their behavior is by reference to implementation-specific documentation/code.

That is also the situation Rust currently is in. There is no Rust spec, only a reference manual for rustc.

People who complain about unspecified behavior in Rust (or, equally, about Rust's lack of a language spec) are not satisfied with mere documentation. They want something like the Java language specification and conformance test suite.


Check GCC-ADA and Spark.


NP-completeness is not a problem at all. Compilers already solve multiple NP-complete problems in the course of compilation after all, for example register allocation. They require heuristics to be solved in a reasonable time, but the upside is that there is no gold standard since there are pathological cases for any heuristic. Presumably, a representative set of crates from the ecosystem will be chosen to find performance issues.

The underspecified part should not be a deal breaker, even though it's certainly a difficulty. But it will also be an opportunity to spot suboptimal implementation choices in rustc. Exposing these will improve the language as a whole.


> Compilers already solve multiple NP-complete problems in the course of compilation after all, for example register allocation.

The NP-complete problem is optimal register allocation (through graph coloring). Register allocation in itself is not NP-complete. You can always use a suboptimal but fast algorithm because optimizations are optional. On the other hand, type checking is not optional, so having to solve a NP-complete problem for that would indeed be problematic.


> On the other hand, type checking is not optional, so having to solve a NP-complete problem for that would indeed be problematic.

Not necessarily. There are plenty of NP-complete problems that can be solved optimally fast enough to be useful for the instances that actually come up in real world applications.

For example the Traveling Salesman Problem (TSP) is NP-complete, but there are exact solvers that run in reasonable time for instances of a few hundred vertices. That's fine if you are say a delivery company trying to plan the day's itinerary for one of your delivery trucks.


A less precise borrow checker can usually still be satisfied by adding workarounds, at the cost of performance of course. Adding redundant reference counting or increasing the lifetime of data and the duration of critical regions make the program slower. In this sense, improving the borrow checker is analogous to adding new analyses and optimizations passes to a compiler.


OK, I suppose I have to dig deeper into Rust to determine whether I really disagree with that, or maybe this is too vague. The question is: who applies your workarounds? If this is always the compiler, then I agree, but if the programmer has to do any work, then your analogy fails.


Yes, the programmer has to apply the safe workarounds. They always work, but improvements to the borrow checker's heuristics can make them redundant. Removing these workarounds increases performance. A certain minimum set of heuristics are part of the documented language spec by now, and this set is going to become larger with time. If a significant fraction of the ecosystem is affected by a split in heuristics coverage, then Gccrs will have to catch up.

In the PR dug out by a sibling commenter, the improvement to the compiler was indeed to apply the workaround that the programmer had to do. I believe that the churn of new heuristics is going to become smaller, as presumably most of the low-hanging fruits have been harvested by now.


> The underspecified part should not be a deal breaker, even though it's certainly a difficulty. But it will also be an opportunity to spot suboptimal implementation choices in rustc. Exposing these will improve the language as a whole.

but... we don't want same sourcecode compile with one compiler implementation, but not the other... right?

When I say "under-specified", I meant something like this:

https://github.com/rust-lang/rust/pull/105300/

quote> I claim it's more correct as well because it fixes #104639.

There is no spec. Just a bunch of implementation-defined behavior. Without a spec, this would be a forever catching up game. It is not easy to come up with a spec -- the implement is filled with heuristics because the intrinsic NP-completeness.


> we don't want same sourcecode compile with one compiler implementation, but not the other... right?

It's not ideal, but I can live with it so long as when I write a program which compiles it has the desired behaviour. That's the problem in C++ and to a lesser extent C which ultimately falls out of this same constraint. In C++ it's easy to write programs which compiler A and compiler B will both compile but they have different results and neither of them is wrong. I have no use for this whatsoever.

If some Rust compilers say my program is unacceptable, and others build it correctly, obviously that's not brilliant news but I can choose whether to fix the program to be acceptable to more compilers, or not worry - the results at least are correct.


Specifying the heuristics would actually impede future implementations. Even if they would be willing to engage in spending more computational effort on proving that a controversial block of code is type-safe. And it's always possible that a smart PhD student comes up with a better heuristics for certain kinds of programs.

Implementations accepting different sets of inputs is certainly annoying, but acceptable as long as they are erring on the side of caution. We definitely don't want code to compile which is actually not type-safe. At a quick glance, the PR can be understood as automating a workaround that programmers had to do by themselves before.

> This PR (similarly, and building on top of #104765) allows RPITs and async fns to untangle their lifetime bounds to figure out the set of lifetimes that actually get caputed instead of falling back to a larger one or even 'static. For most cases it was was already possible for users to manually reorder their lifetimes to make their code compile, this PR just makes that automatic, as the order of generic params and bounds should not matter.


I note that Rust already has been reimplemented (mrustc), mostly by one person.


mrustc assume all rust code is valid and skips all those heuristics checks.

gccrs on the other hand, aims to be a full implementation with all those checkers.


Gccrs does not aim to be a full implementation. They're aiming to be a good enough implementation that they can steal the last parts (the borrow checker) from rustc.

More specifically they're aiming to steal the next gen borrow checker, not the current one


The way it can end well is that the spec gets more and more precise due to the combined efforts of independent frontend implementers.


C++'s type system is turing complete, and there seem to be plenty of successful independant implementations of that -- although they do often disagree on how many programs are executed.


but that's exactly why multiple implementations are a good idea, because it will help encourage further specification and standardization of the unspecified and heuristic behaviors.


Until, then, gdc (gcc dlang) can serve you today.


gdc can compile my rust code to obscure embedded targets?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: