Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

[RFC] enforce main: fn() -> ! #50

Closed
wants to merge 1 commit into from
Closed

[RFC] enforce main: fn() -> ! #50

wants to merge 1 commit into from

Conversation

japaric
Copy link
Member

@japaric japaric commented Dec 30, 2017

Now that the Termination trait has been implemented (cf. rust-lang/rust#46479) we can narrow down
the return type of main to be one of the types that implements the Termination trait.

This RFC proposes only implementing Termination for the never type (!) -- currently
Termination is only implemented for the unit type (()). With this change all programs that link
to cortex-m-rt are forced to set the signature of main to be fn() -> !. The rationale here is
that a divergent (never ending) function better matches the logic of microcontroller programs.

When the change is implemented the user will be forced to make main into a divergent function.

This won't work:

#![feature(termination_trait)]
#![no_std]

fn main() {}
//~^ error: the trait `cortex_m_rt::lang_items::Termination` is not implemented for `()`

Whereas this would works:

#![feature(termination_trait)]
#![no_std]

fn main() -> ! {
    loop {}
}

Drawbacks

Diagnostics for the Termination feature are rather bad at the moment. If this change is
implemented and you write a program where main: fn() but forget to add the
#![feature(termination_trait)] feature gate you get an unhelpful linker error:

#![no_std]

fn main() {}
$ xargo build
(..)
  = note: /home/japaric/tmp/cortex-m-quickstart/target/thumbv7m-none-eabi/debug/deps/cortex_m_quickstart-0f691e4b3fe1bbf7.cortex_m_quickstart.rcgu.o: In function `main':
          cortex_m_quickstart-fd49a734b68c9115d8712982b4fdc764.rs:(.text.main+0x36): undefined reference to `cortex_m_rt::lang_items::start'

cc @pftbest

@japaric japaric added this to the 0.4.0 milestone Dec 30, 2017
@pftbest
Copy link
Contributor

pftbest commented Dec 30, 2017

This change seems logical, and I like it, but I'm not very happy about adding one more #![feature] to the user's code. It's one more roadblock on the path to stabilization. But maybe it will be stable soon, because it's a very popular feature.

Also I found one more error message that is not very helpful:

fn main() -> ! {
    while true {
    }
}
error[E0308]: mismatched types
 --> <source>:2:5
  |
1 |   fn main() -> ! {
  |                - expected `!` because of return type
2 | /     while true {
3 | |     }
  | |_____^ expected !, found ()
  |
  = note: expected type `!`
             found type `()`
error: aborting due to previous error

@japaric
Copy link
Member Author

japaric commented Jan 9, 2018

I'm not very happy about adding one more #![feature] to the user's code.

Me neither. I wish the diagnostics for forgetting the feature gate were better. We can always wait until the feature gets stabilized.

Also I found one more error message that is not very helpful:

That seems unrelated to the termination trait. You get the same error with any other function:

fn foo() -> ! {
    while true {}
    //^ error: expected !, found ()
}

I think the compiler doesn't check the while condition to pick the return type accordingly. That may be related to const eval; for instance should this one work (be interpreted as !): let cond = true; while cond {}? what about this one: const COND: bool = true; while COND {}?

@pftbest
Copy link
Contributor

pftbest commented Jan 9, 2018

@japaric sorry, I didn't mean to say that while cond {} should be evaluated at compile time, I just noticed a missing warning.

When you write this code:

fn main() {
    while true {
    }
}

You get a nice warning that suggests using loop instead:

warning: denote infinite loops with `loop { ... }`
 --> <source>:3:5
  |
3 |     while true {
  |     ^^^^^^^^^^ help: use `loop`
  |
  = note: #[warn(while_true)] on by default

But when you have a diverging function, you don't see such message.

@japaric
Copy link
Member Author

japaric commented Feb 7, 2018

Oh, OK. That sounds like it might be worth to report in rust-lang/rust?

@japaric
Copy link
Member Author

japaric commented Aug 2, 2018

This has been done. The entry! requires the entry point to be a divergent function.

@japaric japaric closed this Aug 2, 2018
@jonas-schievink jonas-schievink deleted the never-termination branch January 13, 2020 21:55
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants