@@ -9,6 +9,7 @@ use rustc_hir::def::DefKind;
99use rustc_hir:: def_id:: CrateNum ;
1010use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1111use rustc_middle:: mir:: interpret:: AllocInit ;
12+ use rustc_middle:: mir:: mono:: Linkage ;
1213use rustc_middle:: ty:: { Instance , Ty } ;
1314use rustc_middle:: { mir, ty} ;
1415use rustc_span:: Symbol ;
@@ -138,7 +139,7 @@ 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+ let mut instance_and_crate: Option < ( ty:: Instance < ' _ > , CrateNum , bool ) > = None ;
142143 helpers:: iter_exported_symbols ( tcx, |cnum, def_id| {
143144 let attrs = tcx. codegen_fn_attrs ( def_id) ;
144145 // Skip over imports of items.
@@ -155,39 +156,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
155156
156157 let instance = Instance :: mono ( tcx, def_id) ;
157158 let symbol_name = tcx. symbol_name ( instance) . name ;
159+ let is_weak = attrs. linkage == Some ( Linkage :: WeakAny ) ;
158160 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+ }
179206 }
207+ } else {
208+ instance_and_crate =
209+ Some ( ( ty:: Instance :: mono ( tcx, def_id) , cnum, is_weak) ) ;
180210 }
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) ) ;
187211 }
188212 interp_ok ( ( ) )
189213 } ) ?;
190214
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+
191223 e. insert ( instance_and_crate. map ( |ic| ic. 0 ) )
192224 }
193225 } ;
0 commit comments