Przeglądaj źródła

fix(codegen): do not double-load nested-array designators (Fact/Design); row->open-array actuals no longer SIGSEGV

Fact loaded array-typed Design results a second time, although Design
already materializes the sub-descriptor pointer for array suffixes
([i] and .field both ElemLoad). Treating ClArray like record/set/class
(address semantics) fixes passing a row to an open-array formal and
the a[i][j]/HIGH(a[i]) patterns m2make needed.

New tests/t_nestidx.mod (42); main suite 108/108.
Eric Streit 2 tygodni temu
rodzic
commit
f019a17ef4

+ 1 - 0
compiler/run_tests.sh

@@ -61,6 +61,7 @@ expect_run t_case.mod 103
 expect_run t_bool.mod 42
 expect_run t_real.mod 31
 expect_run t_array.mod 108
+expect_run t_nestidx.mod 42
 expect_run t_constfold.mod 42
 expect_run t_emptystat.mod 42
 expect_run t_highlen.mod 18

+ 2 - 0
compiler/src/M2.atg

@@ -1820,6 +1820,8 @@ PRODUCTIONS
                                                     SymTab.ClRecord)
                                                 OR (SymTab.ClassOf(dt) =
                                                     SymTab.ClSet)
+                                                OR (SymTab.ClassOf(dt) =
+                                                    SymTab.ClArray)
                                                 OR (SymTab.ClassOf(dt) =
                                                     SymTab.ClClass) THEN
                                                QbeGen.CopyOp(qd, q)

+ 251 - 249
compiler/src/M2.lst

