@@ -15,7 +15,7 @@ use rustc_hir::lang_items::LangItem;
1515use rustc_middle:: mir:: { self , AssertKind , SwitchTargets , UnwindTerminateReason } ;
1616use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , ValidityRequirement } ;
1717use 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 } ;
1919use rustc_session:: config:: OptLevel ;
2020use rustc_span:: { source_map:: Spanned , sym, Span , Symbol } ;
2121use rustc_target:: abi:: call:: { ArgAbi , FnAbi , PassMode , Reg } ;
@@ -986,6 +986,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
986986 }
987987 }
988988
989+ #[ cfg( debug_assertions) ]
990+ assert_assignable ( bx. tcx ( ) , instance, op. layout . ty , fn_abi. args [ i] . layout . ty , 16 ) ;
991+
989992 // The callee needs to own the argument memory if we pass it
990993 // by-ref, so make a local copy of non-immediate constants.
991994 match ( & arg. node , op. val ) {
@@ -1003,6 +1006,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10031006 self . codegen_argument ( bx, op, & mut llargs, & fn_abi. args [ i] ) ;
10041007 }
10051008 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+
10061017 self . codegen_arguments_untupled (
10071018 bx,
10081019 & tup. node ,
@@ -1734,3 +1745,171 @@ enum ReturnDest<'tcx, V> {
17341745 // Store a direct return value to an operand local place.
17351746 DirectOperand ( mir:: Local ) ,
17361747}
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