diff options
| author | Cliff Click <cliffc@acm.org> | 2026-09-28 09:23:27 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-09-28 09:23:27 -0700 |
| commit | 8212a66ff27e56531e0b48807088f1c544d75756 (patch) | |
| tree | d1a1cdbf1ae790ddd8378714d4325a84b90bfc17 /chapter25/src/test/java/com | |
| parent | 3d226b49e1cd23b41fd9baf3917f751973c1ad11 (diff) | |
| download | Simple-8212a66ff27e56531e0b48807088f1c544d75756.tar.gz Simple-8212a66ff27e56531e0b48807088f1c544d75756.zip | |
Check un-init not-null constructor fields
Propagate BOT inputs; Arith, Load.
CallEnd inlining, the FUnPtr dies early.
Load asserts when loading against uninit not-null field.
Keep not-nill state for storage class.
Clean up Node.peep as constant.
Diffstat (limited to 'chapter25/src/test/java/com')
7 files changed, 46 insertions, 28 deletions
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 029e28b8..f41a1904 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -68,6 +68,7 @@ public class Chapter10Test { public void testNullGuardErrors() { for( String body : new String[] { "return p.x;", + "if (p == null) return p.x; return -1;", "if (!!points) return p.x; return -1;", "if (!!p) { int x = p.x; } return p.x;" } ) { diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java index 4d273aff..24552062 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter15Test.java @@ -182,7 +182,7 @@ return root; public void testNestedStructAddMemProj() { CodeGen code = new CodeGen( """ -struct _S { int a; int[] b; }; +struct _S { int a; int[] b; new _S = { int[] ary -> b=ary; }; }; return 0; """); code.parse().opto(); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java index faba6451..79aecbff 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter17Test.java @@ -268,15 +268,38 @@ A x = new A; @Test public void testVar15() { - CodeGen code = new CodeGen(""" -struct B {}; -struct A { B b; new A = { -> - if (arg) b = new B; // Constructor ends with partial init of b -}; }; -return (new A).b; -"""); - try { code.parse().opto().typeCheck(); fail(); } - catch( Exception e ) { assertEquals("'Test.A' is not fully initialized, field 'b' is only partially set in the constructor",e.getMessage()); } + for( String fields : new String[] { + "B b; new A = { -> if (arg) b = new B; };", + "B b; new A = { -> if (arg) return 0; b = new B; };", + "B b; new A = { B b -> b = new B; };", // Argument shadows field + "new A = { -> }; B b;", // Field declared later + } ) { + CodeGen code = new CodeGen("struct B {}; struct A { "+fields+" }; return 0;"); + try { code.parse(); fail(fields); } + catch( Parser.ParseException e ) { assertEquals("'Test.A' is not fully initialized, field 'b' is only partially set in the constructor",e.getMessage()); } + } + } + + @Test + public void testDefaultConstructorFields() { + for( String field : new String[] { "B b;", "B !b;" } ) { + CodeGen code = new CodeGen("struct B {}; struct A { "+field+" }; return new A;"); + try { code.parse(); fail(field); } + catch( Parser.ParseException e ) { assertEquals("'Test.A' is not fully initialized, field 'b' needs to be set in a constructor",e.getMessage()); } + } + for( String fields : new String[] { + "B b = new B;", + "B b; b = new B;", + "new A = { -> }; B b = new B;", + "B b; new A = { -> if (arg) { b = new B; return 0; } b = new B; };", + } ) { + CodeGen code = new CodeGen("struct B {}; struct A { "+fields+" }; return new A.b != null;"); + code.parse().opto().typeCheck(); + assertEquals("1",Eval2.eval(code,0)); + assertEquals("1",Eval2.eval(code,1)); + } + // No returning path means no object can escape uninitialized. + new CodeGen("struct B {}; struct A { B b; new A = { -> while (true) {} }; }; return 0;").parse(); } @Test diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java index a9f7dde7..5ea198ef 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java @@ -195,6 +195,7 @@ return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 struct String { u8[] cs; int _hashCode; + new String = { u8[] data -> cs=data; }; }; // Compare two Strings @@ -222,9 +223,9 @@ val _hashCodeString = { String self -> return hash; }; """; - testCPU(src,"x86_64_v2", "SystemV",18,null); - testCPU(src,"riscv" , "SystemV", 7,null); - testCPU(src,"arm" , "SystemV", 8,null); + testCPU(src,"x86_64_v2", "SystemV",21,null); + testCPU(src,"riscv" , "SystemV",10,null); + testCPU(src,"arm" , "SystemV",10,null); } @Test diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java index 9f37be49..4307a3b6 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -292,6 +292,7 @@ return v0; struct String { u8[] cs; int _hashCode; + new String = { u8[] data -> cs=data; }; }; // Compare two Strings @@ -319,9 +320,9 @@ val _hashCodeString = { String self -> return hash; }; """; - testCPU(src,"x86_64_v2", "SystemV",18,null); - testCPU(src,"riscv" , "SystemV", 7,null); - testCPU(src,"arm" , "SystemV", 8,null); + testCPU(src,"x86_64_v2", "SystemV",21,null); + testCPU(src,"riscv" , "SystemV",10,null); + testCPU(src,"arm" , "SystemV",10,null); } @Test public void testStringExport() throws IOException { @@ -330,6 +331,7 @@ val _hashCodeString = { String self -> struct String { u8[] cs; int _hashCode; + new String = { u8[] data -> cs=data; }; }; // Compare two Strings @@ -357,7 +359,7 @@ val _hashCodeString = { String self -> return hash; }; """; - TestC.runC(src, "stringHash", "",18); + TestC.runC(src, "stringHash", "",21); } @Test public void testLoop2() { diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java index 0ac55a9e..41225097 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java @@ -29,16 +29,7 @@ public class Chapter25Test { @Ignore @Test public void testJig() { - String src =" while(1?!0:arg++) {"; - String src2 = """ -int v0=0^0; - while(1) { - arg=v0++&0; - int v2=0; - if(v0) - if(v0) v2=0; - } - """; + String src = "struct I { int x; }; struct F { I p; }; return new F.p.x;"; CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck); assertEquals("2",Eval2.eval(code,0)); } diff --git a/chapter25/src/test/java/com/seaofnodes/simple/FuzzerWrap.java b/chapter25/src/test/java/com/seaofnodes/simple/FuzzerWrap.java index 66bc4717..68bbe918 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/FuzzerWrap.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/FuzzerWrap.java @@ -18,7 +18,7 @@ public class FuzzerWrap { -148471672577312953L, // bulk mem -5037182906211190034L, // dead Guard control -6359653295501938199L, // monotonicity, escape is dead - 6506797708065910879L, // missing ModeNode._mode is optimistic + 6506797708065910879L, // required field without a user constructor 650692970082394944L, // recursive bulk mem split 8335100609598232836L, // ternary result killed by region cleanup 2520958273643234516L, // nested guard merge |
