@@ -9,6 +9,7 @@ use rustc_hir::def::DefKind;
9
9
use rustc_hir:: def_id:: CrateNum ;
10
10
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
11
11
use rustc_middle:: mir:: interpret:: AllocInit ;
12
+ use rustc_middle:: mir:: mono:: Linkage ;
12
13
use rustc_middle:: ty:: { Instance , Ty } ;
13
14
use rustc_middle:: { mir, ty} ;
14
15
use rustc_span:: Symbol ;
@@ -138,7 +139,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
138
139
Entry :: Occupied ( e) => e. into_mut ( ) ,
139
140
Entry :: Vacant ( e) => {
140
141
// Find it if it was not cached.
141
- let mut instance_and_crate: Option < ( ty:: Instance < ' _ > , CrateNum ) > = None ;
142
+ let mut instance_and_crate: Option < ( ty:: Instance < ' _ > , CrateNum , bool ) > = None ;
142
143
helpers:: iter_exported_symbols ( tcx, |cnum, def_id| {
143
144
let attrs = tcx. codegen_fn_attrs ( def_id) ;
144
145
// Skip over imports of items.
@@ -155,39 +156,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
155
156
156
157
let instance = Instance :: mono ( tcx, def_id) ;
157
158
let symbol_name = tcx. symbol_name ( instance) . name ;
159
+ let is_weak = attrs. linkage == Some ( Linkage :: WeakAny ) ;
158
160
if symbol_name == link_name. as_str ( ) {
159
- if let Some ( ( original_instance, original_cnum) ) = instance_and_crate {
160
- // Make sure we are consistent wrt what is 'first' and 'second'.
161
- let original_span = tcx. def_span ( original_instance. def_id ( ) ) . data ( ) ;
162
- let span = tcx. def_span ( def_id) . data ( ) ;
163
- if original_span < span {
164
- throw_machine_stop ! ( TerminationInfo :: MultipleSymbolDefinitions {
165
- link_name,
166
- first: original_span,
167
- first_crate: tcx. crate_name( original_cnum) ,
168
- second: span,
169
- second_crate: tcx. crate_name( cnum) ,
170
- } ) ;
171
- } else {
172
- throw_machine_stop ! ( TerminationInfo :: MultipleSymbolDefinitions {
173
- link_name,
174
- first: span,
175
- first_crate: tcx. crate_name( cnum) ,
176
- second: original_span,
177
- second_crate: tcx. crate_name( original_cnum) ,
178
- } ) ;
161
+ if let Some ( ( original_instance, original_cnum, original_is_weak) ) =
162
+ instance_and_crate
163
+ {
164
+ match ( is_weak, original_is_weak) {
165
+ ( false , true ) => {
166
+ // Original definition is a weak definition. Override it.
167
+
168
+ instance_and_crate =
169
+ Some ( ( ty:: Instance :: mono ( tcx, def_id) , cnum, is_weak) ) ;
170
+ }
171
+ ( true , false ) => {
172
+ // Current definition is a weak definition. Keep the original one.
173
+ }
174
+ ( true , true ) | ( false , false ) => {
175
+ // Either both definitions are non-weak or both are weak. In
176
+ // either case return an error. For weak definitions we error
177
+ // because it is undefined which definition would have been
178
+ // picked by the linker.
179
+
180
+ // Make sure we are consistent wrt what is 'first' and 'second'.
181
+ let original_span =
182
+ tcx. def_span ( original_instance. def_id ( ) ) . data ( ) ;
183
+ let span = tcx. def_span ( def_id) . data ( ) ;
184
+ if original_span < span {
185
+ throw_machine_stop ! (
186
+ TerminationInfo :: MultipleSymbolDefinitions {
187
+ link_name,
188
+ first: original_span,
189
+ first_crate: tcx. crate_name( original_cnum) ,
190
+ second: span,
191
+ second_crate: tcx. crate_name( cnum) ,
192
+ }
193
+ ) ;
194
+ } else {
195
+ throw_machine_stop ! (
196
+ TerminationInfo :: MultipleSymbolDefinitions {
197
+ link_name,
198
+ first: span,
199
+ first_crate: tcx. crate_name( cnum) ,
200
+ second: original_span,
201
+ second_crate: tcx. crate_name( original_cnum) ,
202
+ }
203
+ ) ;
204
+ }
205
+ }
179
206
}
207
+ } else {
208
+ instance_and_crate =
209
+ Some ( ( ty:: Instance :: mono ( tcx, def_id) , cnum, is_weak) ) ;
180
210
}
181
- if !matches ! ( tcx. def_kind( def_id) , DefKind :: Fn | DefKind :: AssocFn ) {
182
- throw_ub_format ! (
183
- "attempt to call an exported symbol that is not defined as a function"
184
- ) ;
185
- }
186
- instance_and_crate = Some ( ( ty:: Instance :: mono ( tcx, def_id) , cnum) ) ;
187
211
}
188
212
interp_ok ( ( ) )
189
213
} ) ?;
190
214
215
+ if let Some ( ( instance, _, _) ) = instance_and_crate {
216
+ if !matches ! ( tcx. def_kind( instance. def_id( ) ) , DefKind :: Fn | DefKind :: AssocFn ) {
217
+ throw_ub_format ! (
218
+ "attempt to call an exported symbol that is not defined as a function"
219
+ ) ;
220
+ }
221
+ }
222
+
191
223
e. insert ( instance_and_crate. map ( |ic| ic. 0 ) )
192
224
}
193
225
} ;
0 commit comments