1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use rustc_span::symbol::sym;
use rustc_span::Symbol;

use crate::{attr, Attribute};

#[derive(Debug)]
pub enum EntryPointType {
    /// This function is not an entrypoint.
    None,
    /// This is a function called `main` at the root level.
    /// ```
    /// fn main() {}
    /// ```
    MainNamed,
    /// This is a function with the `#[rustc_main]` attribute.
    /// Used by the testing harness to create the test entrypoint.
    /// ```ignore (clashes with test entrypoint)
    /// #[rustc_main]
    /// fn main() {}
    /// ```
    RustcMainAttr,
    /// This is a function with the `#[start]` attribute.
    /// ```ignore (clashes with test entrypoint)
    /// #[start]
    /// fn main() {}
    /// ```
    Start,
    /// This function is **not** an entrypoint but simply named `main` (not at the root).
    /// This is only used for diagnostics.
    /// ```
    /// #[allow(dead_code)]
    /// mod meow {
    ///     fn main() {}
    /// }
    /// ```
    OtherMain,
}

pub fn entry_point_type(
    attrs: &[Attribute],
    at_root: bool,
    name: Option<Symbol>,
) -> EntryPointType {
    if attr::contains_name(attrs, sym::start) {
        EntryPointType::Start
    } else if attr::contains_name(attrs, sym::rustc_main) {
        EntryPointType::RustcMainAttr
    } else {
        if let Some(name) = name
            && name == sym::main
        {
            if at_root {
                // This is a top-level function so it can be `main`.
                EntryPointType::MainNamed
            } else {
                EntryPointType::OtherMain
            }
        } else {
            EntryPointType::None
        }
    }
}