@@ -15,7 +15,7 @@ use rustc_hir::lang_items::LangItem;
15
15
use rustc_middle:: mir:: { self , AssertKind , SwitchTargets , UnwindTerminateReason } ;
16
16
use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , ValidityRequirement } ;
17
17
use rustc_middle:: ty:: print:: { with_no_trimmed_paths, with_no_visible_paths} ;
18
- use rustc_middle:: ty:: { self , Instance , Ty } ;
18
+ use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt } ;
19
19
use rustc_session:: config:: OptLevel ;
20
20
use rustc_span:: { source_map:: Spanned , sym, Span , Symbol } ;
21
21
use rustc_target:: abi:: call:: { ArgAbi , FnAbi , PassMode , Reg } ;
@@ -986,6 +986,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
986
986
}
987
987
}
988
988
989
+ #[ cfg( debug_assertions) ]
990
+ assert_assignable ( bx. tcx ( ) , instance, op. layout . ty , fn_abi. args [ i] . layout . ty , 16 ) ;
991
+
989
992
// The callee needs to own the argument memory if we pass it
990
993
// by-ref, so make a local copy of non-immediate constants.
991
994
match ( & arg. node , op. val ) {
@@ -1003,6 +1006,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1003
1006
self . codegen_argument ( bx, op, & mut llargs, & fn_abi. args [ i] ) ;
1004
1007
}
1005
1008
let num_untupled = untuple. map ( |tup| {
1009
+ #[ cfg( debug_assertions) ]
1010
+ for ( param, arg) in std:: iter:: zip (
1011
+ & fn_abi. args [ first_args. len ( ) ..] ,
1012
+ self . monomorphize ( tup. node . ty ( self . mir , bx. tcx ( ) ) ) . tuple_fields ( ) ,
1013
+ ) {
1014
+ assert_assignable ( bx. tcx ( ) , instance, arg, param. layout . ty , 16 ) ;
1015
+ }
1016
+
1006
1017
self . codegen_arguments_untupled (
1007
1018
bx,
1008
1019
& tup. node ,
@@ -1734,3 +1745,171 @@ enum ReturnDest<'tcx, V> {
1734
1745
// Store a direct return value to an operand local place.
1735
1746
DirectOperand ( mir:: Local ) ,
1736
1747
}
1748
+
1749
+ #[ track_caller]
1750
+ pub ( crate ) fn assert_assignable < ' tcx > (
1751
+ tcx : TyCtxt < ' tcx > ,
1752
+ instance : Option < Instance < ' tcx > > ,
1753
+ from_ty : Ty < ' tcx > ,
1754
+ to_ty : Ty < ' tcx > ,
1755
+ limit : usize ,
1756
+ ) {
1757
+ use ty:: TypeAndMut ;
1758
+ if limit == 0 {
1759
+ // assert_assignable exists solely to catch bugs in cg_clif. it isn't necessary for
1760
+ // soundness. don't attempt to check deep types to avoid exponential behavior in certain
1761
+ // cases.
1762
+ return ;
1763
+ }
1764
+ match ( from_ty. kind ( ) , to_ty. kind ( ) ) {
1765
+ ( ty:: Ref ( _, a, _) , ty:: Ref ( _, b, _) )
1766
+ | (
1767
+ ty:: RawPtr ( TypeAndMut { ty : a, mutbl : _ } ) ,
1768
+ ty:: RawPtr ( TypeAndMut { ty : b, mutbl : _ } ) ,
1769
+ ) => {
1770
+ assert_assignable ( tcx, instance, * a, * b, limit - 1 ) ;
1771
+ }
1772
+ ( ty:: Ref ( _, a, _) , ty:: RawPtr ( TypeAndMut { ty : b, mutbl : _ } ) )
1773
+ | ( ty:: RawPtr ( TypeAndMut { ty : a, mutbl : _ } ) , ty:: Ref ( _, b, _) ) => {
1774
+ assert_assignable ( tcx, instance, * a, * b, limit - 1 ) ;
1775
+ }
1776
+ ( ty:: FnPtr ( _) , ty:: FnPtr ( _) ) => {
1777
+ let from_sig = tcx. normalize_erasing_late_bound_regions (
1778
+ ty:: ParamEnv :: reveal_all ( ) ,
1779
+ from_ty. fn_sig ( tcx) ,
1780
+ ) ;
1781
+ let ty:: FnSig {
1782
+ inputs_and_output : types_from,
1783
+ c_variadic : c_variadic_from,
1784
+ unsafety : unsafety_from,
1785
+ abi : abi_from,
1786
+ } = from_sig;
1787
+ let to_sig = tcx. normalize_erasing_late_bound_regions (
1788
+ ty:: ParamEnv :: reveal_all ( ) ,
1789
+ to_ty. fn_sig ( tcx) ,
1790
+ ) ;
1791
+ let ty:: FnSig {
1792
+ inputs_and_output : types_to,
1793
+ c_variadic : c_variadic_to,
1794
+ unsafety : unsafety_to,
1795
+ abi : abi_to,
1796
+ } = to_sig;
1797
+ let mut types_from = types_from. iter ( ) ;
1798
+ let mut types_to = types_to. iter ( ) ;
1799
+ loop {
1800
+ match ( types_from. next ( ) , types_to. next ( ) ) {
1801
+ ( Some ( a) , Some ( b) ) => assert_assignable ( tcx, instance, a, b, limit - 1 ) ,
1802
+ ( None , None ) => break ,
1803
+ ( Some ( _) , None ) | ( None , Some ( _) ) => panic ! ( "{:#?}/{:#?}" , from_ty, to_ty) ,
1804
+ }
1805
+ }
1806
+ assert_eq ! (
1807
+ c_variadic_from, c_variadic_to,
1808
+ "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n " ,
1809
+ from_sig, to_sig,
1810
+ ) ;
1811
+ assert_eq ! (
1812
+ unsafety_from, unsafety_to,
1813
+ "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n " ,
1814
+ from_sig, to_sig,
1815
+ ) ;
1816
+ assert_eq ! (
1817
+ abi_from, abi_to,
1818
+ "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n " ,
1819
+ from_sig, to_sig,
1820
+ ) ;
1821
+ // fn(&T) -> for<'l> fn(&'l T) is allowed
1822
+ }
1823
+ ( & ty:: Dynamic ( from_traits, _, _from_kind) , & ty:: Dynamic ( to_traits, _, _to_kind) ) => {
1824
+ // FIXME(dyn-star): Do the right thing with DynKinds
1825
+ for ( from, to) in from_traits. iter ( ) . zip ( to_traits) {
1826
+ let from =
1827
+ tcx. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , from) ;
1828
+ let to = tcx. normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , to) ;
1829
+ assert_eq ! (
1830
+ from, to,
1831
+ "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n " ,
1832
+ from_traits, to_traits
1833
+ ) ;
1834
+ }
1835
+ // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
1836
+ }
1837
+ ( & ty:: Tuple ( types_a) , & ty:: Tuple ( types_b) ) => {
1838
+ let mut types_a = types_a. iter ( ) ;
1839
+ let mut types_b = types_b. iter ( ) ;
1840
+ loop {
1841
+ match ( types_a. next ( ) , types_b. next ( ) ) {
1842
+ ( Some ( a) , Some ( b) ) => assert_assignable ( tcx, instance, a, b, limit - 1 ) ,
1843
+ ( None , None ) => return ,
1844
+ ( Some ( _) , None ) | ( None , Some ( _) ) => panic ! ( "{:#?}/{:#?}" , from_ty, to_ty) ,
1845
+ }
1846
+ }
1847
+ }
1848
+ ( & ty:: Adt ( adt_def_a, args_a) , & ty:: Adt ( adt_def_b, args_b) )
1849
+ if adt_def_a. did ( ) == adt_def_b. did ( ) =>
1850
+ {
1851
+ let mut types_a = args_a. types ( ) ;
1852
+ let mut types_b = args_b. types ( ) ;
1853
+ loop {
1854
+ match ( types_a. next ( ) , types_b. next ( ) ) {
1855
+ ( Some ( a) , Some ( b) ) => assert_assignable ( tcx, instance, a, b, limit - 1 ) ,
1856
+ ( None , None ) => return ,
1857
+ ( Some ( _) , None ) | ( None , Some ( _) ) => panic ! ( "{:#?}/{:#?}" , from_ty, to_ty) ,
1858
+ }
1859
+ }
1860
+ }
1861
+ ( ty:: Array ( a, _) , ty:: Array ( b, _) ) => assert_assignable ( tcx, instance, * a, * b, limit - 1 ) ,
1862
+ ( & ty:: Closure ( def_id_a, args_a) , & ty:: Closure ( def_id_b, args_b) )
1863
+ if def_id_a == def_id_b =>
1864
+ {
1865
+ let mut types_a = args_a. types ( ) ;
1866
+ let mut types_b = args_b. types ( ) ;
1867
+ loop {
1868
+ match ( types_a. next ( ) , types_b. next ( ) ) {
1869
+ ( Some ( a) , Some ( b) ) => assert_assignable ( tcx, instance, a, b, limit - 1 ) ,
1870
+ ( None , None ) => return ,
1871
+ ( Some ( _) , None ) | ( None , Some ( _) ) => panic ! ( "{:#?}/{:#?}" , from_ty, to_ty) ,
1872
+ }
1873
+ }
1874
+ }
1875
+ ( & ty:: Coroutine ( def_id_a, args_a) , & ty:: Coroutine ( def_id_b, args_b) )
1876
+ if def_id_a == def_id_b =>
1877
+ {
1878
+ let mut types_a = args_a. types ( ) ;
1879
+ let mut types_b = args_b. types ( ) ;
1880
+ loop {
1881
+ match ( types_a. next ( ) , types_b. next ( ) ) {
1882
+ ( Some ( a) , Some ( b) ) => assert_assignable ( tcx, instance, a, b, limit - 1 ) ,
1883
+ ( None , None ) => return ,
1884
+ ( Some ( _) , None ) | ( None , Some ( _) ) => panic ! ( "{:#?}/{:#?}" , from_ty, to_ty) ,
1885
+ }
1886
+ }
1887
+ }
1888
+ ( & ty:: CoroutineWitness ( def_id_a, args_a) , & ty:: CoroutineWitness ( def_id_b, args_b) )
1889
+ if def_id_a == def_id_b =>
1890
+ {
1891
+ let mut types_a = args_a. types ( ) ;
1892
+ let mut types_b = args_b. types ( ) ;
1893
+ loop {
1894
+ match ( types_a. next ( ) , types_b. next ( ) ) {
1895
+ ( Some ( a) , Some ( b) ) => assert_assignable ( tcx, instance, a, b, limit - 1 ) ,
1896
+ ( None , None ) => return ,
1897
+ ( Some ( _) , None ) | ( None , Some ( _) ) => panic ! ( "{:#?}/{:#?}" , from_ty, to_ty) ,
1898
+ }
1899
+ }
1900
+ }
1901
+ ( ty:: Param ( _) , _) | ( _, ty:: Param ( _) ) if tcx. sess . opts . unstable_opts . polymorphize => {
1902
+ // No way to check if it is correct or not with polymorphization enabled
1903
+ }
1904
+ _ => {
1905
+ assert_eq ! (
1906
+ from_ty,
1907
+ to_ty,
1908
+ "Can't write value with incompatible type {:?} to place with type {:?} in {:?}\n " ,
1909
+ from_ty. kind( ) ,
1910
+ to_ty. kind( ) ,
1911
+ instance,
1912
+ ) ;
1913
+ }
1914
+ }
1915
+ }
0 commit comments