diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 129fdaf37fc0d..95db5500b0e1b 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -1255,7 +1255,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { void onEndOfFunction(SMLoc ErrorLoc) { if (!SkipTypeCheck) - TC.endOfFunction(ErrorLoc); + TC.endOfFunction(ErrorLoc, true); // Reset the type checker state. TC.clear(); } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp index 8b1e1dca4f847..845bf3976c22b 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp @@ -33,6 +33,7 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/SourceMgr.h" +#include using namespace llvm; @@ -59,14 +60,7 @@ void WebAssemblyAsmTypeCheck::localDecl( } void WebAssemblyAsmTypeCheck::dumpTypeStack(Twine Msg) { - LLVM_DEBUG({ - std::string s; - for (auto VT : Stack) { - s += WebAssembly::typeToString(VT); - s += " "; - } - dbgs() << Msg << s << '\n'; - }); + LLVM_DEBUG({ dbgs() << Msg << getTypesString(Stack, 0) << "\n"; }); } bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) { @@ -77,34 +71,124 @@ bool WebAssemblyAsmTypeCheck::typeError(SMLoc ErrorLoc, const Twine &Msg) { return Parser.Error(ErrorLoc, Msg); } -bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, - std::optional EVT) { - if (Stack.empty()) { - return typeError(ErrorLoc, - EVT ? StringRef("empty stack while popping ") + - WebAssembly::typeToString(*EVT) - : StringRef("empty stack while popping value")); +bool WebAssemblyAsmTypeCheck::match(StackType TypeA, StackType TypeB) { + if (TypeA == TypeB) + return false; + if (std::get_if(&TypeA) || std::get_if(&TypeB)) + return false; + + if (std::get_if(&TypeB)) + std::swap(TypeA, TypeB); + assert(std::get_if(&TypeB)); + if (std::get_if(&TypeA) && + WebAssembly::isRefType(std::get(TypeB))) + return false; + return true; +} + +std::string WebAssemblyAsmTypeCheck::getTypesString(ArrayRef Types, + size_t StartPos) { + SmallVector Reverse; + for (auto I = Types.size(); I > StartPos; I--) { + if (std::get_if(&Types[I - 1])) + Reverse.push_back("any"); + else if (std::get_if(&Types[I - 1])) + Reverse.push_back("ref"); + else + Reverse.push_back( + WebAssembly::typeToString(std::get(Types[I - 1]))); } - auto PVT = Stack.pop_back_val(); - if (EVT && *EVT != PVT) { - return typeError(ErrorLoc, - StringRef("popped ") + WebAssembly::typeToString(PVT) + - ", expected " + WebAssembly::typeToString(*EVT)); + + std::stringstream SS; + SS << "["; + bool First = true; + for (auto It = Reverse.rbegin(); It != Reverse.rend(); ++It) { + if (!First) + SS << ", "; + SS << *It; + First = false; } - return false; + SS << "]"; + return SS.str(); } -bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) { - if (Stack.empty()) { - return typeError(ErrorLoc, StringRef("empty stack while popping reftype")); - } - auto PVT = Stack.pop_back_val(); - if (!WebAssembly::isRefType(PVT)) { - return typeError(ErrorLoc, StringRef("popped ") + - WebAssembly::typeToString(PVT) + - ", expected reftype"); +SmallVector +WebAssemblyAsmTypeCheck::valTypeToStackType(ArrayRef ValTypes) { + SmallVector Types(ValTypes.size()); + std::transform(ValTypes.begin(), ValTypes.end(), Types.begin(), + [](wasm::ValType Val) -> StackType { return Val; }); + return Types; +} + +bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc, + ArrayRef ValTypes, + bool ExactMatch) { + return checkTypes(ErrorLoc, valTypeToStackType(ValTypes), ExactMatch); +} + +bool WebAssemblyAsmTypeCheck::checkTypes(SMLoc ErrorLoc, + ArrayRef Types, + bool ExactMatch) { + auto StackI = Stack.size(); + auto TypeI = Types.size(); + bool Error = false; + // Compare elements one by one from the stack top + for (; StackI > 0 && TypeI > 0; StackI--, TypeI--) { + if (match(Stack[StackI - 1], Types[TypeI - 1])) { + Error = true; + break; + } } - return false; + // Even if no match failure has happened in the loop above, if not all + // elements of Types has been matched, that means we don't have enough + // elements on the stack. + // + // Also, if not all elements of the Stack has been matched and when + // 'ExactMatch' is true, that means we have superfluous elements remaining on + // the stack (e.g. at the end of a function). + if (TypeI > 0 || (ExactMatch && StackI > 0)) + Error = true; + + if (!Error) + return false; + + auto StackStartPos = + ExactMatch ? 0 : std::max(0, (int)Stack.size() - (int)Types.size()); + return typeError(ErrorLoc, "type mismatch, expected " + + getTypesString(Types, 0) + " but got " + + getTypesString(Stack, StackStartPos)); +} + +bool WebAssemblyAsmTypeCheck::checkAndPopTypes(SMLoc ErrorLoc, + ArrayRef ValTypes, + bool ExactMatch) { + return checkAndPopTypes(ErrorLoc, valTypeToStackType(ValTypes), ExactMatch); +} + +bool WebAssemblyAsmTypeCheck::checkAndPopTypes(SMLoc ErrorLoc, + ArrayRef Types, + bool ExactMatch) { + bool Error = checkTypes(ErrorLoc, Types, ExactMatch); + auto NumPops = std::min(Stack.size(), Types.size()); + for (size_t I = 0, E = NumPops; I != E; I++) + Stack.pop_back(); + return Error; +} + +bool WebAssemblyAsmTypeCheck::popType(SMLoc ErrorLoc, StackType Type) { + return checkAndPopTypes(ErrorLoc, {Type}, false); +} + +bool WebAssemblyAsmTypeCheck::popRefType(SMLoc ErrorLoc) { + return popType(ErrorLoc, Ref{}); +} + +bool WebAssemblyAsmTypeCheck::popAnyType(SMLoc ErrorLoc) { + return popType(ErrorLoc, Any{}); +} + +void WebAssemblyAsmTypeCheck::pushTypes(ArrayRef ValTypes) { + Stack.append(valTypeToStackType(ValTypes)); } bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp, @@ -117,59 +201,29 @@ bool WebAssemblyAsmTypeCheck::getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp, return false; } -static std::optional -checkStackTop(const SmallVectorImpl &ExpectedStackTop, - const SmallVectorImpl &Got) { - for (size_t I = 0; I < ExpectedStackTop.size(); I++) { - auto EVT = ExpectedStackTop[I]; - auto PVT = Got[Got.size() - ExpectedStackTop.size() + I]; - if (PVT != EVT) - return std::string{"got "} + WebAssembly::typeToString(PVT) + - ", expected " + WebAssembly::typeToString(EVT); - } - return std::nullopt; -} - bool WebAssemblyAsmTypeCheck::checkBr(SMLoc ErrorLoc, size_t Level) { if (Level >= BrStack.size()) return typeError(ErrorLoc, StringRef("br: invalid depth ") + std::to_string(Level)); const SmallVector &Expected = BrStack[BrStack.size() - Level - 1]; - if (Expected.size() > Stack.size()) - return typeError(ErrorLoc, "br: insufficient values on the type stack"); - auto IsStackTopInvalid = checkStackTop(Expected, Stack); - if (IsStackTopInvalid) - return typeError(ErrorLoc, "br " + IsStackTopInvalid.value()); + return checkTypes(ErrorLoc, Expected, false); return false; } bool WebAssemblyAsmTypeCheck::checkEnd(SMLoc ErrorLoc, bool PopVals) { if (!PopVals) BrStack.pop_back(); - if (LastSig.Returns.size() > Stack.size()) - return typeError(ErrorLoc, "end: insufficient values on the type stack"); - if (PopVals) { - for (auto VT : llvm::reverse(LastSig.Returns)) { - if (popType(ErrorLoc, VT)) - return true; - } - return false; - } - - auto IsStackTopInvalid = checkStackTop(LastSig.Returns, Stack); - if (IsStackTopInvalid) - return typeError(ErrorLoc, "end " + IsStackTopInvalid.value()); - return false; + if (PopVals) + return checkAndPopTypes(ErrorLoc, LastSig.Returns, false); + return checkTypes(ErrorLoc, LastSig.Returns, false); } bool WebAssemblyAsmTypeCheck::checkSig(SMLoc ErrorLoc, const wasm::WasmSignature &Sig) { - bool Error = false; - for (auto VT : llvm::reverse(Sig.Params)) - Error |= popType(ErrorLoc, VT); - Stack.insert(Stack.end(), Sig.Returns.begin(), Sig.Returns.end()); + bool Error = checkAndPopTypes(ErrorLoc, Sig.Params, false); + pushTypes(Sig.Returns); return Error; } @@ -246,7 +300,7 @@ bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc, TypeName = "tag"; break; default: - return true; + llvm_unreachable("Signature symbol should either be a function or a tag"); } return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() + ": missing ." + TypeName + "type"); @@ -254,15 +308,8 @@ bool WebAssemblyAsmTypeCheck::getSignature(SMLoc ErrorLoc, return false; } -bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc) { - bool Error = false; - // Check the return types. - for (auto RVT : llvm::reverse(ReturnTypes)) - Error |= popType(ErrorLoc, RVT); - if (!Stack.empty()) { - return typeError(ErrorLoc, std::to_string(Stack.size()) + - " superfluous return values"); - } +bool WebAssemblyAsmTypeCheck::endOfFunction(SMLoc ErrorLoc, bool ExactMatch) { + bool Error = checkAndPopTypes(ErrorLoc, ReturnTypes, ExactMatch); Unreachable = true; return Error; } @@ -276,7 +323,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "local.get") { if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { - Stack.push_back(Type); + pushType(Type); return false; } return true; @@ -291,7 +338,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "local.tee") { if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { bool Error = popType(ErrorLoc, Type); - Stack.push_back(Type); + pushType(Type); return Error; } return true; @@ -299,7 +346,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "global.get") { if (!getGlobal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { - Stack.push_back(Type); + pushType(Type); return false; } return true; @@ -314,7 +361,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "table.get") { bool Error = popType(ErrorLoc, wasm::ValType::I32); if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) { - Stack.push_back(Type); + pushType(Type); return Error; } return true; @@ -332,7 +379,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "table.size") { bool Error = getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type); - Stack.push_back(wasm::ValType::I32); + pushType(wasm::ValType::I32); return Error; } @@ -342,7 +389,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, Error |= popType(ErrorLoc, Type); else Error = true; - Stack.push_back(wasm::ValType::I32); + pushType(wasm::ValType::I32); return Error; } @@ -381,7 +428,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, } if (Name == "drop") { - return popType(ErrorLoc, {}); + return popType(ErrorLoc, Any{}); } if (Name == "try" || Name == "block" || Name == "loop" || Name == "if") { @@ -406,7 +453,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, wasm::WASM_SYMBOL_TYPE_TAG, Sig)) // catch instruction pushes values whose types are specified in the // tag's "params" part - Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end()); + pushTypes(Sig->Params); else Error = true; } @@ -421,14 +468,14 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, } if (Name == "return") { - return endOfFunction(ErrorLoc); + return endOfFunction(ErrorLoc, false); } if (Name == "call_indirect" || Name == "return_call_indirect") { // Function value. bool Error = popType(ErrorLoc, wasm::ValType::I32); Error |= checkSig(ErrorLoc, LastSig); - if (Name == "return_call_indirect" && endOfFunction(ErrorLoc)) + if (Name == "return_call_indirect" && endOfFunction(ErrorLoc, false)) return true; return Error; } @@ -441,7 +488,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, Error |= checkSig(ErrorLoc, *Sig); else Error = true; - if (Name == "return_call" && endOfFunction(ErrorLoc)) + if (Name == "return_call" && endOfFunction(ErrorLoc, false)) return true; return Error; } @@ -453,7 +500,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, if (Name == "ref.is_null") { bool Error = popRefType(ErrorLoc); - Stack.push_back(wasm::ValType::I32); + pushType(wasm::ValType::I32); return Error; } @@ -471,22 +518,22 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst, auto RegOpc = WebAssembly::getRegisterOpcode(Opc); assert(RegOpc != -1 && "Failed to get register version of MC instruction"); const auto &II = MII.get(RegOpc); - bool Error = false; // First pop all the uses off the stack and check them. - for (unsigned I = II.getNumOperands(); I > II.getNumDefs(); I--) { - const auto &Op = II.operands()[I - 1]; - if (Op.OperandType == MCOI::OPERAND_REGISTER) { - auto VT = WebAssembly::regClassToValType(Op.RegClass); - Error |= popType(ErrorLoc, VT); - } + SmallVector PopTypes; + for (unsigned I = II.getNumDefs(); I < II.getNumOperands(); I++) { + const auto &Op = II.operands()[I]; + if (Op.OperandType == MCOI::OPERAND_REGISTER) + PopTypes.push_back(WebAssembly::regClassToValType(Op.RegClass)); } + bool Error = checkAndPopTypes(ErrorLoc, PopTypes, false); + SmallVector PushTypes; // Now push all the defs onto the stack. for (unsigned I = 0; I < II.getNumDefs(); I++) { const auto &Op = II.operands()[I]; assert(Op.OperandType == MCOI::OPERAND_REGISTER && "Register expected"); - auto VT = WebAssembly::regClassToValType(Op.RegClass); - Stack.push_back(VT); + PushTypes.push_back(WebAssembly::regClassToValType(Op.RegClass)); } + pushTypes(PushTypes); return Error; } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h index 972162d3e02f4..9fd35a26f30e5 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h @@ -21,6 +21,7 @@ #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCSymbol.h" +#include namespace llvm { @@ -28,7 +29,10 @@ class WebAssemblyAsmTypeCheck final { MCAsmParser &Parser; const MCInstrInfo &MII; - SmallVector Stack; + struct Ref : public std::monostate {}; + struct Any : public std::monostate {}; + using StackType = std::variant; + SmallVector Stack; SmallVector, 8> BrStack; SmallVector LocalTypes; SmallVector ReturnTypes; @@ -36,10 +40,29 @@ class WebAssemblyAsmTypeCheck final { bool Unreachable = false; bool Is64; + // If ExactMatch is true, 'Types' will be compared against not only the top of + // the value stack but the whole remaining value stack + // (TODO: This should be the whole remaining value stack "at the the current + // block level", which has not been implemented yet) + bool checkTypes(SMLoc ErrorLoc, ArrayRef Types, + bool ExactMatch); + bool checkTypes(SMLoc ErrorLoc, ArrayRef Types, bool ExactMatch); + bool checkAndPopTypes(SMLoc ErrorLoc, ArrayRef Types, + bool ExactMatch); + bool checkAndPopTypes(SMLoc ErrorLoc, ArrayRef Types, + bool ExactMatch); + bool popType(SMLoc ErrorLoc, StackType Type); + bool popRefType(SMLoc ErrorLoc); + bool popAnyType(SMLoc ErrorLoc); + void pushTypes(ArrayRef Types); + void pushType(StackType Type) { Stack.push_back(Type); } + bool match(StackType TypeA, StackType TypeB); + std::string getTypesString(ArrayRef Types, size_t StartPos); + SmallVector + valTypeToStackType(ArrayRef ValTypes); + void dumpTypeStack(Twine Msg); bool typeError(SMLoc ErrorLoc, const Twine &Msg); - bool popType(SMLoc ErrorLoc, std::optional EVT); - bool popRefType(SMLoc ErrorLoc); bool getLocal(SMLoc ErrorLoc, const MCOperand &LocalOp, wasm::ValType &Type); bool checkEnd(SMLoc ErrorLoc, bool PopVals = false); bool checkBr(SMLoc ErrorLoc, size_t Level); @@ -59,7 +82,7 @@ class WebAssemblyAsmTypeCheck final { void funcDecl(const wasm::WasmSignature &Sig); void localDecl(const SmallVectorImpl &Locals); void setLastSig(const wasm::WasmSignature &Sig) { LastSig = Sig; } - bool endOfFunction(SMLoc ErrorLoc); + bool endOfFunction(SMLoc ErrorLoc, bool ExactMatch); bool typeCheck(SMLoc ErrorLoc, const MCInst &Inst, OperandVector &Operands); void clear() { diff --git a/llvm/test/MC/WebAssembly/type-checker-errors.s b/llvm/test/MC/WebAssembly/type-checker-errors.s index 3106fe76c8449..5fdc2f56daf57 100644 --- a/llvm/test/MC/WebAssembly/type-checker-errors.s +++ b/llvm/test/MC/WebAssembly/type-checker-errors.s @@ -19,7 +19,7 @@ local_set_no_local_type: local_set_empty_stack_while_popping: .functype local_set_empty_stack_while_popping () -> () .local i32 -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] local.set 0 end_function @@ -27,7 +27,7 @@ local_set_type_mismatch: .functype local_set_type_mismatch () -> () .local i32 f32.const 1.0 -# CHECK: [[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] local.set 0 end_function @@ -40,7 +40,7 @@ local_tee_no_local_type: local_tee_empty_stack_while_popping: .functype local_tee_empty_stack_while_popping () -> () .local f32 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [] local.tee 0 end_function @@ -48,8 +48,9 @@ local_tee_type_mismatch: .functype local_tee_type_mismatch () -> () .local f32 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] local.tee 0 + drop end_function global_get_missing_globaltype: @@ -79,7 +80,7 @@ global_set_expected_expression_operand: global_set_empty_stack_while_popping: .functype global_set_empty_stack_while_popping () -> () .globaltype valid_global, i64 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i64 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i64] but got [] global.set valid_global end_function @@ -87,7 +88,7 @@ global_set_type_mismatch: .functype global_set_type_mismatch () -> () .globaltype valid_global, i64 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected i64 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i64] but got [i32] global.set valid_global end_function @@ -109,46 +110,52 @@ table_get_missing_tabletype: table_get_empty_stack_while_popping: .functype table_get_empty_stack_while_popping () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.get valid_table + drop end_function table_get_type_mismatch: .functype table_get_type_mismatch () -> () f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] table.get valid_table + drop end_function table_set_expected_expression_operand: .functype table_set_expected_expression_operand () -> () + i32.const 0 # CHECK: :[[@LINE+1]]:13: error: expected expression operand table.set 1 end_function table_set_missing_tabletype: .functype table_set_missing_tabletype () -> () + i32.const 0 # CHECK: :[[@LINE+1]]:13: error: symbol foo: missing .tabletype table.set foo end_function table_set_empty_stack_while_popping_1: .functype table_set_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping externref +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.set valid_table end_function table_set_empty_stack_while_popping_2: .functype table_set_empty_stack_while_popping_2 (externref) -> () local.get 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.set valid_table end_function table_set_type_mismatch_1: .functype table_set_type_mismatch_1 () -> () + i32.const 0 ref.null_func -# CHECK: :[[@LINE+1]]:3: error: popped funcref, expected externref +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [externref] but got [funcref] table.set valid_table end_function @@ -156,32 +163,41 @@ table_set_type_mismatch_2: .functype table_set_type_mismatch_2 () -> () f32.const 1.0 ref.null_extern -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] table.set valid_table end_function table_fill_expected_expression_operand: .functype table_fill_expected_expression_operand () -> () + i32.const 0 + ref.null_extern + i32.const 4 # CHECK: :[[@LINE+1]]:14: error: expected expression operand table.fill 1 end_function table_fill_missing_tabletype: .functype table_fill_missing_tabletype () -> () + i32.const 0 + ref.null_extern + i32.const 4 # CHECK: :[[@LINE+1]]:14: error: symbol foo: missing .tabletype table.fill foo end_function table_fill_empty_stack_while_popping_1: .functype table_fill_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+3]]:3: error: type mismatch, expected [i32] but got [] +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table end_function table_fill_empty_stack_while_popping_2: .functype table_fill_empty_stack_while_popping_2 (i32) -> () local.get 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping externref +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table end_function @@ -189,22 +205,25 @@ table_fill_empty_stack_while_popping_3: .functype table_fill_empty_stack_while_popping_3 (i32, externref) -> () local.get 1 local.get 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table end_function table_fill_type_mismatch_1: .functype table_fill_type_mismatch_1 () -> () + i32.const 0 + ref.null_extern ref.null_func -# CHECK: :[[@LINE+1]]:3: error: popped funcref, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [funcref] table.fill valid_table end_function table_fill_type_mismatch_2: .functype table_fill_type_mismatch_2 () -> () + i32.const 0 ref.null_func i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped funcref, expected externref +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [funcref] table.fill valid_table end_function @@ -213,23 +232,16 @@ table_fill_type_mismatch_3: f32.const 2.0 ref.null_extern i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] table.fill valid_table end_function table_fill_type_mismatch_4: .functype table_fill_type_mismatch_4 () -> () - ref.null_exn i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped exnref, expected externref - table.fill valid_table - end_function - -table_fill_type_mismatch_5: - .functype table_fill_type_mismatch_5 () -> () ref.null_exn i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped exnref, expected externref +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [exnref] table.fill valid_table end_function @@ -244,14 +256,15 @@ table_grow_non_exist_table: table_grow_type_mismatch_1: .functype table_grow_type_mismatch_1 (externref, i32) -> (i32) local.get 1 -# CHECK: [[@LINE+1]]:3: error: empty stack while popping externref +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [externref] but got [] table.grow valid_table end_function table_grow_type_mismatch_2: .functype table_grow_type_mismatch_2 (externref, i32) -> (i32) local.get 0 -# CHECK: [[@LINE+1]]:3: error: popped externref, expected i32 + local.get 0 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [externref] table.grow valid_table end_function @@ -260,57 +273,62 @@ table_grow_wrong_result: local.get 0 local.get 1 table.grow valid_table -# CHECK: [[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_function drop_empty_stack_while_popping: .functype drop_empty_stack_while_popping () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function end_block_insufficient_values_on_stack_1: .functype end_block_insufficient_values_on_stack_1 () -> () block i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_block + drop end_function end_block_insufficient_values_on_stack_2: .functype end_block_insufficient_values_on_stack_2 () -> () block () -> (i32) -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_block + drop end_function end_block_type_mismatch: .functype end_block_type_mismatch () -> () block i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] end_block + drop end_function end_loop_insufficient_values_on_stack: .functype end_loop_insufficient_values_on_stack () -> () loop i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_loop + drop end_function end_loop_type_mismatch: .functype end_loop_type_mismatch () -> () loop f32 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: end got i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_loop + drop end_function end_if_insufficient_values_on_stack_1: .functype end_if_insufficient_values_on_stack_1 () -> () i32.const 1 if i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_if end_function @@ -319,8 +337,9 @@ end_if_type_mismatch_1: i32.const 1 if f32 i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: end got i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_if + drop end_function end_if_insufficient_values_on_stack_2: @@ -329,7 +348,7 @@ end_if_insufficient_values_on_stack_2: if i32 i32.const 2 else -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_if drop end_function @@ -341,7 +360,7 @@ end_if_type_mismatch_2: i32.const 2 else f32.const 3.0 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] end_if drop end_function @@ -350,7 +369,7 @@ else_insufficient_values_on_stack: .functype else_insufficient_values_on_stack () -> () i32.const 1 if i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] else i32.const 0 end_if @@ -362,7 +381,7 @@ else_type_mismatch: i32.const 1 if i32 f32.const 0.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] else i32.const 0 end_if @@ -377,7 +396,7 @@ end_try_insufficient_values_on_stack: try i32 i32.const 0 catch_all -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_try drop end_function @@ -387,7 +406,7 @@ end_try_type_mismatch: try i32 i32.const 0 catch tag_f32 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] end_try drop end_function @@ -395,7 +414,7 @@ end_try_type_mismatch: catch_insufficient_values_on_stack: .functype catch_insufficient_values_on_stack () -> () try i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] catch tag_i32 end_try drop @@ -405,7 +424,7 @@ catch_type_mismatch: .functype catch_type_mismatch () -> () try i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] catch tag_i32 end_try drop @@ -414,7 +433,7 @@ catch_type_mismatch: catch_all_insufficient_values_on_stack: .functype catch_all_insufficient_values_on_stack () -> () try i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] catch_all i32.const 0 end_try @@ -425,7 +444,7 @@ catch_all_type_mismatch: .functype catch_all_type_mismatch () -> () try i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] catch_all i32.const 0 end_try @@ -435,7 +454,7 @@ catch_all_type_mismatch: delegate_insufficient_values_on_stack: .functype delegate_insufficient_values_on_stack () -> () try i32 -# CHECK: :[[@LINE+1]]:3: error: end: insufficient values on the type stack +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] delegate 0 drop end_function @@ -444,46 +463,46 @@ delegate_type_mismatch: .functype delegate_type_mismatch () -> () try i32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] delegate 0 drop end_function end_function_empty_stack_while_popping: .functype end_function_empty_stack_while_popping () -> (i32) -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] end_function end_function_type_mismatch: .functype end_function_type_mismatch () -> (f32) i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] end_function end_function_superfluous_end_function_values: .functype end_function_superfluous_end_function_values () -> () i32.const 1 f32.const 2.0 -# CHECK: :[[@LINE+1]]:3: error: 2 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i32, f32] end_function return_empty_stack_while_popping: .functype return_empty_stack_while_popping () -> (i32) -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] return end_function return_type_mismatch: .functype return_type_mismatch () -> (f32) i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] return end_function # Missing index for call_indirect. call_indirect_empty_stack_while_popping_1: .functype call_indirect_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] call_indirect () -> () end_function @@ -491,7 +510,7 @@ call_indirect_empty_stack_while_popping_1: call_indirect_empty_stack_while_popping_2: .functype call_indirect_empty_stack_while_popping_1 (f32) -> () i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [] call_indirect (f32) -> () end_function @@ -499,7 +518,7 @@ call_indirect_type_mismatch_for_argument: .functype call_indirect_type_mismatch_for_argument () -> () i32.const 1 i32.const 2 -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [i32] call_indirect (f32) -> () end_function @@ -507,13 +526,13 @@ call_indirect_superfluous_value_at_end: .functype call_indirect_superfluous_value_at_end () -> () i32.const 1 call_indirect () -> (i64) -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i64] end_function # Missing index for return_call_indirect. return_call_indirect_empty_stack_while_popping_1: .functype return_call_indirect_empty_stack_while_popping_1 () -> () -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] return_call_indirect () -> () end_function @@ -521,7 +540,7 @@ return_call_indirect_empty_stack_while_popping_1: return_call_indirect_empty_stack_while_popping_2: .functype return_call_indirect_empty_stack_while_popping_2 () -> () i32.const 1 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping f32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [f32] but got [] return_call_indirect (f32) -> () end_function @@ -535,14 +554,14 @@ call_expected_expression_operand: call_empty_stack_while_popping: .functype call_empty_stack_while_popping () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] call fn_i32_to_void end_function call_type_mismatch: .functype call_type_mismatch () -> () f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] call fn_i32_to_void end_function @@ -551,7 +570,7 @@ call_type_mismatch: call_superfluous_value_at_end: .functype call_superfluous_value_at_end () -> () call fn_void_to_i32 -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i32] end_function call_missing_functype: @@ -568,14 +587,14 @@ return_call_expected_expression_operand: return_call_empty_stack_while_popping: .functype return_call_empty_stack_while_popping () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] return_call fn_i32_to_void end_function return_call_type_mismatch: .functype return_call_type_mismatch () -> () f32.const 1.0 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [f32] return_call fn_i32_to_void end_function @@ -607,27 +626,29 @@ catch_superfluous_value_at_end: catch tag_i32 end_try # FIXME: Superfluous value should be caught at end_try? -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [i32] end_function ref_is_null_empty_stack_while_popping: .functype ref_is_null_empty_stack_while_popping () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping reftype +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [ref] but got [] ref.is_null + drop end_function ref_is_null_type_mismatch: .functype ref_is_null_type_mismatch () -> () i32.const 1 -# CHECK: [[@LINE+1]]:3: error: popped i32, expected reftype +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [ref] but got [i32] ref.is_null + drop end_function ref_is_null_pushes_i32: .functype ref_is_null_pushes_i32 () -> (i64) ref.null_func ref.is_null -# CHECK: :[[@LINE+1]]:3: error: popped i32, expected i64 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i64] but got [i32] end_function # For the other instructions, the type checker checks vs the operands in the @@ -636,16 +657,18 @@ ref_is_null_pushes_i32: other_insn_test_1: .functype other_insn_test_1 () -> () -# CHECK: [[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: [[@LINE+1]]:3: error: type mismatch, expected [i32, i32] but got [] i32.add + drop end_function other_insn_test_2: .functype other_insn_test_2 () -> () i32.const 1 ref.null_func -# CHECK: :[[@LINE+1]]:3: error: popped funcref, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, i32] but got [i32, funcref] i32.add + drop end_function other_insn_test_3: @@ -653,7 +676,7 @@ other_insn_test_3: f32.const 1.0 f32.const 2.0 f32.add -# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [] but got [f32] end_function # Unreachable code within 'block' does not affect type checking after @@ -663,7 +686,7 @@ check_after_unreachable_within_block: block unreachable end_block -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -673,7 +696,7 @@ check_after_unreachable_within_loop: loop unreachable end_loop -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -686,7 +709,7 @@ check_after_unreachable_within_if_1: else unreachable end_if -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -697,7 +720,7 @@ check_after_unreachable_within_if_2: if unreachable else -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_if end_function @@ -710,7 +733,7 @@ check_after_unreachable_within_try_1: catch_all unreachable end_try -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -721,7 +744,7 @@ check_after_unreachable_within_try_2: unreachable catch tag_i32 drop -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_try end_function @@ -732,7 +755,7 @@ check_after_unreachable_within_try_3: try unreachable catch_all -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_try end_function @@ -743,7 +766,7 @@ check_after_unreachable_within_try_4: try unreachable delegate 0 -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [any] but got [] drop end_function @@ -753,7 +776,7 @@ br_invalid_type_loop: loop (i32) -> (f32) drop f32.const 1.0 -# CHECK: :[[@LINE+1]]:5: error: br got f32, expected i32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [i32] but got [f32] br 0 end_loop drop @@ -763,7 +786,7 @@ br_invalid_type_block: .functype br_invalid_type_block () -> () i32.const 1 block (i32) -> (f32) -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 f32.const 1.0 end_block @@ -777,7 +800,7 @@ br_invalid_type_if: f32.const 1.0 else i32.const 1 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 end_if drop @@ -787,7 +810,7 @@ br_invalid_type_try: .functype br_invalid_type_try () -> () try f32 i32.const 1 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 catch tag_f32 end_try @@ -799,7 +822,7 @@ br_invalid_type_catch: try f32 f32.const 1.0 catch tag_i32 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 end_try drop @@ -811,7 +834,7 @@ br_invalid_type_catch_all: f32.const 1.0 catch_all i32.const 1 -# CHECK: :[[@LINE+1]]:5: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [f32] but got [i32] br 0 end_try drop @@ -834,7 +857,7 @@ br_incorrect_signature: block f32 block i32 i32.const 1 -# CHECK: :[[@LINE+1]]:7: error: br got i32, expected f32 +# CHECK: :[[@LINE+1]]:7: error: type mismatch, expected [f32] but got [i32] br 1 end_block drop @@ -847,7 +870,7 @@ br_incorrect_func_signature: .functype br_incorrect_func_signature () -> (i32) block f32 f32.const 1.0 -# CHECK: :[[@LINE+1]]:5: error: br got f32, expected i32 +# CHECK: :[[@LINE+1]]:5: error: type mismatch, expected [i32] but got [f32] br 1 end_block drop @@ -856,20 +879,29 @@ br_incorrect_func_signature: multiple_errors_in_function: .functype multiple_errors_in_function () -> () -# CHECK: :[[@LINE+2]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [i32] but got [] # CHECK: :[[@LINE+1]]:13: error: expected expression operand table.get 1 -# CHECK: :[[@LINE+3]]:3: error: empty stack while popping i32 -# CHECK: :[[@LINE+2]]:3: error: empty stack while popping externref -# CHECK: :[[@LINE+1]]:3: error: empty stack while popping i32 +# CHECK: :[[@LINE+3]]:3: error: type mismatch, expected [i32] but got [] +# CHECK: :[[@LINE+2]]:3: error: type mismatch, expected [externref] but got [] +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [] table.fill valid_table f32.const 0.0 ref.null_extern -# CHECK: :[[@LINE+2]]:3: error: popped externref, expected i32 -# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, i32] but got [f32, externref] i32.add drop + end_function + +.functype take_and_return_multi(i32, i64, f32, f64) -> (i32, i64, f32, f64) +call_with_multi_param_and_return: + .functype call_with_multi_param_and_return () -> (i32) + ref.null_extern + f32.const 0.0 +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32, i64, f32, f64] but got [externref, f32] + call take_and_return_multi +# CHECK: :[[@LINE+1]]:3: error: type mismatch, expected [i32] but got [i32, i64, f32, f64] end_function diff --git a/llvm/test/MC/WebAssembly/type-checker-return.s b/llvm/test/MC/WebAssembly/type-checker-return.s index 552093bc555bd..016c034058101 100644 --- a/llvm/test/MC/WebAssembly/type-checker-return.s +++ b/llvm/test/MC/WebAssembly/type-checker-return.s @@ -1,10 +1,5 @@ # RUN: llvm-mc -triple=wasm32 -mattr=+tail-call %s 2>&1 -# XFAIL: * - -# FIXME: These shouldn't produce an error, as return will implicitly drop any -# superfluous values. - return_superfluous_return_values: .functype return_superfluous_return_values () -> () i32.const 1