if (popType(ErrorLoc, {}))
return true;
} else if (Name == "end_block" || Name == "end_loop" || Name == "end_if" ||
- Name == "else" || Name == "end_try") {
- if (checkEnd(ErrorLoc, Name == "else"))
- return true;
- if (Name == "end_block")
- Unreachable = false;
+ Name == "else" || Name == "end_try" || Name == "catch" ||
+ Name == "catch_all" || Name == "delegate") {
+ if (checkEnd(ErrorLoc,
+ Name == "else" || Name == "catch" || Name == "catch_all"))
+ return true;
+ Unreachable = false;
+ if (Name == "catch") {
+ const MCSymbolRefExpr *SymRef;
+ if (getSymRef(Operands[1]->getStartLoc(), Inst, SymRef))
+ return true;
+ const auto *WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol());
+ const auto *Sig = WasmSym->getSignature();
+ if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_TAG)
+ return typeError(Operands[1]->getStartLoc(), StringRef("symbol ") +
+ WasmSym->getName() +
+ " missing .tagtype");
+ // catch instruction pushes values whose types are specified in the tag's
+ // "params" part
+ Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end());
+ }
} else if (Name == "return") {
if (endOfFunction(ErrorLoc))
return true;
if (checkSig(ErrorLoc, *Sig)) return true;
if (Name == "return_call" && endOfFunction(ErrorLoc))
return true;
- } else if (Name == "catch") {
- const MCSymbolRefExpr *SymRef;
- if (getSymRef(Operands[1]->getStartLoc(), Inst, SymRef))
- return true;
- const auto *WasmSym = cast<MCSymbolWasm>(&SymRef->getSymbol());
- const auto *Sig = WasmSym->getSignature();
- if (!Sig || WasmSym->getType() != wasm::WASM_SYMBOL_TYPE_TAG)
- return typeError(Operands[1]->getStartLoc(), StringRef("symbol ") +
- WasmSym->getName() +
- " missing .tagtype");
- // catch instruction pushes values whose types are specified in the tag's
- // "params" part
- Stack.insert(Stack.end(), Sig->Params.begin(), Sig->Params.end());
} else if (Name == "unreachable") {
Unreachable = true;
} else if (Name == "ref.is_null") {
end_loop
end_function
-end_if_insufficient_values_on_stack:
- .functype end_if_insufficient_values_on_stack () -> ()
+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
end_if
end_function
-end_if_type_mismatch:
- .functype end_if_type_mismatch () -> ()
+end_if_type_mismatch_1:
+ .functype end_if_type_mismatch_1 () -> ()
i32.const 1
if f32
i32.const 1
end_if
end_function
-else_insufficient_values_on_stack:
- .functype else_insufficient_values_on_stack () -> ()
+end_if_insufficient_values_on_stack_2:
+ .functype end_if_insufficient_values_on_stack_2 () -> ()
i32.const 1
if i32
i32.const 2
else
# FIXME: Should complain about insufficient values on the stack.
end_if
-# FIXME: Should complain about superflous value on the stack.
+ drop
end_function
-else_type_mismatch:
- .functype else_type_mismatch () -> ()
+end_if_type_mismatch_2:
+ .functype end_if_type_mismatch_2 () -> ()
i32.const 1
if i32
i32.const 2
drop
end_function
+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
+ else
+ i32.const 0
+ end_if
+ drop
+ end_function
+
+else_type_mismatch:
+ .functype else_type_mismatch () -> ()
+ i32.const 1
+ if i32
+ f32.const 0.0
+# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32
+ else
+ i32.const 0
+ end_if
+ drop
+ end_function
+
+.tagtype tag_i32 i32
+
end_try_insufficient_values_on_stack:
.functype end_try_insufficient_values_on_stack () -> ()
try i32
end_try
end_function
+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
+ catch tag_i32
+ end_try
+ drop
+ end_function
+
+catch_type_mismatch:
+ .functype catch_type_mismatch () -> ()
+ try i32
+ f32.const 1.0
+# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32
+ catch tag_i32
+ end_try
+ drop
+ end_function
+
+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
+ catch_all
+ i32.const 0
+ end_try
+ drop
+ end_function
+
+catch_all_type_mismatch:
+ .functype catch_all_type_mismatch () -> ()
+ try i32
+ f32.const 1.0
+# CHECK: :[[@LINE+1]]:3: error: popped f32, expected i32
+ catch_all
+ i32.const 0
+ end_try
+ drop
+ end_function
+
+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
+ delegate 0
+ drop
+ end_function
+
+delegate_type_mismatch:
+ .functype delegate_type_mismatch () -> ()
+ try i32
+ f32.const 1.0
+# CHECK: :[[@LINE+1]]:3: error: end got f32, expected i32
+ 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
catch_superfluous_value_at_end:
.functype catch_superfluous_value_at_end () -> ()
- .tagtype tag_i32 i32
try
catch tag_i32
end_try
f32.add
# CHECK: :[[@LINE+1]]:3: error: 1 superfluous return values
end_function
+
+# Unreachable code within 'block' does not affect type checking after
+# 'end_block'
+check_after_unreachable_within_block:
+ .functype check_after_unreachable_within_block () -> ()
+ block
+ unreachable
+ end_block
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_function
+
+# Unreachable code within 'loop' does not affect type checking after 'end_loop'
+check_after_unreachable_within_loop:
+ .functype check_after_unreachable_within_loop () -> ()
+ loop
+ unreachable
+ end_loop
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_function
+
+# Unreachable code within 'if' does not affect type checking after 'end_if'
+check_after_unreachable_within_if_1:
+ .functype check_after_unreachable_within_if_1 () -> ()
+ i32.const 0
+ if
+ unreachable
+ else
+ unreachable
+ end_if
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_function
+
+# Unreachable code within 'if' does not affect type checking after 'else'
+check_after_unreachable_within_if_2:
+ .functype check_after_unreachable_within_if_2 () -> ()
+ i32.const 0
+ if
+ unreachable
+ else
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_if
+ end_function
+
+# Unreachable code within 'try' does not affect type checking after 'end_try'
+check_after_unreachable_within_try_1:
+ .functype check_after_unreachable_within_try_1 () -> ()
+ try
+ unreachable
+ catch_all
+ unreachable
+ end_try
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_function
+
+# Unreachable code within 'try' does not affect type checking after 'catch'
+check_after_unreachable_within_try_2:
+ .functype check_after_unreachable_within_try_2 () -> ()
+ try
+ unreachable
+ catch tag_i32
+ drop
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_try
+ end_function
+
+# Unreachable code within 'try' does not affect type checking after 'catch_all'
+check_after_unreachable_within_try_3:
+ .functype check_after_unreachable_within_try_3 () -> ()
+ try
+ unreachable
+ catch_all
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_try
+ end_function
+
+# Unreachable code within 'try' does not affect type checking after 'delegate'
+check_after_unreachable_within_try_4:
+ .functype check_after_unreachable_within_try_4 () -> ()
+ try
+ unreachable
+ delegate 0
+# CHECK: :[[@LINE+1]]:3: error: empty stack while popping value
+ drop
+ end_function