@@ -1876,8 +1876,34 @@ declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
1876
1876
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for InvalidValue {
1877
1877
fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & hir:: Expr ) {
1878
1878
1879
- const ZEROED_PATH : & [ Symbol ] = & [ sym:: core, sym:: mem, sym:: zeroed] ;
1880
- const UININIT_PATH : & [ Symbol ] = & [ sym:: core, sym:: mem, sym:: uninitialized] ;
1879
+ #[ derive( Debug ) ]
1880
+ enum InitKind { Zeroed , Uninit } ;
1881
+
1882
+ /// Determine if this expression is a "dangerous initialization".
1883
+ fn is_dangerous_init ( cx : & LateContext < ' _ , ' _ > , expr : & hir:: Expr ) -> Option < InitKind > {
1884
+ const ZEROED_PATH : & [ Symbol ] = & [ sym:: core, sym:: mem, sym:: zeroed] ;
1885
+ const UININIT_PATH : & [ Symbol ] = & [ sym:: core, sym:: mem, sym:: uninitialized] ;
1886
+
1887
+ if let hir:: ExprKind :: Call ( ref path_expr, ref _args) = expr. node {
1888
+ if let hir:: ExprKind :: Path ( ref qpath) = path_expr. node {
1889
+ if let Some ( def_id) = cx. tables . qpath_res ( qpath, path_expr. hir_id )
1890
+ . opt_def_id ( )
1891
+ {
1892
+ if cx. match_def_path ( def_id, & ZEROED_PATH ) {
1893
+ return Some ( InitKind :: Zeroed ) ;
1894
+ }
1895
+ if cx. match_def_path ( def_id, & UININIT_PATH ) {
1896
+ return Some ( InitKind :: Uninit ) ;
1897
+ }
1898
+ // FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and
1899
+ // `MaybeUninit::uninit().assume_init()`.
1900
+ // FIXME: Also detect `transmute` from 0.
1901
+ }
1902
+ }
1903
+ }
1904
+
1905
+ None
1906
+ }
1881
1907
1882
1908
/// Information about why a type cannot be initialized this way.
1883
1909
/// Contains an error message and optionally a span to point at.
@@ -1933,42 +1959,33 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
1933
1959
}
1934
1960
}
1935
1961
1936
- if let hir:: ExprKind :: Call ( ref path_expr, ref _args) = expr. node {
1937
- if let hir:: ExprKind :: Path ( ref qpath) = path_expr. node {
1938
- if let Some ( def_id) = cx. tables . qpath_res ( qpath, path_expr. hir_id ) . opt_def_id ( ) {
1939
- if cx. match_def_path ( def_id, & ZEROED_PATH ) ||
1940
- cx. match_def_path ( def_id, & UININIT_PATH )
1941
- {
1942
- // This conjures an instance of a type out of nothing,
1943
- // using zeroed or uninitialized memory.
1944
- // We are extremely conservative with what we warn about.
1945
- let conjured_ty = cx. tables . expr_ty ( expr) ;
1946
- if let Some ( ( msg, span) ) = ty_find_init_error ( cx. tcx , conjured_ty) {
1947
- let mut err = cx. struct_span_lint (
1948
- INVALID_VALUE ,
1949
- expr. span ,
1950
- & format ! (
1951
- "the type `{}` does not permit {}" ,
1952
- conjured_ty,
1953
- if cx. match_def_path( def_id, & ZEROED_PATH ) {
1954
- "zero-initialization"
1955
- } else {
1956
- "being left uninitialized"
1957
- }
1958
- ) ,
1959
- ) ;
1960
- err. span_label ( expr. span ,
1961
- "this code causes undefined behavior when executed" ) ;
1962
- err. span_label ( expr. span , "help: use `MaybeUninit<T>` instead" ) ;
1963
- if let Some ( span) = span {
1964
- err. span_note ( span, & msg) ;
1965
- } else {
1966
- err. note ( & msg) ;
1967
- }
1968
- err. emit ( ) ;
1969
- }
1970
- }
1962
+ if let Some ( init) = is_dangerous_init ( cx, expr) {
1963
+ // This conjures an instance of a type out of nothing,
1964
+ // using zeroed or uninitialized memory.
1965
+ // We are extremely conservative with what we warn about.
1966
+ let conjured_ty = cx. tables . expr_ty ( expr) ;
1967
+ if let Some ( ( msg, span) ) = ty_find_init_error ( cx. tcx , conjured_ty) {
1968
+ let mut err = cx. struct_span_lint (
1969
+ INVALID_VALUE ,
1970
+ expr. span ,
1971
+ & format ! (
1972
+ "the type `{}` does not permit {}" ,
1973
+ conjured_ty,
1974
+ match init {
1975
+ InitKind :: Zeroed => "zero-initialization" ,
1976
+ InitKind :: Uninit => "being left uninitialized" ,
1977
+ } ,
1978
+ ) ,
1979
+ ) ;
1980
+ err. span_label ( expr. span ,
1981
+ "this code causes undefined behavior when executed" ) ;
1982
+ err. span_label ( expr. span , "help: use `MaybeUninit<T>` instead" ) ;
1983
+ if let Some ( span) = span {
1984
+ err. span_note ( span, & msg) ;
1985
+ } else {
1986
+ err. note ( & msg) ;
1971
1987
}
1988
+ err. emit ( ) ;
1972
1989
}
1973
1990
}
1974
1991
}
0 commit comments