(
sess: &Session,
module: &'m Module,
visited: &mut Vec<bool>,
stack: &mut Vec<Word>,
names: &mut Option<FxHashMap<Word, &'m str>>,
index: usize,
| 192 | }; |
| 193 | |
| 194 | fn visit<'m>( |
| 195 | sess: &Session, |
| 196 | module: &'m Module, |
| 197 | visited: &mut Vec<bool>, |
| 198 | stack: &mut Vec<Word>, |
| 199 | names: &mut Option<FxHashMap<Word, &'m str>>, |
| 200 | index: usize, |
| 201 | func_id_to_idx: &FxHashMap<Word, usize>, |
| 202 | ) -> Result<()> { |
| 203 | if visited[index] { |
| 204 | return Ok(()); |
| 205 | } |
| 206 | visited[index] = true; |
| 207 | stack.push(module.functions[index].def_id().unwrap()); |
| 208 | let mut any_err = None; |
| 209 | for inst in module.functions[index].all_inst_iter() { |
| 210 | if inst.class.opcode == Op::FunctionCall { |
| 211 | let callee = func_id_to_idx[&inst.operands[0].unwrap_id_ref()]; |
| 212 | let callee_had_err = |
| 213 | visit(sess, module, visited, stack, names, callee, func_id_to_idx).err(); |
| 214 | any_err = any_err.or(callee_had_err); |
| 215 | } |
| 216 | if matches!( |
| 217 | inst.class.opcode, |
| 218 | Op::ImageSampleImplicitLod |
| 219 | | Op::ImageSampleDrefImplicitLod |
| 220 | | Op::ImageSampleProjImplicitLod |
| 221 | | Op::ImageSampleProjDrefImplicitLod |
| 222 | | Op::ImageQueryLod |
| 223 | | Op::ImageSparseSampleImplicitLod |
| 224 | | Op::ImageSparseSampleDrefImplicitLod |
| 225 | | Op::DPdx |
| 226 | | Op::DPdy |
| 227 | | Op::Fwidth |
| 228 | | Op::DPdxFine |
| 229 | | Op::DPdyFine |
| 230 | | Op::FwidthFine |
| 231 | | Op::DPdxCoarse |
| 232 | | Op::DPdyCoarse |
| 233 | | Op::FwidthCoarse |
| 234 | | Op::Kill |
| 235 | ) { |
| 236 | // These instructions are (usually) in system functions - if we get an error, allow |
| 237 | // the system function to be visited again from elsewhere to emit another error |
| 238 | // from another callsite. |
| 239 | visited[index] = false; |
| 240 | |
| 241 | let names = names.get_or_insert_with(|| get_names(module)); |
| 242 | let stack = stack.iter().rev().map(|&s| get_name(names, s).into_owned()); |
| 243 | let note = once("Stack:".to_string()) |
| 244 | .chain(stack) |
| 245 | .collect::<Vec<_>>() |
| 246 | .join("\n"); |
| 247 | any_err = Some( |
| 248 | sess.struct_err(format!( |
| 249 | "{} cannot be used outside a fragment shader", |
| 250 | inst.class.opname |
| 251 | )) |
no test coverage detected