@@ -24,10 +24,12 @@ use rustc_middle::mir::*;
24
24
use rustc_middle:: thir:: { self , ExprId , LintLevel , LocalVarId , Param , ParamId , PatKind , Thir } ;
25
25
use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt , TypeVisitableExt , TypingMode } ;
26
26
use rustc_middle:: { bug, span_bug} ;
27
+ use rustc_session:: lint;
27
28
use rustc_span:: { Span , Symbol , sym} ;
28
29
29
30
use crate :: builder:: expr:: as_place:: PlaceBuilder ;
30
31
use crate :: builder:: scope:: DropKind ;
32
+ use crate :: errors;
31
33
32
34
pub ( crate ) fn closure_saved_names_of_captured_variables < ' tcx > (
33
35
tcx : TyCtxt < ' tcx > ,
@@ -535,6 +537,7 @@ fn construct_fn<'tcx>(
535
537
return_block. unit ( )
536
538
} ) ;
537
539
540
+ builder. lint_and_remove_uninhabited ( ) ;
538
541
let mut body = builder. finish ( ) ;
539
542
540
543
body. spread_arg = if abi == ExternAbi :: RustCall {
@@ -592,6 +595,7 @@ fn construct_const<'a, 'tcx>(
592
595
593
596
builder. build_drop_trees ( ) ;
594
597
598
+ builder. lint_and_remove_uninhabited ( ) ;
595
599
builder. finish ( )
596
600
}
597
601
@@ -810,6 +814,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
810
814
writer. write_mir_fn ( & body, & mut std:: io:: stdout ( ) ) . unwrap ( ) ;
811
815
}
812
816
817
+ fn lint_and_remove_uninhabited ( & mut self ) {
818
+ let mut lints = vec ! [ ] ;
819
+
820
+ for bbdata in self . cfg . basic_blocks . iter_mut ( ) {
821
+ let term = bbdata. terminator_mut ( ) ;
822
+ let TerminatorKind :: Call { ref mut target, destination, .. } = term. kind else {
823
+ continue ;
824
+ } ;
825
+ let Some ( target_bb) = * target else { continue } ;
826
+
827
+ let ty = destination. ty ( & self . local_decls , self . tcx ) . ty ;
828
+ let ty_is_inhabited = ty. is_inhabited_from (
829
+ self . tcx ,
830
+ self . parent_module ,
831
+ self . infcx . typing_env ( self . param_env ) ,
832
+ ) ;
833
+
834
+ if !ty_is_inhabited {
835
+ // Unreachable code warnings are already emitted during type checking.
836
+ // However, during type checking, full type information is being
837
+ // calculated but not yet available, so the check for diverging
838
+ // expressions due to uninhabited result types is pretty crude and
839
+ // only checks whether ty.is_never(). Here, we have full type
840
+ // information available and can issue warnings for less obviously
841
+ // uninhabited types (e.g. empty enums). The check above is used so
842
+ // that we do not emit the same warning twice if the uninhabited type
843
+ // is indeed `!`.
844
+ if !ty. is_never ( ) {
845
+ lints. push ( ( target_bb, ty, term. source_info . span ) ) ;
846
+ }
847
+
848
+ // The presence or absence of a return edge affects control-flow sensitive
849
+ // MIR checks and ultimately whether code is accepted or not. We can only
850
+ // omit the return edge if a return type is visibly uninhabited to a module
851
+ // that makes the call.
852
+ * target = None ;
853
+ }
854
+ }
855
+
856
+ for ( target_bb, orig_ty, orig_span) in lints {
857
+ if orig_span. in_external_macro ( self . tcx . sess . source_map ( ) ) {
858
+ continue ;
859
+ }
860
+ let target_bb = & self . cfg . basic_blocks [ target_bb] ;
861
+ let ( target_loc, descr) = target_bb
862
+ . statements
863
+ . iter ( )
864
+ . find_map ( |stmt| match stmt. kind {
865
+ StatementKind :: StorageLive ( _) | StatementKind :: StorageDead ( _) => None ,
866
+ StatementKind :: FakeRead ( ..) => Some ( ( stmt. source_info , "definition" ) ) ,
867
+ _ => Some ( ( stmt. source_info , "expression" ) ) ,
868
+ } )
869
+ . unwrap_or_else ( || ( target_bb. terminator ( ) . source_info , "expression" ) ) ;
870
+ let lint_root = self . source_scopes [ target_loc. scope ]
871
+ . local_data
872
+ . as_ref ( )
873
+ . unwrap_crate_local ( )
874
+ . lint_root ;
875
+ self . tcx . emit_node_span_lint (
876
+ lint:: builtin:: UNREACHABLE_CODE ,
877
+ lint_root,
878
+ target_loc. span ,
879
+ errors:: UnreachableDueToUninhabited {
880
+ expr : target_loc. span ,
881
+ orig : orig_span,
882
+ descr,
883
+ ty : orig_ty,
884
+ } ,
885
+ ) ;
886
+ }
887
+ }
888
+
813
889
fn finish ( self ) -> Body < ' tcx > {
814
890
let mut body = Body :: new (
815
891
MirSource :: item ( self . def_id . to_def_id ( ) ) ,
0 commit comments