Browse Source

+ recurse into multiple subscription nodes when calculating contant @... expressions, resolves #39665

florian 3 years ago
parent
commit
62f21ae60d
2 changed files with 76 additions and 12 deletions
  1. 24 12
      compiler/nmem.pas
  2. 52 0
      tests/webtbs/tw39665.pp

+ 24 - 12
compiler/nmem.pas

@@ -654,23 +654,35 @@ implementation
     function taddrnode.simplify(forinline : boolean) : tnode;
     function taddrnode.simplify(forinline : boolean) : tnode;
       var
       var
         hsym : tfieldvarsym;
         hsym : tfieldvarsym;
+        hp : tnode;
+        fieldoffset : asizeint;
       begin
       begin
         result:=nil;
         result:=nil;
-        if ((left.nodetype=subscriptn) and
-          (tsubscriptnode(left).left.nodetype=derefn) and
-          (tsubscriptnode(left).left.resultdef.typ=recorddef) and
-          (tderefnode(tsubscriptnode(left).left).left.nodetype=niln)) or
-          ((left.nodetype=subscriptn) and
-          (tsubscriptnode(left).left.nodetype=typeconvn) and
-          (tsubscriptnode(left).left.resultdef.typ=recorddef) and
-          (ttypeconvnode(tsubscriptnode(left).left).left.nodetype=derefn) and
-          (tderefnode(ttypeconvnode(tsubscriptnode(left).left).left).left.nodetype=niln)) then
+        if left.nodetype<>subscriptn then
+          exit;
+        hp:=left;
+        fieldoffset:=0;
+        while hp.nodetype=subscriptn do
+          begin
+            hsym:=tsubscriptnode(hp).vs;
+            if tabstractrecordsymtable(hsym.owner).is_packed then
+              inc(fieldoffset,hsym.fieldoffset div 8)
+            else
+              inc(fieldoffset,hsym.fieldoffset);
+            hp:=tsubscriptnode(hp).left;
+          end;
+        if ((hp.nodetype=derefn) and
+          (hp.resultdef.typ=recorddef) and
+          (tderefnode(hp).left.nodetype=niln)) or
+          ((hp.nodetype=typeconvn) and
+          (hp.resultdef.typ=recorddef) and
+          (ttypeconvnode(hp).left.nodetype=derefn) and
+          (tderefnode(ttypeconvnode(hp).left).left.nodetype=niln)) then
           begin
           begin
-            hsym:=tsubscriptnode(left).vs;
             if tabstractrecordsymtable(hsym.owner).is_packed then
             if tabstractrecordsymtable(hsym.owner).is_packed then
-              result:=cpointerconstnode.create(hsym.fieldoffset div 8,resultdef)
+              result:=cpointerconstnode.create(fieldoffset,resultdef)
             else
             else
-              result:=cpointerconstnode.create(hsym.fieldoffset,resultdef);
+              result:=cpointerconstnode.create(fieldoffset,resultdef);
           end;
           end;
       end;
       end;
 
 

+ 52 - 0
tests/webtbs/tw39665.pp

@@ -0,0 +1,52 @@
+{$mode objfpc}
+type
+	PBContainer = ^BContainer;
+	BContainer = record
+		b: int32;
+	end;
+
+	PMyObj = ^MyObj;
+	MyObj = record
+		dummy: int32;
+		a: int32;
+		bCtr: BContainer;
+	end;
+
+const
+	AOfs = PtrUint(@PMyObj(nil)^.a);
+	BOfs = PtrUint(@PMyObj(nil)^.bCtr.b); // does not compile
+	BOfs2 = PtrUint(@PMyObj(nil)^.bCtr) + PtrUint(@PBContainer(nil)^.b); // ugly workaround
+
+	function MyObjFromA_SubOffsetOf(aPtr: PInt32): PMyObj;
+	begin
+		result := pointer(aPtr) - PtrUint(@PMyObj(nil)^.a);
+	end;
+
+	function MyObjFromA_SubConst(aPtr: PInt32): PMyObj;
+	begin
+		result := pointer(aPtr) - AOfs;
+	end;
+
+	function MyObjFromB_SubOffsetOf(bPtr: PInt32): PMyObj;
+	begin
+		result := pointer(bPtr) - PtrUint(@PMyObj(nil)^.bCtr.b);
+	end;
+
+	function MyObjFromB_SubConst(bPtr: PInt32): PMyObj;
+	begin
+		result := pointer(bPtr) - BOfs;
+	end;
+
+var
+	mo: MyObj;
+begin
+	writeln('''a'' offset in ''MyObj'': ', AOfs);
+	writeln('''b'' offset in ''MyObj'': ', BOfs);
+    if BOfs<>BOfs2 then
+      halt(1);
+	writeln('@mo: ', HexStr(@mo));
+	writeln('@mo recovered from @mo.a by subtracting "offsetof": ', HexStr(MyObjFromA_SubOffsetOf(@mo.a)));
+	writeln('@mo recovered from @mo.a by subtracting constant:   ', HexStr(MyObjFromA_SubConst(@mo.a)));
+	writeln('@mo recovered from @mo.b by subtracting "offsetof": ', HexStr(MyObjFromB_SubOffsetOf(@mo.bCtr.b)));
+	writeln('@mo recovered from @mo.b by subtracting constant:   ', HexStr(MyObjFromB_SubConst(@mo.bCtr.b)));
+end.