@@ -95,7 +95,7 @@ use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet};
9595use rustc_index:: vec:: IndexVec ;
9696use rustc_middle:: hir:: map:: Map ;
9797use rustc_middle:: ty:: query:: Providers ;
98- use rustc_middle:: ty:: { self , DefIdTree , RootVariableMinCaptureList , TyCtxt } ;
98+ use rustc_middle:: ty:: { self , DefIdTree , RootVariableMinCaptureList , Ty , TyCtxt } ;
9999use rustc_session:: lint;
100100use rustc_span:: symbol:: { kw, sym, Symbol } ;
101101use rustc_span:: Span ;
@@ -123,8 +123,8 @@ rustc_index::newtype_index! {
123123#[ derive( Copy , Clone , PartialEq , Debug ) ]
124124enum LiveNodeKind {
125125 UpvarNode ( Span ) ,
126- ExprNode ( Span ) ,
127- VarDefNode ( Span ) ,
126+ ExprNode ( Span , HirId ) ,
127+ VarDefNode ( Span , HirId ) ,
128128 ClosureNode ,
129129 ExitNode ,
130130}
@@ -133,8 +133,8 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
133133 let sm = tcx. sess . source_map ( ) ;
134134 match lnk {
135135 UpvarNode ( s) => format ! ( "Upvar node [{}]" , sm. span_to_diagnostic_string( s) ) ,
136- ExprNode ( s) => format ! ( "Expr node [{}]" , sm. span_to_diagnostic_string( s) ) ,
137- VarDefNode ( s) => format ! ( "Var def node [{}]" , sm. span_to_diagnostic_string( s) ) ,
136+ ExprNode ( s, _ ) => format ! ( "Expr node [{}]" , sm. span_to_diagnostic_string( s) ) ,
137+ VarDefNode ( s, _ ) => format ! ( "Var def node [{}]" , sm. span_to_diagnostic_string( s) ) ,
138138 ClosureNode => "Closure node" . to_owned ( ) ,
139139 ExitNode => "Exit node" . to_owned ( ) ,
140140 }
@@ -297,7 +297,7 @@ impl IrMaps<'tcx> {
297297 }
298298
299299 pat. each_binding ( |_, hir_id, _, ident| {
300- self . add_live_node_for_node ( hir_id, VarDefNode ( ident. span ) ) ;
300+ self . add_live_node_for_node ( hir_id, VarDefNode ( ident. span , hir_id ) ) ;
301301 self . add_variable ( Local ( LocalInfo {
302302 id : hir_id,
303303 name : ident. name ,
@@ -391,14 +391,14 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
391391 hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, ref path) ) => {
392392 debug ! ( "expr {}: path that leads to {:?}" , expr. hir_id, path. res) ;
393393 if let Res :: Local ( _var_hir_id) = path. res {
394- self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span ) ) ;
394+ self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span , expr . hir_id ) ) ;
395395 }
396396 intravisit:: walk_expr ( self , expr) ;
397397 }
398398 hir:: ExprKind :: Closure ( ..) => {
399399 // Interesting control flow (for loops can contain labeled
400400 // breaks or continues)
401- self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span ) ) ;
401+ self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span , expr . hir_id ) ) ;
402402
403403 // Make a live_node for each captured variable, with the span
404404 // being the location that the variable is used. This results
@@ -426,11 +426,11 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
426426
427427 // live nodes required for interesting control flow:
428428 hir:: ExprKind :: If ( ..) | hir:: ExprKind :: Match ( ..) | hir:: ExprKind :: Loop ( ..) => {
429- self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span ) ) ;
429+ self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span , expr . hir_id ) ) ;
430430 intravisit:: walk_expr ( self , expr) ;
431431 }
432432 hir:: ExprKind :: Binary ( op, ..) if op. node . is_lazy ( ) => {
433- self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span ) ) ;
433+ self . add_live_node_for_node ( expr. hir_id , ExprNode ( expr. span , expr . hir_id ) ) ;
434434 intravisit:: walk_expr ( self , expr) ;
435435 }
436436
@@ -978,11 +978,26 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
978978
979979 hir:: ExprKind :: Call ( ref f, ref args) => {
980980 let m = self . ir . tcx . parent_module ( expr. hir_id ) . to_def_id ( ) ;
981- let succ = if self . ir . tcx . is_ty_uninhabited_from (
982- m,
983- self . typeck_results . expr_ty ( expr) ,
984- self . param_env ,
985- ) {
981+ let ty = self . typeck_results . expr_ty ( expr) ;
982+ let succ = if self . ir . tcx . is_ty_uninhabited_from ( m, ty, self . param_env ) {
983+ if let LiveNodeKind :: ExprNode ( succ_span, succ_id) = self . ir . lnks [ succ] {
984+ self . warn_about_unreachable (
985+ expr. span ,
986+ ty,
987+ succ_span,
988+ succ_id,
989+ "expression" ,
990+ ) ;
991+ } else if let LiveNodeKind :: VarDefNode ( succ_span, succ_id) = self . ir . lnks [ succ]
992+ {
993+ self . warn_about_unreachable (
994+ expr. span ,
995+ ty,
996+ succ_span,
997+ succ_id,
998+ "definition" ,
999+ ) ;
1000+ }
9861001 self . exit_ln
9871002 } else {
9881003 succ
@@ -993,11 +1008,26 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
9931008
9941009 hir:: ExprKind :: MethodCall ( .., ref args, _) => {
9951010 let m = self . ir . tcx . parent_module ( expr. hir_id ) . to_def_id ( ) ;
996- let succ = if self . ir . tcx . is_ty_uninhabited_from (
997- m,
998- self . typeck_results . expr_ty ( expr) ,
999- self . param_env ,
1000- ) {
1011+ let ty = self . typeck_results . expr_ty ( expr) ;
1012+ let succ = if self . ir . tcx . is_ty_uninhabited_from ( m, ty, self . param_env ) {
1013+ if let LiveNodeKind :: ExprNode ( succ_span, succ_id) = self . ir . lnks [ succ] {
1014+ self . warn_about_unreachable (
1015+ expr. span ,
1016+ ty,
1017+ succ_span,
1018+ succ_id,
1019+ "expression" ,
1020+ ) ;
1021+ } else if let LiveNodeKind :: VarDefNode ( succ_span, succ_id) = self . ir . lnks [ succ]
1022+ {
1023+ self . warn_about_unreachable (
1024+ expr. span ,
1025+ ty,
1026+ succ_span,
1027+ succ_id,
1028+ "definition" ,
1029+ ) ;
1030+ }
10011031 self . exit_ln
10021032 } else {
10031033 succ
@@ -1274,6 +1304,47 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
12741304
12751305 ln
12761306 }
1307+
1308+ fn warn_about_unreachable (
1309+ & mut self ,
1310+ orig_span : Span ,
1311+ orig_ty : Ty < ' tcx > ,
1312+ expr_span : Span ,
1313+ expr_id : HirId ,
1314+ descr : & str ,
1315+ ) {
1316+ if !orig_ty. is_never ( ) {
1317+ // Unreachable code warnings are already emitted during type checking.
1318+ // However, during type checking, full type information is being
1319+ // calculated but not yet available, so the check for diverging
1320+ // expressions due to uninhabited result types is pretty crude and
1321+ // only checks whether ty.is_never(). Here, we have full type
1322+ // information available and can issue warnings for less obviously
1323+ // uninhabited types (e.g. empty enums). The check above is used so
1324+ // that we do not emit the same warning twice if the uninhabited type
1325+ // is indeed `!`.
1326+
1327+ self . ir . tcx . struct_span_lint_hir (
1328+ lint:: builtin:: UNREACHABLE_CODE ,
1329+ expr_id,
1330+ expr_span,
1331+ |lint| {
1332+ let msg = format ! ( "unreachable {}" , descr) ;
1333+ lint. build ( & msg)
1334+ . span_label ( expr_span, & msg)
1335+ . span_label ( orig_span, "any code following this expression is unreachable" )
1336+ . span_note (
1337+ orig_span,
1338+ & format ! (
1339+ "this expression has type `{}`, which is uninhabited" ,
1340+ orig_ty
1341+ ) ,
1342+ )
1343+ . emit ( ) ;
1344+ } ,
1345+ ) ;
1346+ }
1347+ }
12771348}
12781349
12791350// _______________________________________________________________________
0 commit comments