@@ -612,6 +612,17 @@ trait NameKeyExt {
612612 FunctionOrigin :: EntryPoint ( idx) => NameKey :: EntryPointLocal ( idx, local_handle) ,
613613 }
614614 }
615+
616+ /// Return the name key for a local variable used by ReadZeroSkipWrite bounds-check
617+ /// policy when it needs to produce a pointer-typed result for an OOB access. These
618+ /// are unique per accessed type, so the second argument is a type handle. See docs
619+ /// for [`crate::back::msl`].
620+ fn oob_local_for_type ( origin : FunctionOrigin , ty : Handle < crate :: Type > ) -> NameKey {
621+ match origin {
622+ FunctionOrigin :: Handle ( handle) => NameKey :: FunctionOobLocal ( handle, ty) ,
623+ FunctionOrigin :: EntryPoint ( idx) => NameKey :: EntryPointOobLocal ( idx, ty) ,
624+ }
625+ }
615626}
616627
617628impl NameKeyExt for NameKey { }
@@ -722,6 +733,11 @@ impl<'a> ExpressionContext<'a> {
722733 index:: bounds_check_iter ( chain, self . module , self . function , self . info )
723734 }
724735
736+ /// See docs for [`proc::index::oob_local_types`].
737+ fn oob_local_types ( & self ) -> FastHashSet < Handle < crate :: Type > > {
738+ index:: oob_local_types ( self . module , self . function , self . info , self . policies )
739+ }
740+
725741 fn get_packed_vec_kind ( & self , expr_handle : Handle < crate :: Expression > ) -> Option < crate :: Scalar > {
726742 match self . function . expressions [ expr_handle] {
727743 crate :: Expression :: AccessIndex { base, index } => {
@@ -929,8 +945,18 @@ impl<W: Write> Writer<W> {
929945 Ok ( ( ) )
930946 }
931947
932- /// Writes the local variables of the given function.
948+ /// Writes the local variables of the given function, as well as any extra
949+ /// out-of-bounds locals that are needed.
950+ ///
951+ /// The names of the OOB locals are also added to `self.names` at the same
952+ /// time.
933953 fn put_locals ( & mut self , context : & ExpressionContext ) -> BackendResult {
954+ let oob_local_types = context. oob_local_types ( ) ;
955+ for & ty in oob_local_types. iter ( ) {
956+ let name_key = NameKey :: oob_local_for_type ( context. origin , ty) ;
957+ self . names . insert ( name_key, self . namer . call ( "oob" ) ) ;
958+ }
959+
934960 for ( name_key, ty, init) in context
935961 . function
936962 . local_variables
@@ -939,6 +965,10 @@ impl<W: Write> Writer<W> {
939965 let name_key = NameKey :: local ( context. origin , local_handle) ;
940966 ( name_key, local. ty , local. init )
941967 } )
968+ . chain ( oob_local_types. iter ( ) . map ( |& ty| {
969+ let name_key = NameKey :: oob_local_for_type ( context. origin , ty) ;
970+ ( name_key, ty, None )
971+ } ) )
942972 {
943973 let ty_name = TypeContext {
944974 handle : ty,
@@ -1761,7 +1791,42 @@ impl<W: Write> Writer<W> {
17611791 {
17621792 write ! ( self . out, " ? " ) ?;
17631793 self . put_access_chain ( expr_handle, policy, context) ?;
1764- write ! ( self . out, " : DefaultConstructible()" ) ?;
1794+ write ! ( self . out, " : " ) ?;
1795+
1796+ if context. resolve_type ( base) . pointer_space ( ) . is_some ( ) {
1797+ // We can't just use `DefaultConstructible` if this is a pointer.
1798+ // Instead, we create a dummy local variable to serve as pointer
1799+ // target if the access is out of bounds.
1800+ let result_ty = context. info [ expr_handle]
1801+ . ty
1802+ . inner_with ( & context. module . types )
1803+ . pointer_base_type ( ) ;
1804+ let result_ty_handle = match result_ty {
1805+ Some ( TypeResolution :: Handle ( handle) ) => handle,
1806+ Some ( TypeResolution :: Value ( _) ) => {
1807+ // As long as the result of a pointer access expression is
1808+ // passed to a function or stored in a let binding, the
1809+ // type will be in the arena. If additional uses of
1810+ // pointers become valid, this assumption might no longer
1811+ // hold. Note that the LHS of a load or store doesn't
1812+ // take this path -- there is dedicated code in `put_load`
1813+ // and `put_store`.
1814+ unreachable ! (
1815+ "Expected type {result_ty:?} of access through pointer type {base:?} to be in the arena" ,
1816+ ) ;
1817+ }
1818+ None => {
1819+ unreachable ! (
1820+ "Expected access through pointer type {base:?} to return a pointer, but got {result_ty:?}" ,
1821+ )
1822+ }
1823+ } ;
1824+ let name_key =
1825+ NameKey :: oob_local_for_type ( context. origin , result_ty_handle) ;
1826+ self . out . write_str ( & self . names [ & name_key] ) ?;
1827+ } else {
1828+ write ! ( self . out, "DefaultConstructible()" ) ?;
1829+ }
17651830
17661831 if !is_scoped {
17671832 write ! ( self . out, ")" ) ?;
0 commit comments