@@ -234,20 +234,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
234234 // diverging expression (e.g. it arose from desugaring of `try { return }`),
235235 // we skip issuing a warning because it is autogenerated code.
236236 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+ }
238249 ExprKind :: MethodCall ( segment, ..) => {
239250 self . warn_if_unreachable ( expr. hir_id , segment. ident . span , "call" )
240251 }
252+ // Allow field access when the struct is uninhabited.
253+ ExprKind :: Field ( ..)
254+ if matches ! ( self . diverges. get( ) , Diverges :: UninhabitedExpr ( _, _) ) => { }
241255 _ => self . warn_if_unreachable ( expr. hir_id , expr. span , "expression" ) ,
242256 }
243257
244258 // Any expression that produces a value of type `!` must have diverged,
245259 // unless it's a place expression that isn't being read from, in which case
246260 // diverging would be unsound since we may never actually read the `!`.
247261 // 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+ }
251272 }
252273
253274 // Record the type, which applies it effects.
@@ -353,6 +374,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
353374 self . pat_guaranteed_to_constitute_read_for_never ( * pat)
354375 }
355376
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+
356398 // These nodes (if they have a sub-expr) do constitute a read.
357399 hir:: Node :: Block ( _)
358400 | hir:: Node :: Arm ( _)
@@ -382,7 +424,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
382424 | hir:: Node :: Ty ( _)
383425 | hir:: Node :: AssocItemConstraint ( _)
384426 | hir:: Node :: TraitRef ( _)
385- | hir:: Node :: Pat ( _)
386427 | hir:: Node :: PatField ( _)
387428 | hir:: Node :: LetStmt ( _)
388429 | hir:: Node :: Synthetic
@@ -443,6 +484,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
443484 }
444485 }
445486
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+
446494 #[ instrument( skip( self , expr) , level = "debug" ) ]
447495 fn check_expr_kind (
448496 & self ,
0 commit comments