@@ -1838,263 +1838,265 @@ Listing:
  1821                                                  OR (SymTab.ClassOf(dt) =
  1822                                                      SymTab.ClSet)
  1823                                                  OR (SymTab.ClassOf(dt) =
- 1824                                                      SymTab.ClClass) THEN
- 1825                                                 QbeGen.CopyOp(qd, q)
- 1826                                               ELSE QbeGen.ElemLoad(qd, dt,
- 1827                                                 q)
- 1828                                               END
- 1829                                             ELSE QbeGen.CopyOp(qd, q)
- 1830                                             END;
- 1831                                             IF (dk = SymTab.KindVar)
- 1832                                                OR (dk = SymTab.KindParam)
- 1833                                                OR (dk =
- 1834                                                   SymTab.KindField) THEN
- 1835                                               IF sfx THEN
- 1836                                                 QbeGen.NoteAddr(q, qd)
- 1837                                               ELSE
- 1838                                                 QbeGen.AddrOf(qn, qa);
- 1839                                                 QbeGen.NoteAddr(q, qa)
- 1840                                               END
- 1841                                             ELSIF sfx
- 1842   AND (dt #
- 1843                                                   SymTab.InvalidType)
- 1844   AND ((SymTab.ClassOf(dt) =
- 1845                                                    SymTab.ClArray)
- 1846                                                   OR (SymTab.ClassOf(dt) =
- 1847                                                       SymTab.ClSet)
+ 1824                                                      SymTab.ClArray)
+ 1825                                                  OR (SymTab.ClassOf(dt) =
+ 1826                                                      SymTab.ClClass) THEN
+ 1827                                                 QbeGen.CopyOp(qd, q)
+ 1828                                               ELSE QbeGen.ElemLoad(qd, dt,
+ 1829                                                 q)
+ 1830                                               END
+ 1831                                             ELSE QbeGen.CopyOp(qd, q)
+ 1832                                             END;
+ 1833                                             IF (dk = SymTab.KindVar)
+ 1834                                                OR (dk = SymTab.KindParam)
+ 1835                                                OR (dk =
+ 1836                                                   SymTab.KindField) THEN
+ 1837                                               IF sfx THEN
+ 1838                                                 QbeGen.NoteAddr(q, qd)
+ 1839                                               ELSE
+ 1840                                                 QbeGen.AddrOf(qn, qa);
+ 1841                                                 QbeGen.NoteAddr(q, qa)
+ 1842                                               END
+ 1843                                             ELSIF sfx
+ 1844   AND (dt #
+ 1845                                                   SymTab.InvalidType)
+ 1846   AND ((SymTab.ClassOf(dt) =
+ 1847                                                    SymTab.ClArray)
  1848                                                   OR (SymTab.ClassOf(dt) =
- 1849                                                       SymTab.ClRecord)) THEN
- 1850                                               QbeGen.NoteAddr(qd, qd)
- 1851                                             END; .)
- 1852        [ ArgList<qn, TRUE, ct2, q2, called>
- 1853                                          (. t := ct2;
- 1854                                             QbeGen.CopyOp(q2, q); .) ]
- 1855                                          (. IF NOT called
- 1856   AND (dk = SymTab.KindProc) THEN
- 1857                                               (* bare zero-arg function
- 1858                                                  call (parentheses may be
- 1859                                                  omitted); a proper or
- 1860                                                  parameterised proc here
- 1861                                                  is 230 *)
- 1862                                               IF (SymTab.ProcNPar(qn) = 0)
- 1863   AND (SymTab.ProcRes(qn) #
- 1864                                                     SymTab.InvalidType) THEN
- 1865                                                 QbeGen.Mangled(qn,
- 1866                                                   SymTab.ProcUid(qn), qm0);
- 1867                                                 QbeGen.CallBegin(qm0,
- 1868                                                   SymTab.ProcRes(qn),
- 1869                                                   SymTab.ProcDepthOf(qn),
- 1870                                                   SymTab.IsExternal(qn));
- 1871                                                 QbeGen.CallEnd(TRUE, q);
- 1872                                                 t := SymTab.ProcRes(qn)
- 1873                                               ELSE SemError(230)
- 1874                                               END
- 1875                                             END; .)
- 1876      | ( "HIGH"                          (. isHigh := TRUE; .)
- 1877        | "LEN"                           (. isHigh := FALSE; .) )
- 1878        "(" Design<dt, dk, qd, qn, sfx> ")"
- 1879                                          (. IF dt = SymTab.InvalidType THEN
- 1880                                             ELSIF SymTab.ClassOf(dt) #
- 1881                                                   SymTab.ClArray THEN
- 1882                                               SemError(217);
- 1883                                               t := SymTab.InvalidType;
- 1884                                               QbeGen.CopyOp("0", q)
- 1885                                             ELSE
- 1886                                               IF isHigh THEN
- 1887                                                 IF SymTab.IsOpenArray(dt) THEN
- 1888                                                   QbeGen.OpenHi(qd, qr)
- 1889                                                 ELSE
- 1890                                                   QbeGen.IntStr(
- 1891                                                     SymTab.ArrayHi(dt), qr)
- 1892                                                 END
- 1893                                               ELSE
- 1894                                                 IF SymTab.IsOpenArray(dt) THEN
- 1895                                                   QbeGen.LoadCount(qd, qr)
- 1896                                                 ELSE
- 1897                                                   QbeGen.IntStr(VAL(
- 1898                                                     INTEGER,
- 1899                                                     SymTab.ArrayLen(dt)),
- 1900                                                     qr)
- 1901                                                 END
- 1902                                               END;
- 1903                                                t := SymTab.IntType();
- 1904                                                QbeGen.CopyOp(qr, q)
- 1905                                              END; .)
- 1906      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 1907                                          (. IF dt = SymTab.InvalidType THEN
- 1908                                               t := SymTab.InvalidType;
- 1909                                               QbeGen.CopyOp("0", q)
- 1910                                             ELSE
- 1911                                               QbeGen.IntStr(VAL(INTEGER,
- 1912                                                 SymTab.ObjectSize(dt)), q);
- 1913                                               t := SymTab.IntType()
- 1914                                             END; .)
- 1915      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 1916                                          (. IF dt = SymTab.InvalidType THEN
- 1917                                               t := SymTab.InvalidType;
- 1918                                               QbeGen.CopyOp("0", q)
- 1919                                             ELSE
- 1920                                               IF sfx THEN
- 1921                                                 QbeGen.CopyOp(qd, q)
- 1922                                               ELSIF (dk = SymTab.KindVar)
- 1923                                                  OR (dk = SymTab.KindParam) THEN
- 1924                                                 QbeGen.AddrOf(qn, q)
- 1925                                               ELSE SemError(230);
- 1926                                                 QbeGen.CopyOp("0", q)
- 1927                                               END;
- 1928                                               t := SymTab.AddrType()
- 1929                                             END; .)
- 1930      | "CHR" "(" Expr<et, q> ")"
- 1931                                          (. IF (et # SymTab.InvalidType)
- 1932   AND NOT SymTab.IsIntFamily(et) THEN
- 1933                                               SemError(211) END;
- 1934                                             t := SymTab.CharType(); .)
- 1935      | "ORD" "(" Expr<et, q> ")"
- 1936                                          (. IF et # SymTab.InvalidType THEN
- 1937                                               IF (SymTab.ClassOf(et) #
- 1938                                                   SymTab.ClChar)
- 1939   AND (SymTab.ClassOf(et) #
- 1940                                                     SymTab.ClBool)
+ 1849                                                       SymTab.ClSet)
+ 1850                                                   OR (SymTab.ClassOf(dt) =
+ 1851                                                       SymTab.ClRecord)) THEN
+ 1852                                               QbeGen.NoteAddr(qd, qd)
+ 1853                                             END; .)
+ 1854        [ ArgList<qn, TRUE, ct2, q2, called>
+ 1855                                          (. t := ct2;
+ 1856                                             QbeGen.CopyOp(q2, q); .) ]
+ 1857                                          (. IF NOT called
+ 1858   AND (dk = SymTab.KindProc) THEN
+ 1859                                               (* bare zero-arg function
+ 1860                                                  call (parentheses may be
+ 1861                                                  omitted); a proper or
+ 1862                                                  parameterised proc here
+ 1863                                                  is 230 *)
+ 1864                                               IF (SymTab.ProcNPar(qn) = 0)
+ 1865   AND (SymTab.ProcRes(qn) #
+ 1866                                                     SymTab.InvalidType) THEN
+ 1867                                                 QbeGen.Mangled(qn,
+ 1868                                                   SymTab.ProcUid(qn), qm0);
+ 1869                                                 QbeGen.CallBegin(qm0,
+ 1870                                                   SymTab.ProcRes(qn),
+ 1871                                                   SymTab.ProcDepthOf(qn),
+ 1872                                                   SymTab.IsExternal(qn));
+ 1873                                                 QbeGen.CallEnd(TRUE, q);
+ 1874                                                 t := SymTab.ProcRes(qn)
+ 1875                                               ELSE SemError(230)
+ 1876                                               END
+ 1877                                             END; .)
+ 1878      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 1879        | "LEN"                           (. isHigh := FALSE; .) )
+ 1880        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1881                                          (. IF dt = SymTab.InvalidType THEN
+ 1882                                             ELSIF SymTab.ClassOf(dt) #
+ 1883                                                   SymTab.ClArray THEN
+ 1884                                               SemError(217);
+ 1885                                               t := SymTab.InvalidType;
+ 1886                                               QbeGen.CopyOp("0", q)
+ 1887                                             ELSE
+ 1888                                               IF isHigh THEN
+ 1889                                                 IF SymTab.IsOpenArray(dt) THEN
+ 1890                                                   QbeGen.OpenHi(qd, qr)
+ 1891                                                 ELSE
+ 1892                                                   QbeGen.IntStr(
+ 1893                                                     SymTab.ArrayHi(dt), qr)
+ 1894                                                 END
+ 1895                                               ELSE
+ 1896                                                 IF SymTab.IsOpenArray(dt) THEN
+ 1897                                                   QbeGen.LoadCount(qd, qr)
+ 1898                                                 ELSE
+ 1899                                                   QbeGen.IntStr(VAL(
+ 1900                                                     INTEGER,
+ 1901                                                     SymTab.ArrayLen(dt)),
+ 1902                                                     qr)
+ 1903                                                 END
+ 1904                                               END;
+ 1905                                                t := SymTab.IntType();
+ 1906                                                QbeGen.CopyOp(qr, q)
+ 1907                                              END; .)
+ 1908      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1909                                          (. IF dt = SymTab.InvalidType THEN
+ 1910                                               t := SymTab.InvalidType;
+ 1911                                               QbeGen.CopyOp("0", q)
+ 1912                                             ELSE
+ 1913                                               QbeGen.IntStr(VAL(INTEGER,
+ 1914                                                 SymTab.ObjectSize(dt)), q);
+ 1915                                               t := SymTab.IntType()
+ 1916                                             END; .)
+ 1917      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1918                                          (. IF dt = SymTab.InvalidType THEN
+ 1919                                               t := SymTab.InvalidType;
+ 1920                                               QbeGen.CopyOp("0", q)
+ 1921                                             ELSE
+ 1922                                               IF sfx THEN
+ 1923                                                 QbeGen.CopyOp(qd, q)
+ 1924                                               ELSIF (dk = SymTab.KindVar)
+ 1925                                                  OR (dk = SymTab.KindParam) THEN
+ 1926                                                 QbeGen.AddrOf(qn, q)
+ 1927                                               ELSE SemError(230);
+ 1928                                                 QbeGen.CopyOp("0", q)
+ 1929                                               END;
+ 1930                                               t := SymTab.AddrType()
+ 1931                                             END; .)
+ 1932      | "CHR" "(" Expr<et, q> ")"
+ 1933                                          (. IF (et # SymTab.InvalidType)
+ 1934   AND NOT SymTab.IsIntFamily(et) THEN
+ 1935                                               SemError(211) END;
+ 1936                                             t := SymTab.CharType(); .)
+ 1937      | "ORD" "(" Expr<et, q> ")"
+ 1938                                          (. IF et # SymTab.InvalidType THEN
+ 1939                                               IF (SymTab.ClassOf(et) #
+ 1940                                                   SymTab.ClChar)
  1941   AND (SymTab.ClassOf(et) #
- 1942                                                     SymTab.ClEnum)
- 1943   AND NOT SymTab.IsIntFamily(et) THEN
- 1944                                                 SemError(211) END
- 1945                                             END;
- 1946                                             t := SymTab.IntType(); .)
- 1947      | "ABS" "(" Expr<et, q> ")"
- 1948                                          (. IF (et # SymTab.InvalidType)
- 1949   AND NOT SymTab.IsIntFamily(et)
- 1950   AND (SymTab.ClassOf(et) #
- 1951                                                  SymTab.ClReal) THEN
- 1952                                               SemError(211)
- 1953                                             ELSE QbeGen.AbsQ(q, qa,
- 1954                                                    SymTab.ClassOf(et) =
- 1955                                                      SymTab.ClReal)
- 1956                                             END;
- 1957                                             t := et; .)
- 1958      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
- 1959                                          (. IF NOT SymTab.Lookup(vn) THEN
- 1960                                               SemError(201);
- 1961                                               t := SymTab.InvalidType
- 1962                                             ELSE vt := SymTab.SymType(vn);
- 1963                                               IF vt = SymTab.InvalidType THEN
- 1964                                                 t := SymTab.InvalidType
- 1965                                               ELSIF et =
- 1966                                                  SymTab.InvalidType THEN
- 1967                                                 t := vt
- 1968                                               ELSE
- 1969                                                 c1 := SymTab.ClassOf(et);
- 1970                                                 c2 := SymTab.ClassOf(vt);
- 1971                                                 IF ((c1 = SymTab.ClInt)
- 1972                                                     OR (c1 =
- 1973                                                        SymTab.ClChar)
+ 1942                                                     SymTab.ClBool)
+ 1943   AND (SymTab.ClassOf(et) #
+ 1944                                                     SymTab.ClEnum)
+ 1945   AND NOT SymTab.IsIntFamily(et) THEN
+ 1946                                                 SemError(211) END
+ 1947                                             END;
+ 1948                                             t := SymTab.IntType(); .)
+ 1949      | "ABS" "(" Expr<et, q> ")"
+ 1950                                          (. IF (et # SymTab.InvalidType)
+ 1951   AND NOT SymTab.IsIntFamily(et)
+ 1952   AND (SymTab.ClassOf(et) #
+ 1953                                                  SymTab.ClReal) THEN
+ 1954                                               SemError(211)
+ 1955                                             ELSE QbeGen.AbsQ(q, qa,
+ 1956                                                    SymTab.ClassOf(et) =
+ 1957                                                      SymTab.ClReal)
+ 1958                                             END;
+ 1959                                             t := et; .)
+ 1960      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
+ 1961                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 1962                                               SemError(201);
+ 1963                                               t := SymTab.InvalidType
+ 1964                                             ELSE vt := SymTab.SymType(vn);
+ 1965                                               IF vt = SymTab.InvalidType THEN
+ 1966                                                 t := SymTab.InvalidType
+ 1967                                               ELSIF et =
+ 1968                                                  SymTab.InvalidType THEN
+ 1969                                                 t := vt
+ 1970                                               ELSE
+ 1971                                                 c1 := SymTab.ClassOf(et);
+ 1972                                                 c2 := SymTab.ClassOf(vt);
+ 1973                                                 IF ((c1 = SymTab.ClInt)
  1974                                                     OR (c1 =
- 1975                                                        SymTab.ClBool)
+ 1975                                                        SymTab.ClChar)
  1976                                                     OR (c1 =
- 1977                                                        SymTab.ClEnum))
- 1978   AND ((c2 = SymTab.ClInt)
- 1979                                                     OR (c2 =
- 1980                                                        SymTab.ClChar)
+ 1977                                                        SymTab.ClBool)
+ 1978                                                     OR (c1 =
+ 1979                                                        SymTab.ClEnum))
+ 1980   AND ((c2 = SymTab.ClInt)
  1981                                                     OR (c2 =
- 1982                                                        SymTab.ClBool)
+ 1982                                                        SymTab.ClChar)
  1983                                                     OR (c2 =
- 1984                                                        SymTab.ClEnum)) THEN
- 1985                                                   t := vt
- 1986                                                 ELSIF (c1 = SymTab.ClPtr)
- 1987   AND (c2 = SymTab.ClPtr) THEN
- 1988                                                   t := vt
- 1989                                                 ELSIF (c1 = SymTab.ClReal)
- 1990   AND (c2 = SymTab.ClReal) THEN
- 1991                                                   t := vt
- 1992                                                 ELSE SemError(230);
- 1993                                                   t := SymTab.InvalidType
- 1994                                                 END
- 1995                                               END
- 1996                                             END; .)
- 1997      | "(" Expr<et, q> ")"               (. t := et; .)
- 1998      | SetLit<st, sq>                    (. t := st;
- 1999                                             QbeGen.CopyOp(sq, q); .)
- 2000      | "NOT" Fact<t2, q2>                (. IF SymTab.BoolCheck(t2) THEN
- 2001                                               t := SymTab.BoolType()
- 2002                                             ELSE SemError(212);
- 2003                                               t := SymTab.InvalidType END;
- 2004                                             IF t # SymTab.InvalidType THEN
- 2005                                               QbeGen.NotQ(q2, q)
- 2006                                             ELSE QbeGen.CopyOp("0", q)
- 2007                                             END; .) .
- 2008    (* Set literals are SET OF [0..255] (8 words); elements validated
- 2009       0..255 statically when foldable (222 otherwise), runtime trap
- 2010       for computed elements. Ranges always lower via SetRange. *)
- 2011    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2012      = "{"                               (. t := SymTab.NewSet(
- 2013                                               SymTab.NewSubR(0, 255));
- 2014                                             QbeGen.NewSetTemp(8, q);
- 2015                                             QbeGen.SetZero(q, 8); .)
- 2016        [ SetElem<t, q> { "," SetElem<t, q> } ]
- 2017        "}" .
- 2018    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
- 2019                                               qe, q2: QbeGen.QVal;
- 2020                                               v, v2: INTEGER;
- 2021                                               lo: INTEGER;
- 2022                                               span: CARDINAL;
- 2023                                               cl, cl2: INTEGER;
- 2024                                               hasR: BOOLEAN; .)
- 2025      =                                   (. hasR := FALSE; .)
- 2026        Expr<et, qe>
- 2027        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
- 2028                                          (. lo := SymTab.SetBaseLo(st);
- 2029                                             span := SymTab.SetCount(st);
- 2030                                             IF (et = SymTab.InvalidType)
- 2031                                                OR (hasR AND (et2 =
- 2032                                                   SymTab.InvalidType)) THEN
- 2033                                             ELSE cl :=
- 2034                                                    SymTab.ClassOf(et);
- 2035                                               IF hasR THEN
- 2036                                                 cl2 :=
- 2037                                                   SymTab.ClassOf(et2)
- 2038                                               ELSE cl2 := SymTab.ClInt
- 2039                                               END;
- 2040                                               IF ((cl # SymTab.ClInt)
- 2041   AND (cl # SymTab.ClChar)
- 2042   AND (cl # SymTab.ClBool))
- 2043                                                  OR (hasR AND 
- 2044                                                     ((cl2
- 2045                                                       # SymTab.ClInt)
- 2046   AND (cl2
- 2047                                                        # SymTab.ClChar)
+ 1984                                                        SymTab.ClBool)
+ 1985                                                     OR (c2 =
+ 1986                                                        SymTab.ClEnum)) THEN
+ 1987                                                   t := vt
+ 1988                                                 ELSIF (c1 = SymTab.ClPtr)
+ 1989   AND (c2 = SymTab.ClPtr) THEN
+ 1990                                                   t := vt
+ 1991                                                 ELSIF (c1 = SymTab.ClReal)
+ 1992   AND (c2 = SymTab.ClReal) THEN
+ 1993                                                   t := vt
+ 1994                                                 ELSE SemError(230);
+ 1995                                                   t := SymTab.InvalidType
+ 1996                                                 END
+ 1997                                               END
+ 1998                                             END; .)
+ 1999      | "(" Expr<et, q> ")"               (. t := et; .)
+ 2000      | SetLit<st, sq>                    (. t := st;
+ 2001                                             QbeGen.CopyOp(sq, q); .)
+ 2002      | "NOT" Fact<t2, q2>                (. IF SymTab.BoolCheck(t2) THEN
+ 2003                                               t := SymTab.BoolType()
+ 2004                                             ELSE SemError(212);
+ 2005                                               t := SymTab.InvalidType END;
+ 2006                                             IF t # SymTab.InvalidType THEN
+ 2007                                               QbeGen.NotQ(q2, q)
+ 2008                                             ELSE QbeGen.CopyOp("0", q)
+ 2009                                             END; .) .
+ 2010    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 2011       0..255 statically when foldable (222 otherwise), runtime trap
+ 2012       for computed elements. Ranges always lower via SetRange. *)
+ 2013    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2014      = "{"                               (. t := SymTab.NewSet(
+ 2015                                               SymTab.NewSubR(0, 255));
+ 2016                                             QbeGen.NewSetTemp(8, q);
+ 2017                                             QbeGen.SetZero(q, 8); .)
+ 2018        [ SetElem<t, q> { "," SetElem<t, q> } ]
+ 2019        "}" .
+ 2020    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
+ 2021                                               qe, q2: QbeGen.QVal;
+ 2022                                               v, v2: INTEGER;
+ 2023                                               lo: INTEGER;
+ 2024                                               span: CARDINAL;
+ 2025                                               cl, cl2: INTEGER;
+ 2026                                               hasR: BOOLEAN; .)
+ 2027      =                                   (. hasR := FALSE; .)
+ 2028        Expr<et, qe>
+ 2029        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
+ 2030                                          (. lo := SymTab.SetBaseLo(st);
+ 2031                                             span := SymTab.SetCount(st);
+ 2032                                             IF (et = SymTab.InvalidType)
+ 2033                                                OR (hasR AND (et2 =
+ 2034                                                   SymTab.InvalidType)) THEN
+ 2035                                             ELSE cl :=
+ 2036                                                    SymTab.ClassOf(et);
+ 2037                                               IF hasR THEN
+ 2038                                                 cl2 :=
+ 2039                                                   SymTab.ClassOf(et2)
+ 2040                                               ELSE cl2 := SymTab.ClInt
+ 2041                                               END;
+ 2042                                               IF ((cl # SymTab.ClInt)
+ 2043   AND (cl # SymTab.ClChar)
+ 2044   AND (cl # SymTab.ClBool))
+ 2045                                                  OR (hasR AND 
+ 2046                                                     ((cl2
+ 2047                                                       # SymTab.ClInt)
  2048   AND (cl2
- 2049                                                        # SymTab.ClBool))) THEN
- 2050                                                 SemError(222)
- 2051                                               ELSIF hasR
- 2052   AND SymTab.ConstInt(qe, v)
- 2053   AND SymTab.ConstInt(q2,
- 2054                                                     v2)
- 2055   AND ((v < lo)
- 2056                                                     OR (v2 < lo)
- 2057                                                     OR (v >= lo +
- 2058                                                        VAL(INTEGER, span))
- 2059                                                     OR (v2 >= lo +
+ 2049                                                        # SymTab.ClChar)
+ 2050   AND (cl2
+ 2051                                                        # SymTab.ClBool))) THEN
+ 2052                                                 SemError(222)
+ 2053                                               ELSIF hasR
+ 2054   AND SymTab.ConstInt(qe, v)
+ 2055   AND SymTab.ConstInt(q2,
+ 2056                                                     v2)
+ 2057   AND ((v < lo)
+ 2058                                                     OR (v2 < lo)
+ 2059                                                     OR (v >= lo +
  2060                                                        VAL(INTEGER, span))
- 2061                                                     OR (v > v2)) THEN
- 2062                                                 SemError(222)
- 2063                                                ELSIF hasR THEN
- 2064                                                  QbeGen.SetRange(sq, qe, q2,
- 2065                                                    lo, span)
- 2066                                                ELSIF SymTab.ConstInt(qe,
- 2067                                                        v)
- 2068   AND ((v < lo)
- 2069                                                      OR (v >= lo +
- 2070                                                         VAL(INTEGER,
- 2071                                                           span))) THEN
- 2072                                                  SemError(222)
- 2073                                                ELSE QbeGen.SetBit(sq, qe,
- 2074                                                  lo, span)
- 2075                                               END
- 2076                                             END; .) .
- 2077    GetIdent<VAR n: SymTab.Name>
- 2078      = ident                             (. LexName(n); .) .
- 2079  
- 2080  END M2.
+ 2061                                                     OR (v2 >= lo +
+ 2062                                                        VAL(INTEGER, span))
+ 2063                                                     OR (v > v2)) THEN
+ 2064                                                 SemError(222)
+ 2065                                                ELSIF hasR THEN
+ 2066                                                  QbeGen.SetRange(sq, qe, q2,
+ 2067                                                    lo, span)
+ 2068                                                ELSIF SymTab.ConstInt(qe,
+ 2069                                                        v)
+ 2070   AND ((v < lo)
+ 2071                                                      OR (v >= lo +
+ 2072                                                         VAL(INTEGER,
+ 2073                                                           span))) THEN
+ 2074                                                  SemError(222)
+ 2075                                                ELSE QbeGen.SetBit(sq, qe,
+ 2076                                                  lo, span)
+ 2077                                               END
+ 2078                                             END; .) .
+ 2079    GetIdent<VAR n: SymTab.Name>
+ 2080      = ident                             (. LexName(n); .) .
+ 2081  
+ 2082  END M2.
 
     0 errors
 

+ 30 - 0
compiler/tests/t_nestidx.mod

@@ -0,0 +1,30 @@
+MODULE TNestIdx;
+// Nested arrays: a[i][j] and a[i, j] loads/stores, and passing a
+// nested-array element (a row) to an open-array formal. Exit 42.
+TYPE Row = ARRAY [0..3] OF INTEGER;
+TYPE Mat = ARRAY [0..2] OF Row;
+
+VAR m : Mat;
+VAR ExitCode : INTEGER;
+VAR i, j, total : INTEGER;
+
+PROCEDURE Sum(r : ARRAY OF INTEGER) : INTEGER;
+  VAR k, s : INTEGER;
+BEGIN
+  s := 0;
+  FOR k := 0 TO HIGH(r) DO s := s + r[k] END;
+  RETURN s
+END Sum;
+
+BEGIN
+  FOR i := 0 TO 2 DO
+    FOR j := 0 TO 3 DO m[i][j] := i + j END
+  END;
+  (* row sums: 6, 10, 14 -> 30 *)
+  total := Sum(m[0]) + Sum(m[1]) + Sum(m[2]);
+  (* diagonal: 0 + 2 + 4 = 6 -> 36 *)
+  total := total + m[0][0] + m[1][1] + m[2][2];
+  (* comma form: m[1,3] + m[2,0] = 4 + 2 = 6 -> 42 *)
+  total := total + m[1, 3] + m[2, 0];
+  ExitCode := total
+END TNestIdx.

+ 59 - 0
docs/summary_fix-nested-arrays.md

@@ -0,0 +1,59 @@
+# Fix — nested-array elements (double load → wrong code / signal)
+
+Tag `v3-fix-nested-arrays`. Main suite 108/108; `QbeGen` still compiles
+clean under V3; `tools/m2make` 18/18.
+
+## Symptom
+
+Two failures surfaced by `M2make` (documented in
+`tools/m2make/README.md`), which forced its portable core onto a
+"flat 1-D arrays only" subset:
+
+- passing a nested-array element (a row) to an open-array formal,
+  e.g. `Sum(m[1])`, **segfaulted**;
+- the `a[i][j]` / `HIGH(a[i])` patterns in `M2makeOS` could not be used.
+
+## Root cause
+
+`Fact`'s `Design` branch loaded array-typed designators a second time.
+`Design` already materialises the array value for array-typed suffixes:
+the `[i]` index handler and the `.field` handler both emit `ElemLoad`
+(load the sub-descriptor pointer) when the element type is an array.
+`Fact` then did `ElemLoad` again, so the row pointer was replaced by its
+first word (the element count), which was passed on as an address:
+
+```
+%t129 =l loadl %t128     ; row descriptor address (correct, from Design)
+%t130 =l loadl %t129     ; extra load: dereferences the row -> count
+call $Sum_0(l 0, l %t130)
+```
+
+## Fix
+
+`compiler/src/M2.atg` (`Fact`, `Design` branch): treat `ClArray` like
+`ClRecord` / `ClSet` / `ClClass` — an array designator's value *is* its
+address, so `CopyOp(qd, q)` instead of `ElemLoad(qd, dt, q)`.
+
+## Verification
+
+- `Sum(m[1])` went from SIGSEGV (139) to the expected value (15),
+  confirmed by reverting and re-applying the one-line change.
+- New regression test `compiler/tests/t_nestidx.mod` (exit 42) covers
+  `a[i][j]` loads **and** stores, the comma form `a[i, j]`,
+  `HIGH(row)` via `Sum`, and passing rows to an open-array formal.
+- The `M2makeOS` pattern (`argTab[i][k]`, `HIGH(argTab[i])`,
+  `CopyArg(s, argTab[argN])`) now compiles and runs.
+- `QbeGen.def/.mod` still compile clean under V3 (0 errors).
+
+## Note on the "233 on `a[i][j]` loads"
+
+A minimal `a[i][j]` load/store parsed and ran correctly even with the
+fix reverted, so no separate rejection was reproducible; the
+open-array-actual case is the one that definitely miscompiled. The
+one-line change above is the common fix for the nested-array-element
+value path.
+
+## Files
+
+`compiler/src/M2.atg`, `compiler/tests/t_nestidx.mod`,
+`compiler/run_tests.sh`.