From 82de1f088b2a13621158609b04ba9c97c473fe6f Mon Sep 17 00:00:00 2001
From: Evan Haas <evan@lagerdata.com>
Date: Wed, 24 Apr 2024 23:55:14 -0700
Subject: [PATCH] Type: set incomplete array length correctly for typeof-types

Fixes #692
---
 src/aro/Parser.zig                   |  6 ++----
 src/aro/Type.zig                     | 18 ++++++++++++++++++
 test/cases/typeof incomplete array.c |  2 ++
 3 files changed, 22 insertions(+), 4 deletions(-)
 create mode 100644 test/cases/typeof incomplete array.c

diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig
index 8c971358..fc2afcc0 100644
--- a/src/aro/Parser.zig
+++ b/src/aro/Parser.zig
@@ -1818,10 +1818,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
         var init_list_expr = try p.initializer(init_d.d.ty);
         init_d.initializer = init_list_expr;
         if (!init_list_expr.ty.isArray()) break :init;
-        if (init_d.d.ty.specifier == .incomplete_array) {
-            // Modifying .data is exceptionally allowed for .incomplete_array.
-            init_d.d.ty.data.array.len = init_list_expr.ty.arrayLen() orelse break :init;
-            init_d.d.ty.specifier = .array;
+        if (init_d.d.ty.is(.incomplete_array)) {
+            init_d.d.ty.setIncompleteArrayLen(init_list_expr.ty.arrayLen() orelse break :init);
         }
     }
 
diff --git a/src/aro/Type.zig b/src/aro/Type.zig
index dd983c8d..de9932ae 100644
--- a/src/aro/Type.zig
+++ b/src/aro/Type.zig
@@ -463,6 +463,24 @@ pub fn isArray(ty: Type) bool {
     };
 }
 
+
+/// Must only be used to set the length of an incomplete array as determined by its initializer
+pub fn setIncompleteArrayLen(ty: *Type, len: u64) void {
+    switch (ty.specifier) {
+        .incomplete_array => {
+            // Modifying .data is exceptionally allowed for .incomplete_array.
+            ty.data.array.len = len;
+            ty.specifier = .array;
+        },
+
+        .typeof_type => ty.data.sub_type.setIncompleteArrayLen(len),
+        .typeof_expr => ty.data.expr.ty.setIncompleteArrayLen(len),
+        .attributed => ty.data.attributed.base.setIncompleteArrayLen(len),
+
+        else => unreachable,
+    }
+}
+
 /// Whether the type is promoted if used as a variadic argument or as an argument to a function with no prototype
 fn undergoesDefaultArgPromotion(ty: Type, comp: *const Compilation) bool {
     return switch (ty.specifier) {
diff --git a/test/cases/typeof incomplete array.c b/test/cases/typeof incomplete array.c
new file mode 100644
index 00000000..4cce1d4f
--- /dev/null
+++ b/test/cases/typeof incomplete array.c	
@@ -0,0 +1,2 @@
+typeof(const int[]) arr1 = {1,2};
+_Static_assert(sizeof(arr1) == sizeof(int[2]), "");