summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/wasm-shell.cpp6
-rw-r--r--src/wasm-type.h7
-rw-r--r--src/wasm/wasm-type.cpp12
-rw-r--r--src/wasm/wasm-validator.cpp8
-rw-r--r--test/lit/validation/nn-tuples.wast17
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)))
+ )
+)