(&self, cx: &CodegenCx<'tcx>, span: Span, pointee: PointeeTy<'tcx>)
| 188 | |
| 189 | impl<'tcx> RecursivePointeeCache<'tcx> { |
| 190 | fn begin(&self, cx: &CodegenCx<'tcx>, span: Span, pointee: PointeeTy<'tcx>) -> Option<Word> { |
| 191 | match self.map.borrow_mut().entry(pointee) { |
| 192 | // State: This is the first time we've seen this type. Record that we're beginning to translate this type, |
| 193 | // and start doing the translation. |
| 194 | Entry::Vacant(entry) => { |
| 195 | entry.insert(PointeeDefState::Defining); |
| 196 | None |
| 197 | } |
| 198 | Entry::Occupied(mut entry) => match *entry.get() { |
| 199 | // State: This is the second time we've seen this type, and we're already translating this type. If we |
| 200 | // were to try to translate the type now, we'd get a stack overflow, due to continually recursing. So, |
| 201 | // emit an OpTypeForwardPointer, and use that ID. (This is the juicy part of this algorithm) |
| 202 | PointeeDefState::Defining => { |
| 203 | let new_id = cx.emit_global().id(); |
| 204 | // NOTE(eddyb) we emit `StorageClass::Generic` here, but later |
| 205 | // the linker will specialize the entire SPIR-V module to use |
| 206 | // storage classes inferred from `OpVariable`s. |
| 207 | cx.emit_global() |
| 208 | .type_forward_pointer(new_id, StorageClass::Generic); |
| 209 | entry.insert(PointeeDefState::DefiningWithForward(new_id)); |
| 210 | cx.zombie_with_span( |
| 211 | new_id, |
| 212 | span, |
| 213 | "cannot create self-referential types, even through pointers", |
| 214 | ); |
| 215 | Some(new_id) |
| 216 | } |
| 217 | // State: This is the third or more time we've seen this type, and we've already emitted an |
| 218 | // OpTypeForwardPointer. Just use the ID we've already emitted. (Alternatively, we already defined this |
| 219 | // type, so just use that.) |
| 220 | PointeeDefState::DefiningWithForward(id) | PointeeDefState::Defined(id) => Some(id), |
| 221 | }, |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | fn end( |
| 226 | &self, |
no test coverage detected