6161//! The evaluated form is inserted in `evaluated` as an `OpTy` or `None` if evaluation failed.
6262//!
6363//! The difficulty is non-deterministic evaluation of MIR constants. Some `Const` can have
64- //! different runtime values each time they are evaluated. This is the case with
65- //! `Const::Slice` which have a new pointer each time they are evaluated, and constants that
66- //! contain a fn pointer (`AllocId` pointing to a `GlobalAlloc::Function`) pointing to a different
67- //! symbol in each codegen unit.
64+ //! different runtime values each time they are evaluated. This happens with valtrees that
65+ //! generate a new allocation each time they are used. This is checked by `is_deterministic`.
6866//!
6967//! Meanwhile, we want to be able to read indirect constants. For instance:
7068//! ```
8179//! may be non-deterministic. When that happens, we assign a disambiguator to ensure that we do not
8280//! merge the constants. See `duplicate_slice` test in `gvn.rs`.
8381//!
84- //! Second, when writing constants in MIR, we do not write `Const::Slice` or `Const`
85- //! that contain `AllocId`s.
82+ //! Conversely, some constants cannot cross function boundaries, which could happen because of
83+ //! inlining. For instance, constants that contain a fn pointer (`AllocId` pointing to a
84+ //! `GlobalAlloc::Function`) point to a different symbol in each codegen unit. To avoid this,
85+ //! when writing constants in MIR, we do not write `Const`s that contain `AllocId`s. This is
86+ //! checked by `may_have_provenance`. See <https://github.com/rust-lang/rust/issues/128775> for
87+ //! more information.
8688
8789use std:: borrow:: Cow ;
8890use std:: hash:: { Hash , Hasher } ;
@@ -103,7 +105,7 @@ use rustc_hir::def::DefKind;
103105use rustc_index:: bit_set:: DenseBitSet ;
104106use rustc_index:: { IndexVec , newtype_index} ;
105107use rustc_middle:: bug;
106- use rustc_middle:: mir:: interpret:: GlobalAlloc ;
108+ use rustc_middle:: mir:: interpret:: { AllocRange , GlobalAlloc } ;
107109use rustc_middle:: mir:: visit:: * ;
108110use rustc_middle:: mir:: * ;
109111use rustc_middle:: ty:: layout:: HasTypingEnv ;
@@ -487,7 +489,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
487489
488490 #[ instrument( level = "trace" , skip( self ) , ret) ]
489491 fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
490- if value . is_deterministic ( ) {
492+ if is_deterministic ( value ) {
491493 // The constant is deterministic, no need to disambiguate.
492494 let constant = Value :: Constant { value, disambiguator : None } ;
493495 self . insert ( value. ty ( ) , constant)
@@ -522,14 +524,14 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
522524 fn insert_bool ( & mut self , flag : bool ) -> VnIndex {
523525 // Booleans are deterministic.
524526 let value = Const :: from_bool ( self . tcx , flag) ;
525- debug_assert ! ( value . is_deterministic( ) ) ;
527+ debug_assert ! ( is_deterministic( value ) ) ;
526528 self . insert ( self . tcx . types . bool , Value :: Constant { value, disambiguator : None } )
527529 }
528530
529531 fn insert_scalar ( & mut self , ty : Ty < ' tcx > , scalar : Scalar ) -> VnIndex {
530532 // Scalars are deterministic.
531533 let value = Const :: from_scalar ( self . tcx , scalar, ty) ;
532- debug_assert ! ( value . is_deterministic( ) ) ;
534+ debug_assert ! ( is_deterministic( value ) ) ;
533535 self . insert ( ty, Value :: Constant { value, disambiguator : None } )
534536 }
535537
@@ -1729,6 +1731,49 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
17291731 }
17301732}
17311733
1734+ /// Return true if any evaluation of this constant in the same MIR body
1735+ /// always returns the same value, taking into account even pointer identity tests.
1736+ ///
1737+ /// In other words, this answers: is "cloning" the `Const` ok?
1738+ ///
1739+ /// This returns `false` for constants that synthesize new `AllocId` when they are instantiated.
1740+ /// It is `true` for anything else, since a given `AllocId` *does* have a unique runtime value
1741+ /// within the scope of a single MIR body.
1742+ fn is_deterministic ( c : Const < ' _ > ) -> bool {
1743+ // Primitive types cannot contain provenance and always have the same value.
1744+ if c. ty ( ) . is_primitive ( ) {
1745+ return true ;
1746+ }
1747+
1748+ match c {
1749+ // Some constants may generate fresh allocations for pointers they contain,
1750+ // so using the same constant twice can yield two different results.
1751+ // Notably, valtrees purposefully generate new allocations.
1752+ Const :: Ty ( ..) => false ,
1753+ // We do not know the contents, so don't attempt to do anything clever.
1754+ Const :: Unevaluated ( ..) => false ,
1755+ // When an evaluated constant contains provenance, it is encoded as an `AllocId`.
1756+ // Cloning the constant will reuse the same `AllocId`. If this is in the same MIR
1757+ // body, this same `AllocId` will result in the same pointer in codegen.
1758+ Const :: Val ( ..) => true ,
1759+ }
1760+ }
1761+
1762+ /// Check if a constant may contain provenance information.
1763+ /// Can return `true` even if there is no provenance.
1764+ fn may_have_provenance ( tcx : TyCtxt < ' _ > , value : ConstValue , size : Size ) -> bool {
1765+ match value {
1766+ ConstValue :: ZeroSized | ConstValue :: Scalar ( Scalar :: Int ( _) ) => return false ,
1767+ ConstValue :: Scalar ( Scalar :: Ptr ( ..) ) | ConstValue :: Slice { .. } => return true ,
1768+ ConstValue :: Indirect { alloc_id, offset } => !tcx
1769+ . global_alloc ( alloc_id)
1770+ . unwrap_memory ( )
1771+ . inner ( )
1772+ . provenance ( )
1773+ . range_empty ( AllocRange :: from ( offset..offset + size) , & tcx) ,
1774+ }
1775+ }
1776+
17321777fn op_to_prop_const < ' tcx > (
17331778 ecx : & mut InterpCx < ' tcx , DummyMachine > ,
17341779 op : & OpTy < ' tcx > ,
@@ -1760,7 +1805,7 @@ fn op_to_prop_const<'tcx>(
17601805 if !scalar. try_to_scalar_int ( ) . is_ok ( ) {
17611806 // Check that we do not leak a pointer.
17621807 // Those pointers may lose part of their identity in codegen.
1763- // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
1808+ // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/128775 is fixed.
17641809 return None ;
17651810 }
17661811 return Some ( ConstValue :: Scalar ( scalar) ) ;
@@ -1772,7 +1817,7 @@ fn op_to_prop_const<'tcx>(
17721817 let ( size, _align) = ecx. size_and_align_of_val ( & mplace) . discard_err ( ) ??;
17731818
17741819 // Do not try interning a value that contains provenance.
1775- // Due to https://github.com/rust-lang/rust/issues/79738 , doing so could lead to bugs.
1820+ // Due to https://github.com/rust-lang/rust/issues/128775 , doing so could lead to bugs.
17761821 // FIXME: remove this hack once that issue is fixed.
17771822 let alloc_ref = ecx. get_ptr_alloc ( mplace. ptr ( ) , size) . discard_err ( ) ??;
17781823 if alloc_ref. has_provenance ( ) {
@@ -1803,8 +1848,17 @@ fn op_to_prop_const<'tcx>(
18031848
18041849 // Check that we do not leak a pointer.
18051850 // Those pointers may lose part of their identity in codegen.
1806- // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
1807- if ecx. tcx . global_alloc ( alloc_id) . unwrap_memory ( ) . inner ( ) . provenance ( ) . ptrs ( ) . is_empty ( ) {
1851+ // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/128775 is fixed.
1852+ if ecx
1853+ . tcx
1854+ . global_alloc ( alloc_id)
1855+ . unwrap_memory ( )
1856+ . inner ( )
1857+ . provenance ( )
1858+ . provenances ( )
1859+ . next ( )
1860+ . is_none ( )
1861+ {
18081862 return Some ( value) ;
18091863 }
18101864
@@ -1861,8 +1915,8 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
18611915
18621916 // Check that we do not leak a pointer.
18631917 // Those pointers may lose part of their identity in codegen.
1864- // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/79738 is fixed.
1865- assert ! ( !value . may_have_provenance( self . tcx, op. layout. size) ) ;
1918+ // FIXME: remove this hack once https://github.com/rust-lang/rust/issues/128775 is fixed.
1919+ assert ! ( !may_have_provenance( self . tcx, value , op. layout. size) ) ;
18661920
18671921 Some ( Const :: Val ( value, op. layout . ty ) )
18681922 }
0 commit comments