From 63d3e3bdecda18993d1685f59d7b05bc3427e59d Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Wed, 25 Feb 2026 23:12:13 +0000 Subject: [PATCH] Fix for tag.wast spec test --- check.py | 5 +++-- scripts/test/shared.py | 1 - src/ir/import-utils.h | 10 +++++++--- src/parser/contexts.h | 11 +++++++++-- src/tools/execution-results.h | 2 +- src/tools/wasm-ctor-eval.cpp | 7 ++----- src/wasm-interpreter.h | 3 +-- 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/check.py b/check.py index dfd67743274..6efd598f9b0 100755 --- a/check.py +++ b/check.py @@ -200,7 +200,9 @@ def check_expected(actual, expected, stdout=None): UNSPLITTABLE_TESTS = [Path(x) for x in [ "spec/testsuite/instance.wast", - "spec/instance.wast"]] + "spec/instance.wast", + "spec/testsuite/tag.wast", + "spec/tag.wast"]] def is_splittable(wast: Path): @@ -377,7 +379,6 @@ def run_example_tests(): subprocess.check_call(cmd) print('run...', output_file) actual = subprocess.check_output([os.path.abspath(output_file)]).decode('utf-8') - os.remove(output_file) shared.fail_if_not_identical_to_file(actual, expected) diff --git a/scripts/test/shared.py b/scripts/test/shared.py index ad02b617d44..820044cc067 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -425,7 +425,6 @@ def get_tests(test_dir, extensions=[], recursive=False): 'id.wast', # Empty IDs should be disallowed 'instance.wast', # Requires support for table default elements 'table64.wast', # Requires validations for table size - 'tag.wast', # Non-empty tag results allowed by stack switching 'local_init.wast', # Requires local validation to respect unnamed blocks 'ref_func.wast', # Requires rejecting undeclared functions references 'ref_is_null.wast', # Requires support for non-nullable reference types in tables diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index 4c7907f94e4..0d95be2fb10 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -138,7 +138,7 @@ class ImportResolver { virtual RuntimeTable* getTableOrNull(ImportNames name, const Table& type) const = 0; - virtual Tag* getTagOrNull(ImportNames name, const Signature& type) const = 0; + virtual Tag* getTagOrNull(ImportNames name, HeapType type) const = 0; }; // Looks up imports from the given `linkedInstances`. @@ -170,14 +170,18 @@ class LinkedInstancesImportResolver : public ImportResolver { return instance->getExportedTableOrNull(name.name); } - Tag* getTagOrNull(ImportNames name, const Signature& type) const override { + Tag* getTagOrNull(ImportNames name, HeapType type) const override { auto it = linkedInstances.find(name.module); if (it == linkedInstances.end()) { return nullptr; } ModuleRunnerType* instance = it->second.get(); - return instance->getExportedTagOrNull(name.name); + auto* tag = instance->getExportedTagOrNull(name.name); + if (tag && tag->type != type) { + return nullptr; + } + return tag; } private: diff --git a/src/parser/contexts.h b/src/parser/contexts.h index c16ac92268e..a833c85f70a 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -1533,12 +1533,19 @@ struct ParseModuleTypesCtx : TypeParserCtx, Result<> addDeclareElem(Name, ElemListT&&, Index) { return Ok{}; } - Result<> - addTag(Name, const std::vector&, ImportNames*, TypeUse use, Index pos) { + Result<> addTag(Name name, + const std::vector& exports, + ImportNames* import, + TypeUse use, + Index pos) { auto& t = wasm.tags[index]; if (!use.type.isSignature()) { return in.err(pos, "tag type must be a signature"); } + if (use.type.getSignature().results != Type::none && + !wasm.features.hasStackSwitching()) { + return in.err(pos, "non-empty tag result type"); + } t->type = use.type; return Ok{}; } diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index f5f55bdaaee..62fb098880c 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -353,7 +353,7 @@ struct LoggingExternalInterface : public ShellExternalInterface { class FuzzerImportResolver : public LinkedInstancesImportResolver { using LinkedInstancesImportResolver::LinkedInstancesImportResolver; - Tag* getTagOrNull(ImportNames name, const Signature& type) const override { + Tag* getTagOrNull(ImportNames name, HeapType type) const override { if (name.module == "fuzzing-support") { if (name.name == "wasmtag") { return &wasmTag; diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 1c8f0c5216f..a8b693ea53d 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -84,14 +84,11 @@ class EvallingImportResolver : public ImportResolver { throw FailToEvalException{"Imported table access."}; } - // We assume that each tag import is distinct. This is wrong if the same tag - // instantiation is imported twice with different import names. - Tag* getTagOrNull(ImportNames name, - const Signature& signature) const override { + Tag* getTagOrNull(ImportNames name, HeapType type) const override { auto [it, inserted] = importedTags.try_emplace(name, Tag{}); if (inserted) { auto& tag = it->second; - tag.type = HeapType(signature); + tag.type = type; } return &it->second; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 5ae570437ed..a1925c562c3 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3478,8 +3478,7 @@ class ModuleRunnerBase : public ExpressionRunner { for (auto& tag : wasm.tags) { if (tag->imported()) { auto importNames = tag->importNames(); - auto importedTag = - importResolver->getTagOrNull(importNames, tag->type.getSignature()); + auto importedTag = importResolver->getTagOrNull(importNames, tag->type); if (!importedTag) { externalInterface->trap((std::stringstream() << "Imported tag " << importNames