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