diff options
-rw-r--r-- | src/tools/wasm-shell.cpp | 6 | ||||
-rw-r--r-- | src/wasm-type.h | 7 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 12 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 8 | ||||
-rw-r--r-- | test/lit/validation/nn-tuples.wast | 17 |
5 files changed, 43 insertions, 7 deletions
diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 0de93c69e..2d0fbf14c 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -134,7 +134,7 @@ protected: lastModule = module->name; builders[moduleName] = builder; modules[moduleName].swap(module); - modules[moduleName]->features = FeatureSet::All; + modules[moduleName]->features.setAll(); bool valid = WasmValidator().validate(*modules[moduleName]); if (!valid) { std::cout << *modules[moduleName] << '\n'; @@ -237,7 +237,7 @@ protected: void parseModuleAssertion(Element& s) { Module wasm; - wasm.features = FeatureSet::All; + wasm.features.setAll(); std::unique_ptr<SExpressionWasmBuilder> builder; auto id = s[0]->str(); @@ -358,7 +358,7 @@ protected: "memory", spectest->memory.name, ExternalKind::Memory)); modules["spectest"].swap(spectest); - modules["spectest"]->features = FeatureSet::All; + modules["spectest"]->features.setAll(); instantiate(modules["spectest"].get()); linkedInstances["spectest"] = instances["spectest"]; // print_* functions are handled separately, no need to define here. diff --git a/src/wasm-type.h b/src/wasm-type.h index 05deeef15..4d908fe05 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -186,6 +186,13 @@ public: bool isArray() const; bool isDefaultable() const; + // Check if a type is either defaultable or non-nullable. This is useful in + // the case where we allow non-nullable types, but we disallow other things + // that are non-defaultable. For example, when GC-non-nullable references are + // allowed we can have a non-nullable reference, but we cannot have any other + // nondefaultable type. + bool isDefaultableOrNonNullable() const; + Nullability getNullability() const; private: diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index ea4e43efe..ce823aae0 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -1021,6 +1021,18 @@ bool Type::isDefaultable() const { return isConcrete() && !isNonNullable() && !isRtt(); } +bool Type::isDefaultableOrNonNullable() const { + if (isTuple()) { + for (auto t : *this) { + if (!t.isDefaultableOrNonNullable()) { + return false; + } + } + return true; + } + return isConcrete() && !isRtt(); +} + Nullability Type::getNullability() const { return isNullable() ? Nullable : NonNullable; } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 86fc4811b..8d35543fc 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2728,11 +2728,11 @@ void FunctionValidator::visitFunction(Function* curr) { shouldBeTrue(result.isConcrete(), curr, "results must be concretely typed"); } for (const auto& var : curr->vars) { - if (var.isRef() && getModule()->features.hasGCNNLocals()) { - continue; - } features |= var.getFeatures(); - shouldBeTrue(var.isDefaultable(), var, "vars must be defaultable"); + bool valid = getModule()->features.hasGCNNLocals() + ? var.isDefaultableOrNonNullable() + : var.isDefaultable(); + shouldBeTrue(valid, var, "vars must be defaultable"); } shouldBeTrue(features <= getModule()->features, curr->name, diff --git a/test/lit/validation/nn-tuples.wast b/test/lit/validation/nn-tuples.wast new file mode 100644 index 000000000..452a6c77e --- /dev/null +++ b/test/lit/validation/nn-tuples.wast @@ -0,0 +1,17 @@ +;; Test for non-nullable types in tuples + +;; RUN: not wasm-opt -all %s 2>&1 | filecheck %s --check-prefix NO-NN-LOCALS +;; RUN: wasm-opt -all %s --enable-gc-nn-locals -o - -S | filecheck %s --check-prefix NN-LOCALS + +;; NO-NN-LOCALS: vars must be defaultable + +;; NN-LOCALS: (module +;; NN-LOCALS: (local $tuple ((ref any) (ref any))) +;; NN-LOCALS: (nop) +;; NN-LOCALS: ) + +(module + (func $foo + (local $tuple ((ref any) (ref any))) + ) +) |