summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-06-08 08:26:07 -0700
committerGitHub <noreply@github.com>2023-06-08 15:26:07 +0000
commitbffd98c80ef2d2ea20b49618e8e345406c8f451c (patch)
tree9a4b27ca5ae4f9a8ca925da978df151e0a05503f /test
parent1daa10fb356cb01d80eaa3fd13c8c1d9a53ea343 (diff)
downloadbinaryen-bffd98c80ef2d2ea20b49618e8e345406c8f451c.tar.gz
binaryen-bffd98c80ef2d2ea20b49618e8e345406c8f451c.tar.bz2
binaryen-bffd98c80ef2d2ea20b49618e8e345406c8f451c.zip
TypeRefining: Fix a bug with chains of StructGets (#5757)
If we have (struct.get $A (struct.get $B then if both types end up refined we may have a problem. If the inner one is refined to emit nullref then the outer one no longer knows what type it is, since it depends on the type of the ref child for that in our IR. We can't just skip updating it, as the outside may depend on its new refined type to validate. To avoid errors here, just make this code that is effectively unreachable also actually unreachable.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/type-refining.wast55
1 files changed, 55 insertions, 0 deletions
diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast
index 8258a3a54..824ad43a8 100644
--- a/test/lit/passes/type-refining.wast
+++ b/test/lit/passes/type-refining.wast
@@ -1167,3 +1167,58 @@
)
)
)
+
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct (field (mut nullref))))
+ (type $A (struct (field (mut anyref))))
+ ;; CHECK: (type $B (struct (field (mut nullref))))
+ (type $B (struct (field (mut (ref null $A)))))
+ )
+
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (func $0 (type $none_=>_none)
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (struct.new_default $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $0
+ (struct.set $A 0
+ (struct.new $A
+ ;; These two struct.gets will both be refined. That of $B will be
+ ;; refined to a get of a null, at which point the get of $A could get
+ ;; confused and not know what type it is reading from (since in the IR,
+ ;; we depend on the ref for that). The pass should not error here while
+ ;; it refines both the struct type's fields to nullref, after which the
+ ;; code here will be unreachable (since we do a struct.get from a
+ ;; nullref).
+ (struct.get $A 0
+ (struct.get $B 0
+ (struct.new_default $B)
+ )
+ )
+ )
+ (ref.null none)
+ )
+ )
+)