@@ -15,73 +15,97 @@ use syntax::ast::{crate, node_id, item, item_fn};
15
15
use syntax:: codemap:: span;
16
16
use syntax:: visit:: { default_visitor, mk_vt, vt, Visitor , visit_crate, visit_item} ;
17
17
use syntax:: attr:: { attrs_contains_name} ;
18
+ use syntax:: ast_map;
19
+ use core:: util;
18
20
19
21
struct EntryContext {
20
22
session : Session ,
21
23
24
+ ast_map : ast_map:: map ,
25
+
26
+ // The top-level function called 'main'
27
+ main_fn : Option < ( node_id , span ) > ,
28
+
22
29
// The function that has attribute named 'main'
23
30
attr_main_fn : Option < ( node_id , span ) > ,
24
31
25
- // The functions that could be main functions
26
- main_fns : ~[ Option < ( node_id , span ) > ] ,
27
-
28
32
// The function that has the attribute 'start' on it
29
33
start_fn : Option < ( node_id , span ) > ,
34
+
35
+ // The functions that one might think are 'main' but aren't, e.g.
36
+ // main functions not defined at the top level. For diagnostics.
37
+ non_main_fns : ~[ ( node_id , span ) ] ,
30
38
}
31
39
32
40
type EntryVisitor = vt < @mut EntryContext > ;
33
41
34
- pub fn find_entry_point ( session : Session , crate : @crate ) {
42
+ pub fn find_entry_point ( session : Session , crate : @crate , ast_map : ast_map:: map ) {
43
+
44
+ // FIXME #4404 android JNI hacks
45
+ if * session. building_library ||
46
+ session. targ_cfg . os == session:: os_android {
47
+ // No need to find a main function
48
+ return ;
49
+ }
35
50
36
51
let ctxt = @mut EntryContext {
37
52
session : session,
53
+ ast_map : ast_map,
54
+ main_fn : None ,
38
55
attr_main_fn : None ,
39
- main_fns : ~[ ] ,
40
56
start_fn : None ,
57
+ non_main_fns : ~[ ] ,
41
58
} ;
42
59
43
60
visit_crate ( crate , ctxt, mk_vt ( @Visitor {
44
61
visit_item : |item, ctxt, visitor| find_item ( item, ctxt, visitor) ,
45
62
.. * default_visitor ( )
46
63
} ) ) ;
47
64
48
- check_duplicate_main ( ctxt) ;
65
+ configure_main ( ctxt) ;
49
66
}
50
67
51
68
fn find_item( item : @item, ctxt : @mut EntryContext , visitor : EntryVisitor ) {
52
69
match item. node {
53
70
item_fn( * ) => {
54
- // If this is the main function, we must record it in the
55
- // session.
56
-
57
- // FIXME #4404 android JNI hacks
58
- if !* ctxt. session . building_library ||
59
- ctxt. session . targ_cfg . os == session:: os_android {
60
-
61
- if ctxt. attr_main_fn . is_none ( ) &&
62
- item. ident == special_idents:: main {
63
-
64
- ctxt. main_fns . push ( Some ( ( item. id , item. span ) ) ) ;
71
+ if item. ident == special_idents:: main {
72
+ match ctxt. ast_map . find ( & item. id ) {
73
+ Some ( & ast_map:: node_item( _, path) ) => {
74
+ if path. len ( ) == 0 {
75
+ // This is a top-level function so can be 'main'
76
+ if ctxt. main_fn . is_none ( ) {
77
+ ctxt. main_fn = Some ( ( item. id , item. span ) ) ;
78
+ } else {
79
+ ctxt. session . span_err (
80
+ item. span ,
81
+ ~"multiple ' main' functions") ;
82
+ }
83
+ } else {
84
+ // This isn't main
85
+ ctxt. non_main_fns. push ( ( item. id , item. span ) ) ;
86
+ }
87
+ }
88
+ _ => util:: unreachable ( )
65
89
}
90
+ }
66
91
67
- if attrs_contains_name ( item. attrs , ~"main") {
68
- if ctxt. attr_main_fn . is_none ( ) {
69
- ctxt. attr_main_fn = Some ( ( item. id , item. span ) ) ;
70
- } else {
71
- ctxt. session . span_err (
72
- item. span ,
73
- ~"multiple ' main' functions") ;
74
- }
92
+ if attrs_contains_name ( item. attrs , ~"main") {
93
+ if ctxt. attr_main_fn . is_none ( ) {
94
+ ctxt. attr_main_fn = Some ( ( item. id , item. span ) ) ;
95
+ } else {
96
+ ctxt. session . span_err (
97
+ item. span ,
98
+ ~"multiple ' main' functions") ;
75
99
}
100
+ }
76
101
77
- if attrs_contains_name ( item. attrs , ~"start") {
78
- if ctxt. start_fn . is_none ( ) {
79
- ctxt. start_fn = Some ( ( item. id , item. span ) ) ;
80
- } else {
81
- ctxt. session . span_err (
82
- item. span ,
83
- ~"multiple ' start' functions") ;
84
- }
102
+ if attrs_contains_name ( item. attrs , ~"start") {
103
+ if ctxt. start_fn . is_none ( ) {
104
+ ctxt. start_fn = Some ( ( item. id , item. span ) ) ;
105
+ } else {
106
+ ctxt. session . span_err (
107
+ item. span ,
108
+ ~"multiple ' start' functions") ;
85
109
}
86
110
}
87
111
}
@@ -91,29 +115,30 @@ fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) {
91
115
visit_item( item, ctxt, visitor) ;
92
116
}
93
117
94
- // main function checking
95
- //
96
- // be sure that there is only one main function
97
- fn check_duplicate_main ( ctxt : @mut EntryContext ) {
118
+ fn configure_main ( ctxt : @mut EntryContext ) {
98
119
let this = & mut * ctxt;
99
- if this. attr_main_fn . is_none ( ) && this. start_fn . is_none ( ) {
100
- if this. main_fns . len ( ) >= 1 u {
101
- let mut i = 1 u;
102
- while i < this. main_fns . len ( ) {
103
- let ( _, dup_main_span) = this. main_fns [ i] . unwrap ( ) ;
104
- this. session . span_err (
105
- dup_main_span,
106
- ~"multiple ' main' functions") ;
107
- i += 1 ;
108
- }
109
- * this. session . entry_fn = this. main_fns [ 0 ] ;
110
- * this. session . entry_type = Some ( session:: EntryMain ) ;
111
- }
112
- } else if !this. start_fn . is_none ( ) {
120
+ if this. start_fn . is_some ( ) {
113
121
* this. session . entry_fn = this. start_fn ;
114
122
* this. session . entry_type = Some ( session:: EntryStart ) ;
115
- } else {
123
+ } else if this . attr_main_fn . is_some ( ) {
116
124
* this. session . entry_fn = this. attr_main_fn ;
117
125
* this. session . entry_type = Some ( session:: EntryMain ) ;
126
+ } else if this. main_fn . is_some ( ) {
127
+ * this. session . entry_fn = this. main_fn ;
128
+ * this. session . entry_type = Some ( session:: EntryMain ) ;
129
+ } else {
130
+ // No main function
131
+ this. session . err ( ~"main function not found") ;
132
+ if !this. non_main_fns . is_empty ( ) {
133
+ // There were some functions named 'main' though. Try to give the user a hint.
134
+ this. session . note ( ~"the main function must be defined at the crate level \
135
+ but you have one or more functions named ' main' that are not \
136
+ defined at the crate level. Either move the definition or attach \
137
+ the `#[ main] ` attribute to override this behavior. ") ;
138
+ for this. non_main_fns. each |& ( _, span) | {
139
+ this. session . span_note ( span, ~"here is a function named ' main' ") ;
140
+ }
141
+ }
142
+ this. session . abort_if_errors ( ) ;
118
143
}
119
144
}
0 commit comments