@@ -234,20 +234,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
234
234
// diverging expression (e.g. it arose from desugaring of `try { return }`),
235
235
// we skip issuing a warning because it is autogenerated code.
236
236
ExprKind :: Call ( ..) if expr. span . is_desugaring ( DesugaringKind :: TryBlock ) => { }
237
- ExprKind :: Call ( callee, _) => self . warn_if_unreachable ( expr. hir_id , callee. span , "call" ) ,
237
+ ExprKind :: Call ( callee, _) => {
238
+ // Do not emit a warning for a call to a constructor.
239
+ let emit_warning = if let ExprKind :: Path ( ref qpath) = callee. kind {
240
+ let res = self . typeck_results . borrow ( ) . qpath_res ( qpath, callee. hir_id ) ;
241
+ !matches ! ( res, Res :: Def ( DefKind :: Ctor ( ..) , _) )
242
+ } else {
243
+ true
244
+ } ;
245
+ if emit_warning {
246
+ self . warn_if_unreachable ( expr. hir_id , callee. span , "call" )
247
+ }
248
+ }
238
249
ExprKind :: MethodCall ( segment, ..) => {
239
250
self . warn_if_unreachable ( expr. hir_id , segment. ident . span , "call" )
240
251
}
252
+ // Allow field access when the struct is uninhabited.
253
+ ExprKind :: Field ( ..)
254
+ if matches ! ( self . diverges. get( ) , Diverges :: UninhabitedExpr ( _, _) ) => { }
241
255
_ => self . warn_if_unreachable ( expr. hir_id , expr. span , "expression" ) ,
242
256
}
243
257
244
258
// Any expression that produces a value of type `!` must have diverged,
245
259
// unless it's a place expression that isn't being read from, in which case
246
260
// diverging would be unsound since we may never actually read the `!`.
247
261
// e.g. `let _ = *never_ptr;` with `never_ptr: *const !`.
248
- if ty. is_never ( ) && self . expr_guaranteed_to_constitute_read_for_never ( expr) {
249
- self . diverges
250
- . set ( self . diverges . get ( ) | Diverges :: Always ( DivergeReason :: Other , expr. span ) ) ;
262
+ let cur_diverges = self . diverges . get ( ) ;
263
+ if !cur_diverges. is_always ( ) && self . expr_guaranteed_to_constitute_read_for_never ( expr) {
264
+ if ty. is_never ( ) {
265
+ // Any expression that produces a value of type `!` must have diverged.
266
+ self . diverges . set ( cur_diverges | Diverges :: Always ( DivergeReason :: Other , expr. span ) ) ;
267
+ } else if self . ty_is_uninhabited ( ty) {
268
+ // This expression produces a value of uninhabited type.
269
+ // This means it has diverged somehow.
270
+ self . diverges . set ( cur_diverges | Diverges :: UninhabitedExpr ( expr. hir_id , expr. span ) ) ;
271
+ }
251
272
}
252
273
253
274
// Record the type, which applies it effects.
@@ -353,6 +374,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
353
374
self . pat_guaranteed_to_constitute_read_for_never ( * pat)
354
375
}
355
376
377
+ hir:: Node :: Pat ( parent_pat) => match parent_pat. kind {
378
+ hir:: PatKind :: Lit ( ..) | hir:: PatKind :: Range ( ..) => false ,
379
+
380
+ // These nodes do not have direct sub-exprs.
381
+ hir:: PatKind :: Wild
382
+ | hir:: PatKind :: Binding ( ..)
383
+ | hir:: PatKind :: Struct ( ..)
384
+ | hir:: PatKind :: TupleStruct ( ..)
385
+ | hir:: PatKind :: Or ( ..)
386
+ | hir:: PatKind :: Never
387
+ | hir:: PatKind :: Path ( ..)
388
+ | hir:: PatKind :: Tuple ( ..)
389
+ | hir:: PatKind :: Box ( ..)
390
+ | hir:: PatKind :: Deref ( ..)
391
+ | hir:: PatKind :: Ref ( ..)
392
+ | hir:: PatKind :: Slice ( ..)
393
+ | hir:: PatKind :: Err ( ..) => {
394
+ unreachable ! ( "no sub-expr expected for {parent_pat:?}" )
395
+ }
396
+ } ,
397
+
356
398
// These nodes (if they have a sub-expr) do constitute a read.
357
399
hir:: Node :: Block ( _)
358
400
| hir:: Node :: Arm ( _)
@@ -382,7 +424,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
382
424
| hir:: Node :: Ty ( _)
383
425
| hir:: Node :: AssocItemConstraint ( _)
384
426
| hir:: Node :: TraitRef ( _)
385
- | hir:: Node :: Pat ( _)
386
427
| hir:: Node :: PatField ( _)
387
428
| hir:: Node :: LetStmt ( _)
388
429
| hir:: Node :: Synthetic
@@ -443,6 +484,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
443
484
}
444
485
}
445
486
487
+ fn ty_is_uninhabited ( & self , ty : Ty < ' tcx > ) -> bool {
488
+ let ty = self . resolve_vars_if_possible ( ty) ;
489
+ // Freshen the type as `is_inhabited_from` may call a query on `ty`.
490
+ let ty = self . freshen ( ty) ;
491
+ !ty. is_inhabited_from ( self . tcx , self . parent_module , self . param_env )
492
+ }
493
+
446
494
#[ instrument( skip( self , expr) , level = "debug" ) ]
447
495
fn check_expr_kind (
448
496
& self ,
0 commit comments