@@ -127,16 +127,31 @@ extern {}
127
127
/// run.
128
128
pub unsafe fn try < F : FnOnce ( ) > ( f : F ) -> Result < ( ) , Box < Any + Send > > {
129
129
let mut f = Some ( f) ;
130
+ return inner_try ( try_fn :: < F > , & mut f as * mut _ as * mut c_void ) ;
130
131
131
- let prev = PANICKING . with ( |s| s. get ( ) ) ;
132
- PANICKING . with ( |s| s. set ( false ) ) ;
133
- let ep = rust_try ( try_fn :: < F > , & mut f as * mut _ as * mut c_void ) ;
134
- PANICKING . with ( |s| s. set ( prev) ) ;
135
- return if ep. is_null ( ) {
136
- Ok ( ( ) )
137
- } else {
138
- Err ( imp:: cleanup ( ep) )
139
- } ;
132
+ // If an inner function were not used here, then this generic function `try`
133
+ // uses the native symbol `rust_try`, for which the code is statically
134
+ // linked into the standard library. This means that the DLL for the
135
+ // standard library must have `rust_try` as an exposed symbol that
136
+ // downstream crates can link against (because monomorphizations of `try` in
137
+ // downstream crates will have a reference to the `rust_try` symbol).
138
+ //
139
+ // On MSVC this requires the symbol `rust_try` to be tagged with
140
+ // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
141
+ // files and instead just have this non-generic shim the compiler can take
142
+ // care of exposing correctly.
143
+ unsafe fn inner_try ( f : extern fn ( * mut c_void ) , data : * mut c_void )
144
+ -> Result < ( ) , Box < Any + Send > > {
145
+ let prev = PANICKING . with ( |s| s. get ( ) ) ;
146
+ PANICKING . with ( |s| s. set ( false ) ) ;
147
+ let ep = rust_try ( f, data) ;
148
+ PANICKING . with ( |s| s. set ( prev) ) ;
149
+ if ep. is_null ( ) {
150
+ Ok ( ( ) )
151
+ } else {
152
+ Err ( imp:: cleanup ( ep) )
153
+ }
154
+ }
140
155
141
156
extern fn try_fn < F : FnOnce ( ) > ( opt_closure : * mut c_void ) {
142
157
let opt_closure = opt_closure as * mut Option < F > ;
0 commit comments