@@ -5,6 +5,7 @@ use std::path::Path;
55use  rustc_abi:: { Align ,  AlignFromBytesError ,  CanonAbi ,  Size } ; 
66use  rustc_apfloat:: Float ; 
77use  rustc_ast:: expand:: allocator:: alloc_error_handler_name; 
8+ use  rustc_hir:: attrs:: Linkage ; 
89use  rustc_hir:: def:: DefKind ; 
910use  rustc_hir:: def_id:: CrateNum ; 
1011use  rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ; 
@@ -138,7 +139,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
138139            Entry :: Occupied ( e)  => e. into_mut ( ) , 
139140            Entry :: Vacant ( e)  => { 
140141                // Find it if it was not cached. 
141-                 let  mut  instance_and_crate:  Option < ( ty:: Instance < ' _ > ,  CrateNum ) >  = None ; 
142+ 
143+                 struct  SymbolTarget < ' tcx >  { 
144+                     instance :  ty:: Instance < ' tcx > , 
145+                     cnum :  CrateNum , 
146+                     is_weak :  bool , 
147+                 } 
148+                 let  mut  symbol_target:  Option < SymbolTarget < ' tcx > >  = None ; 
142149                helpers:: iter_exported_symbols ( tcx,  |cnum,  def_id| { 
143150                    let  attrs = tcx. codegen_fn_attrs ( def_id) ; 
144151                    // Skip over imports of items. 
@@ -155,40 +162,80 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
155162
156163                    let  instance = Instance :: mono ( tcx,  def_id) ; 
157164                    let  symbol_name = tcx. symbol_name ( instance) . name ; 
165+                     let  is_weak = attrs. linkage  == Some ( Linkage :: WeakAny ) ; 
158166                    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-                                 } ) ; 
167+                         if  let  Some ( original)  = & symbol_target { 
168+                             // There is more than one definition with this name. What we do now 
169+                             // depends on whether one or both definitions are weak. 
170+                             match  ( is_weak,  original. is_weak )  { 
171+                                 ( false ,  true )  => { 
172+                                     // Original definition is a weak definition. Override it. 
173+ 
174+                                     symbol_target = Some ( SymbolTarget  { 
175+                                         instance :  ty:: Instance :: mono ( tcx,  def_id) , 
176+                                         cnum, 
177+                                         is_weak, 
178+                                     } ) ; 
179+                                 } 
180+                                 ( true ,  false )  => { 
181+                                     // Current definition is a weak definition. Keep the original one. 
182+                                 } 
183+                                 ( true ,  true )  | ( false ,  false )  => { 
184+                                     // Either both definitions are non-weak or both are weak. In 
185+                                     // either case return an error. For weak definitions we error 
186+                                     // because it is unspecified which definition would have been 
187+                                     // picked by the linker. 
188+ 
189+                                     // Make sure we are consistent wrt what is 'first' and 'second'. 
190+                                     let  original_span =
191+                                         tcx. def_span ( original. instance . def_id ( ) ) . data ( ) ; 
192+                                     let  span = tcx. def_span ( def_id) . data ( ) ; 
193+                                     if  original_span < span { 
194+                                         throw_machine_stop ! ( 
195+                                             TerminationInfo :: MultipleSymbolDefinitions  { 
196+                                                 link_name, 
197+                                                 first:  original_span, 
198+                                                 first_crate:  tcx. crate_name( original. cnum) , 
199+                                                 second:  span, 
200+                                                 second_crate:  tcx. crate_name( cnum) , 
201+                                             } 
202+                                         ) ; 
203+                                     }  else  { 
204+                                         throw_machine_stop ! ( 
205+                                             TerminationInfo :: MultipleSymbolDefinitions  { 
206+                                                 link_name, 
207+                                                 first:  span, 
208+                                                 first_crate:  tcx. crate_name( cnum) , 
209+                                                 second:  original_span, 
210+                                                 second_crate:  tcx. crate_name( original. cnum) , 
211+                                             } 
212+                                         ) ; 
213+                                     } 
214+                                 } 
179215                            } 
216+                         }  else  { 
217+                             symbol_target = Some ( SymbolTarget  { 
218+                                 instance :  ty:: Instance :: mono ( tcx,  def_id) , 
219+                                 cnum, 
220+                                 is_weak, 
221+                             } ) ; 
180222                        } 
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) ) ; 
187223                    } 
188224                    interp_ok ( ( ) ) 
189225                } ) ?; 
190226
191-                 e. insert ( instance_and_crate. map ( |ic| ic. 0 ) ) 
227+                 // Once we identified the instance corresponding to the symbol, ensure 
228+                 // it is a function. It is okay to encounter non-functions in the search above 
229+                 // as long as the final instance we arrive at is a function. 
230+                 if  let  Some ( SymbolTarget  {  instance,  .. } )  = symbol_target { 
231+                     if  !matches ! ( tcx. def_kind( instance. def_id( ) ) ,  DefKind :: Fn  | DefKind :: AssocFn )  { 
232+                         throw_ub_format ! ( 
233+                             "attempt to call an exported symbol that is not defined as a function" 
234+                         ) ; 
235+                     } 
236+                 } 
237+ 
238+                 e. insert ( symbol_target. map ( |SymbolTarget  {  instance,  .. } | instance) ) 
192239            } 
193240        } ; 
194241        match  instance { 
0 commit comments