diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -867,13 +867,19 @@ if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) { // Precompute setjmp users for (User *U : SetjmpF->users()) { - if (auto *UI = dyn_cast(U)) { - auto *UserF = UI->getFunction(); + if (auto *CB = dyn_cast(U)) { + auto *UserF = CB->getFunction(); // If a function that calls setjmp does not contain any other calls that // can longjmp, we don't need to do any transformation on that function, // so can ignore it if (containsLongjmpableCalls(UserF)) SetjmpUsers.insert(UserF); + } else { + std::string S; + raw_string_ostream SS(S); + SS << *U; + report_fatal_error(Twine("Does not support indirect uses of setjmp: ") + + SS.str()); } } } @@ -1217,9 +1223,10 @@ Function *SetjmpF = M.getFunction("setjmp"); for (User *U : SetjmpF->users()) { auto *CI = dyn_cast(U); + // FIXME 'invoke' to setjmp can happen when we use Wasm EH + Wasm SjLj, but + // we don't support two being used together yet. if (!CI) - report_fatal_error("Does not support indirect calls to setjmp"); - + report_fatal_error("Wasm EH + Wasm SjLj is not fully supported yet"); BasicBlock *BB = CI->getParent(); if (BB->getParent() != &F) // in other function continue; diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-indirect-setjmp.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-indirect-setjmp.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj-indirect-setjmp.ll @@ -0,0 +1,27 @@ +; RUN: not --crash llc < %s -enable-emscripten-sjlj 2>&1 | FileCheck %s +; RUN: not --crash llc < %s -wasm-enable-sjlj -mattr=+exception-handling -exception-model=wasm 2>&1 | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +%struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] } + +; CHECK: LLVM ERROR: Does not support indirect uses of setjmp +@setjmp_fp = global i32 (%struct.__jmp_buf_tag*)* @setjmp, align 4 + +define void @indirect_setjmp_call() { +entry: + %buf = alloca [1 x %struct.__jmp_buf_tag], align 16 + %0 = load i32 (%struct.__jmp_buf_tag*)*, i32 (%struct.__jmp_buf_tag*)** @setjmp_fp, align 4 + %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0 + %call = call i32 %0(%struct.__jmp_buf_tag* %arraydecay) + call void @foo() + ret void +} + +declare void @foo() +; Function Attrs: returns_twice +declare i32 @setjmp(%struct.__jmp_buf_tag*) #0 + +attributes #0 = { returns_twice } +