Closed aturon closed 1 year ago
How are exit statuses going to be dealt with?
This comment by @Screwtapello seems to have been made too close to the end of FCP for any alterations to be made to the RFC in response to it.
In short: the RFC proposes returning 2 on failure on grounds which, while well-founded, are obscure and produce a slightly unusual result; the least surprising thing is to return 1 when the program has no indication it wants any more detail than just success or failure. Is this sufficiently bikesheddy that it can be discussed without it feeling like we're perverting the RFC process, or are we now locked into this specific implementation detail?
It's not an implementation detail though, is it?
Some scripts use exit codes as a way to get information from a sub-process.
This is specifically about the case when a sub-process (implemented in Rust) has no information to give, beyond a binary "everything's fine"/"something went wrong".
Some scripts use exit codes as a way to get information from a sub-process.
That behavior is always extremely dependent on the program being called except in that non-zero means failure. Given that std::process::exit
with a main-function wrapper and a lookup table is going to remain the best option for those who want a more articulate exit status no matter what is done, this seems like a mostly insignificant detail.
I don't think SemVer has a "mostly insignificant detail" exception though.
I think the exit code should be added to the unresolved questions list. @zackw also opened a related internals thread.
Many people agree that the exit code should be 1
on failure (instead of 2
):
https://www.reddit.com/r/rust/comments/6nxg6t/the_rfc_using_in_main_just_got_merged/
@arielb1 are you going to implement this rfc?
@bkchr
No, just to mentor it. I assigned so I won't forget to write the mentoring notes.
Ahh nice, I would be interested in doing it :) But, I don't have any idea where to start :D
@bkchr
That's why I'm here :-). I should write the mentoring instructions soon enough.
Okay, then I'm waiting for your instructions.
This is a WG-compiler-middle issue. If you want to seek help, you can join #rustc on irc.mozilla.org (I'm arielby) or https://gitter.im/rust-impl-period/WG-compiler-middle (I'm @arielb1 there).
There's a WIP compiler readme at #44505 - it describes some things in the compiler.
Work plan for this RFC:
Termination
lang-item to libcoreTermination
in main
Termination
in doctestsTermination
in #[test]
Termination
lang-item to libcoreFirst, you need to add the Termination
trait to libcore/ops/termination.rs
, along with some documentation. You'll also need to mark it as unstable with an #[unstable(feature = "termination_trait", issue = "0")]
attribute - this will prevent people from using it before it is stabilized.
Then, you need to mark it as a lang-item in src/librustc/middle/lang_items.rs
. This means the compiler can find it out when type-checking main
(e.g. see 0c3ac648f85cca1e8dd89dfff727a422bc1897a6).
That means:
librustc/middle/lang_items.rs
)#[cfg_attr(not(stage0), lang = "termination")]
to the Termination
trait. The reason you can't just add a #[lang = "termination"]
attribute is because the "stage0" compiler (during bootstrapping) won't know termination
is something that exists, so it won't be able to compile libstd. We'll manually remove the cfg_attr
when we update the stage0 compiler.
See bootstrapping docs at XXX for details.Termination
in mainThis is the interesting part I know how to deal with. This means making a main
that returns ()
not type-check (currently you get a main function has wrong type
error) and work.
To make it type-check, you first need to remove the existing error in: https://github.com/rust-lang/rust/blob/9a00f3cc306f2f79bfbd54f1986d8ca7a74f6661/src/librustc_typeck/lib.rs#L171-L218
Then, you need to add a check that the return type implements the Termination
trait in (you add a trait obligation using register_predicate_obligation
- search for uses of that). That can be done here:
https://github.com/rust-lang/rust/blob/9a00f3cc306f2f79bfbd54f1986d8ca7a74f6661/src/librustc_typeck/check/mod.rs#L1100-L1108
The other part is making it work. That should be rather easy. As the RFC says, you want to make lang_start
generic over the return type.
lang_start
is currently defined here:
https://github.com/rust-lang/rust/blob/9a00f3cc306f2f79bfbd54f1986d8ca7a74f6661/src/libstd/rt.rs#L32
So you'll need to change it to be generic and match the RFC:
#[lang = "start"]
fn lang_start<T: Termination>
(main: fn() -> T, argc: isize, argv: *const *const u8) -> !
{
use panic;
use sys;
use sys_common;
use sys_common::thread_info;
use thread::Thread;
sys::init();
sys::process::exit(unsafe {
let main_guard = sys::thread::guard::init();
sys::stack_overflow::init();
// Next, set up the current Thread with the guard information we just
// created. Note that this isn't necessary in general for new threads,
// but we just do this to name the main thread and to give it correct
// info about the stack bounds.
let thread = Thread::new(Some("main".to_owned()));
thread_info::set(main_guard, thread);
// Store our args if necessary in a squirreled away location
sys::args::init(argc, argv);
// Let's run some code!
let exitcode = panic::catch_unwind(|| main().report())
.unwrap_or(101);
sys_common::cleanup();
exitcode
});
}
And then you'll need to call it from create_entry_fn
. Currently, it instantiates a monomorphic lang_start
using Instance::mono
, and you'll need to change it to use monomorphize::resolve
with the right substs.
Termination
in doctestsI don't really understand how doctests work. Maybe ask @alexcrichton (that's what I would do)?
Termination
in #[test]
I don't really understand how libtest works. Maybe ask @alexcrichton (that's what I would do)? Unit tests are basically generated by a macro, so you need to change that macro, or its caller, to handle return types that are not ()
.
@bkchr
Can you at least join the IRC/gitter?
@bkchr just checking in -- I saw you and @arielb1 were conversing on gitter some time back, any progress? Get suck somewhere?
No sorry, no progress up to now. Currently I have a lot of things to do, but I hope that I will find some time this week to start on this.
@bkchr If you need some help let me know!
I'm currently a little bit stuck, I want to create the Obligation. To create the Obligation I need a TraifRef, for a TraitRef I need a DefId. Can someone point me to some code on how to create a DefId from the Termination Trait?
@bkchr The trait should be added to the lang item list, e.g.: https://github.com/rust-lang/rust/blob/ade0b01ebf18550e41d24c6e36f91afaccd7f389/src/librustc/middle/lang_items.rs#L312
and get marked with #[termination_trait]
, e.g.: https://github.com/rust-lang/rust/blob/ade0b01ebf18550e41d24c6e36f91afaccd7f389/src/libcore/fmt/mod.rs#L525-L526
Yeah that is not the problem, I already done that. I need to check for the termination trait in the check_fn function. I want to use register_predicate_obligation and for that I need the defid of the termination trait.
Oh, then all you need is tcx.require_lang_item(TerminationTraitLangItem)
.
@bkchr how goes? Just checking in again. =) No worries if you are busy, just want to make sure you're getting all the help you need.
Sorry, busy at the moment :/ Up to now, I got all the help I needed :)
This is the code to check for the TerminationTrait: https://github.com/bkchr/rust/blob/f185e355d8970c3350269ddbc6dfe3b8f678dc44/src/librustc_typeck/check/mod.rs#L1108
I think that I not checking on the return type of the function? I get the following error:
error[E0277]: the trait bound `Self: std::ops::Termination` is not satisfied
--> src/rustc/rustc.rs:15:11
|
15 | fn main() { rustc_driver::main() }
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Termination` is not implemented for `Self`
|
= help: consider adding a `where Self: std::ops::Termination` bound
What does I need to change, to check on the return type of the function?
@bkchr I'd recommend joining the compiler-middle working group gitter at https://gitter.im/rust-impl-period/WG-compiler-middle for feedback, as well as trying the #rust-internals IRC channel at https://chat.mibbit.com/?server=irc.mozilla.org%3A%2B6697&channel=%23rust-internals . :)
@bstrie yeah thanks, I'm already part of the gitter chat and could solve my problem. :)
@bkchr your problem is on this line. The trait reference you want to build there is something like R: Termination
where R
is the return type of the function. This is specified by building up an appropriate "substs", which is the set of values to substitute for the trait's type parameters (in this case, Self
).
However, you are invoking the Substs::identity_for_item
method on the trait. This will give you back the substitutions one would use inside the trait definition itself. i.e., in this case you are mapping the Self
parameter declared on the Termination
trait to Self
. This would be appropriate if you were checking the definition of some function inside the Terminator
trait, but not so much here.
What you want instead is to get the return type of the entry function. This is just one of the variables ret_ty
or actual_ret_ty
. Either is fine, but I guess ret_ty
is better -- that corresponds to the return type that the user declared (whereas actual_ret_ty
is the type the actual code returned).
You can make the substs you want by just calling the mk_substs()
method from the tcx. In this case, there is only one parameter, the type, so something like let substs = fcx.tcx.mk_substs(&[ret_ty]);
would work, I think.
I believe the thing to use is tcx.mk_substs_trait(ret_ty, &[])
.
@bkchr just checking in -- had a chance to put that advice to use? (Also, for faster responses, it may be wise to ask on gitter.)
Yeah, I could solve the problem with gitter :)
@bkchr how goes? Just checking in.
Everything okay, I will probably get some time this week to look into the code.
Is there room for one more person to help with this? I would like to begin contributing to the Rust community before year's end and would love to help with this feature. Hopefully it wouldn't be too confusing to have two people collaborating on this.
@U007D
This is a small feature and @bkchr is almost done with it.
Ah, ok--that's good to know, thanks. I'll keep an eye out for something else I can help with.
@U007D Have you seen https://www.rustaceans.org/findwork ?
@lnicola Yes, I have! I'm trying to find something at the intersection of something I feel confident about being able to work on (ie. be a net positive) and I'm passionate about. To be honest, even though I've been learning Rust for about a year, it's still a little intimidating to step up to volunteer for something. FWIW, that is by no means the fault of the Rust community--the Rust community has bent over backwards to make this an open, welcoming and inclusive culture--the best I've had the pleasure of experiencing. (I suspect it has more to do with old battle scars from years and years of experience in the tech industry where teams tend to be competitive rather than collaborative.)
Anyway, it's my goal to pick something this year and to at least begin making a positive contribution. It's time for me to get involved! :)
Thanks for the suggestion, @lnicola. That is a good resource.
@bkchr any updates?
I'm on it (https://github.com/rust-lang/rust/pull/46479). Now I have holidays and time to work in the comments in the pull request. Sorry for all the delays :/
Oh, sorry, didn't notice you had a pull request up. Cross-linked it.
Hello, uhm. So I thought I'd start my potential Rust contributor career by bikeshedding, as is tradition. Specifically, about this one:
How about Exit
? It's short and to the point, fitting existing Rust vocabulary. Exit-as-a-noun is a natural counterpart to exit-as-a-verb which, to most, is the familiar word for ending a process "from inside" in a controlled manner.
To a C++ programmer specifically, "termination" brings to mind std::terminate
which defaults to abnormal termination (calling abort
) and is basically the C++ equivalent to a panic (but unlike a panic, never unwinds the stack).
Wait, ignore that comment, looks like the RFC left that explicitly open to discussion.
I do like Exit
as a trait name.
I'm figuring that the feature will get stabilized far before the trait does, like happened with Carrier
.
FWIW that's another case where I'm really glad that the provisional name was changed before stabilization :D
As the author of the RFC I have no objection to changing the name of the trait to Exit
, or anything else really. I'm not particularly good at naming things and happy for someone else to have a better idea.
Is the trait supposed to be
std::Termination
, not std::ops::Termination
?The trait could not be placed into libcore
, because the implementation for Result
requires to print to stderr
and that can not be done in libcore
.
@bkchr The impl being in libstd doesn't mean the trait needs to be in libstd as well.
@kennytm I know, but Result is also defined in libcore, so Termination can not be implemented for Result in libstd.
This is a tracking issue for the RFC "
?
inmain
" (rust-lang/rfcs#1937).Steps:
?
inmain
(#46479)?
in doctest?
in#[test]
Stabilizations:
main
with non-() return types (https://github.com/rust-lang/rust/issues/48453) Merged in https://github.com/rust-lang/rust/pull/49162Related issues:
Unresolved questions:
this will be stabilized by #48453no longer true after https://github.com/rust-lang/rust/pull/48497