8
8
#![ feature( is_terminal) ]
9
9
#![ feature( once_cell) ]
10
10
#![ feature( decl_macro) ]
11
+ #![ feature( panic_info_message) ]
11
12
#![ recursion_limit = "256" ]
12
13
#![ allow( rustc:: potential_query_instability) ]
13
14
#![ deny( rustc:: untranslatable_diagnostic) ]
@@ -30,6 +31,8 @@ use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
30
31
use rustc_interface:: { interface, Queries } ;
31
32
use rustc_lint:: LintStore ;
32
33
use rustc_metadata:: locator;
34
+ use rustc_query_impl:: QueryCtxt ;
35
+ use rustc_query_system:: query:: QueryContext ;
33
36
use rustc_save_analysis as save;
34
37
use rustc_save_analysis:: DumpHandler ;
35
38
use rustc_session:: config:: { nightly_options, CG_OPTIONS , Z_OPTIONS } ;
@@ -45,7 +48,6 @@ use rustc_target::json::ToJson;
45
48
46
49
use std:: borrow:: Cow ;
47
50
use std:: cmp:: max;
48
- use std:: env;
49
51
use std:: ffi:: OsString ;
50
52
use std:: fs;
51
53
use std:: io:: { self , IsTerminal , Read , Write } ;
@@ -55,6 +57,7 @@ use std::process::{self, Command, Stdio};
55
57
use std:: str;
56
58
use std:: sync:: LazyLock ;
57
59
use std:: time:: Instant ;
60
+ use std:: { backtrace, env} ;
58
61
59
62
pub mod args;
60
63
pub mod pretty;
@@ -1181,6 +1184,102 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
1181
1184
}
1182
1185
}
1183
1186
1187
+ struct IceError ;
1188
+ impl From < time:: error:: InvalidFormatDescription > for IceError {
1189
+ fn from ( _: time:: error:: InvalidFormatDescription ) -> IceError {
1190
+ IceError
1191
+ }
1192
+ }
1193
+ impl From < time:: error:: Format > for IceError {
1194
+ fn from ( _: time:: error:: Format ) -> IceError {
1195
+ IceError
1196
+ }
1197
+ }
1198
+ impl From < std:: io:: Error > for IceError {
1199
+ fn from ( _: std:: io:: Error ) -> IceError {
1200
+ IceError
1201
+ }
1202
+ }
1203
+
1204
+ fn write_ice_to_disk ( info : & panic:: PanicInfo < ' _ > ) -> Result < String , IceError > {
1205
+ let capture = backtrace:: Backtrace :: force_capture ( ) ;
1206
+ let now = time:: OffsetDateTime :: now_utc ( ) ;
1207
+ let format = time:: format_description:: parse ( "[year]-[month]-[day]_[hour]:[minute]:[second]" ) ?;
1208
+ let file_now = now. format ( & format) ?;
1209
+ let format = time:: format_description:: parse ( "[year]-[month]-[day] [hour]:[minute]:[second]" ) ?;
1210
+ let now = now. format ( & format) ?;
1211
+ let path = format ! ( "rustc-ice-context-{file_now}.txt" ) ;
1212
+ let mut file = std:: fs:: File :: create ( & path) ?;
1213
+ writeln ! (
1214
+ file,
1215
+ "rustc {}{} running on {} at {now}" ,
1216
+ util:: version_str!( ) . unwrap_or( "unknown_version" ) ,
1217
+ match ( option_env!( "CFG_VER_HASH" ) , option_env!( "CFG_VER_DATE" ) ) {
1218
+ ( Some ( hash) , Some ( date) ) => format!( " ({hash} - {date})" ) ,
1219
+ ( Some ( val) , None ) | ( None , Some ( val) ) => format!( " ({val})" ) ,
1220
+ ( None , None ) => String :: new( ) ,
1221
+ } ,
1222
+ config:: host_triple( ) ,
1223
+ ) ?;
1224
+
1225
+ if let Some ( ( flags, excluded_cargo_defaults) ) = extra_compiler_flags ( ) {
1226
+ writeln ! ( file, "compiler flags:" ) ?;
1227
+ for flag in flags {
1228
+ writeln ! ( file, " {flag}" ) ?;
1229
+ }
1230
+ if excluded_cargo_defaults {
1231
+ writeln ! ( file, "some of the compiler flags provided by cargo are hidden" ) ?;
1232
+ }
1233
+ }
1234
+ writeln ! ( file, "" ) ?;
1235
+ match ( info. message ( ) , info. location ( ) ) {
1236
+ ( Some ( message) , Some ( location) ) => {
1237
+ writeln ! ( file, "panicked at {location}:\n {message}" ) ?;
1238
+ }
1239
+ ( None , Some ( location) ) => {
1240
+ writeln ! ( file, "panicked at {location}" ) ?;
1241
+ }
1242
+ ( Some ( message) , None ) => {
1243
+ writeln ! ( file, "panicked\n {message}" ) ?;
1244
+ }
1245
+ ( None , None ) => {
1246
+ writeln ! ( file, "panicked" ) ?;
1247
+ }
1248
+ }
1249
+
1250
+ writeln ! ( file, "" ) ?;
1251
+ writeln ! ( file, "{}" , capture) ?;
1252
+
1253
+ // Be careful relying on global state here: this code is called from
1254
+ // a panic hook, which means that the global `Handler` may be in a weird
1255
+ // state if it was responsible for triggering the panic.
1256
+ // This the same as `interface::try_print_query_stack` but writing to file.
1257
+ rustc_middle:: ty:: tls:: with_context_opt ( |icx| {
1258
+ let Some ( icx) = icx else { return Err ( IceError ) ; } ;
1259
+ let qcx = QueryCtxt :: from_tcx ( icx. tcx ) ;
1260
+ let query_map = qcx. try_collect_active_jobs ( ) ;
1261
+ let mut i = 0 ;
1262
+ let mut current_query = icx. query ;
1263
+ writeln ! ( file, "" ) ?;
1264
+ writeln ! ( file, "query stack during panic:" ) ?;
1265
+ while let Some ( query) = current_query {
1266
+ let Some ( query_info) = query_map. as_ref ( ) . and_then ( |map| map. get ( & query) ) else {
1267
+ break ;
1268
+ } ;
1269
+ writeln ! (
1270
+ file,
1271
+ "#{} [{:?}] {}" ,
1272
+ i, query_info. query. dep_kind, query_info. query. description
1273
+ ) ?;
1274
+ current_query = query_info. job . parent ;
1275
+ i += 1 ;
1276
+ }
1277
+ writeln ! ( file, "end of query stack" ) ?;
1278
+ Ok ( ( ) )
1279
+ } ) ?;
1280
+ Ok ( path)
1281
+ }
1282
+
1184
1283
static DEFAULT_HOOK : LazyLock < Box < dyn Fn ( & panic:: PanicInfo < ' _ > ) + Sync + Send + ' static > > =
1185
1284
LazyLock :: new ( || {
1186
1285
let hook = panic:: take_hook ( ) ;
@@ -1196,17 +1295,25 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
1196
1295
}
1197
1296
} ;
1198
1297
1298
+ let is_dev = util:: version_str!( ) . map_or_else (
1299
+ || std:: env:: var ( "RUSTC_BACKTRACE_FORCE" ) . as_deref ( ) != Ok ( "1" ) ,
1300
+ |v| {
1301
+ v. ends_with ( "-dev" )
1302
+ && std:: env:: var ( "RUSTC_BACKTRACE_FORCE" ) . as_deref ( ) != Ok ( "0" )
1303
+ } ,
1304
+ ) ;
1305
+ let written_ice = if !is_dev { write_ice_to_disk ( info) } else { Err ( IceError ) } ;
1199
1306
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
1200
1307
// Don't do this for delayed bugs, which already emit their own more useful backtrace.
1201
- if !info. payload ( ) . is :: < rustc_errors:: DelayedBugPanic > ( ) {
1308
+ if !info. payload ( ) . is :: < rustc_errors:: DelayedBugPanic > ( ) && written_ice . is_err ( ) {
1202
1309
( * DEFAULT_HOOK ) ( info) ;
1203
1310
1204
1311
// Separate the output with an empty line
1205
1312
eprintln ! ( ) ;
1206
1313
}
1207
1314
1208
1315
// Print the ICE message
1209
- report_ice ( info, BUG_REPORT_URL ) ;
1316
+ report_ice ( info, BUG_REPORT_URL , written_ice . ok ( ) ) ;
1210
1317
} ) ) ;
1211
1318
hook
1212
1319
} ) ;
@@ -1217,7 +1324,7 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
1217
1324
///
1218
1325
/// When `install_ice_hook` is called, this function will be called as the panic
1219
1326
/// hook.
1220
- pub fn report_ice ( info : & panic:: PanicInfo < ' _ > , bug_report_url : & str ) {
1327
+ pub fn report_ice ( info : & panic:: PanicInfo < ' _ > , bug_report_url : & str , reported_ice : Option < String > ) {
1221
1328
let fallback_bundle =
1222
1329
rustc_errors:: fallback_fluent_bundle ( rustc_errors:: DEFAULT_LOCALE_RESOURCES , false ) ;
1223
1330
let emitter = Box :: new ( rustc_errors:: emitter:: EmitterWriter :: stderr (
@@ -1238,39 +1345,51 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
1238
1345
if !info. payload ( ) . is :: < rustc_errors:: ExplicitBug > ( )
1239
1346
&& !info. payload ( ) . is :: < rustc_errors:: DelayedBugPanic > ( )
1240
1347
{
1241
- let mut d = rustc_errors:: Diagnostic :: new ( rustc_errors:: Level :: Bug , "unexpected panic" ) ;
1348
+ let mut d = rustc_errors:: Diagnostic :: new (
1349
+ rustc_errors:: Level :: Bug ,
1350
+ "the compiler unexpectedly panicked. this is a bug." ,
1351
+ ) ;
1242
1352
handler. emit_diagnostic ( & mut d) ;
1243
1353
}
1244
1354
1245
- let mut xs: Vec < Cow < ' static , str > > = vec ! [
1246
- "the compiler unexpectedly panicked. this is a bug." . into( ) ,
1247
- format!( "we would appreciate a bug report: {bug_report_url}" ) . into( ) ,
1248
- format!(
1249
- "rustc {} running on {}" ,
1250
- util:: version_str!( ) . unwrap_or( "unknown_version" ) ,
1251
- config:: host_triple( )
1252
- )
1253
- . into( ) ,
1254
- ] ;
1255
-
1256
- if let Some ( ( flags, excluded_cargo_defaults) ) = extra_compiler_flags ( ) {
1257
- xs. push ( format ! ( "compiler flags: {}" , flags. join( " " ) ) . into ( ) ) ;
1258
-
1259
- if excluded_cargo_defaults {
1260
- xs. push ( "some of the compiler flags provided by cargo are hidden" . into ( ) ) ;
1355
+ let xs: Vec < Cow < ' static , str > > = if let Some ( path) = & reported_ice {
1356
+ vec ! [
1357
+ format!( "all necessary context about this bug was written to `{path}`" ) . into( ) ,
1358
+ format!( "we would appreciate a bug report with this context at <{bug_report_url}>" )
1359
+ . into( ) ,
1360
+ ]
1361
+ } else {
1362
+ let mut xs = vec ! [
1363
+ format!( "we would appreciate a bug report at <{bug_report_url}>" ) . into( ) ,
1364
+ format!(
1365
+ "rustc {} running on {}" ,
1366
+ util:: version_str!( ) . unwrap_or( "unknown_version" ) ,
1367
+ config:: host_triple( )
1368
+ )
1369
+ . into( ) ,
1370
+ ] ;
1371
+ if let Some ( ( flags, excluded_cargo_defaults) ) = extra_compiler_flags ( ) {
1372
+ xs. push ( format ! ( "compiler flags: {}" , flags. join( " " ) ) . into ( ) ) ;
1373
+
1374
+ if excluded_cargo_defaults {
1375
+ xs. push ( "some of the compiler flags provided by cargo are hidden" . into ( ) ) ;
1376
+ }
1261
1377
}
1262
- }
1378
+ xs
1379
+ } ;
1263
1380
1264
1381
for note in & xs {
1265
1382
handler. note_without_error ( note. as_ref ( ) ) ;
1266
1383
}
1267
1384
1268
- // If backtraces are enabled, also print the query stack
1269
- let backtrace = env:: var_os ( "RUST_BACKTRACE" ) . map_or ( false , |x| & x != "0" ) ;
1385
+ if reported_ice. is_none ( ) {
1386
+ // If backtraces are enabled, also print the query stack
1387
+ let backtrace = env:: var_os ( "RUST_BACKTRACE" ) . map_or ( false , |x| & x != "0" ) ;
1270
1388
1271
- let num_frames = if backtrace { None } else { Some ( 2 ) } ;
1389
+ let num_frames = if backtrace { None } else { Some ( 2 ) } ;
1272
1390
1273
- interface:: try_print_query_stack ( & handler, num_frames) ;
1391
+ interface:: try_print_query_stack ( & handler, num_frames) ;
1392
+ }
1274
1393
1275
1394
#[ cfg( windows) ]
1276
1395
unsafe {
0 commit comments