Răsfoiți Sursa

* fixed passing var/out parameters to obj-c methods (test by Gorazd Krosl)

git-svn-id: branches/objc@13752 -
Jonas Maebe 16 ani în urmă
părinte
comite
5fa268db01
3 a modificat fișierele cu 85 adăugiri și 2 ștergeri
  1. 1 0
      .gitattributes
  2. 9 2
      compiler/nobjc.pas
  3. 75 0
      tests/test/packages/cocoaint/tvarpara.pp

+ 1 - 0
.gitattributes

@@ -8349,6 +8349,7 @@ tests/test/opt/twpo6.pp svneol=native#text/plain
 tests/test/opt/twpo7.pp svneol=native#text/plain
 tests/test/opt/uwpo2.pp svneol=native#text/plain
 tests/test/packages/cocoaint/tobjcnh1.pp svneol=native#text/plain
+tests/test/packages/cocoaint/tvarpara.pp svneol=native#text/plain
 tests/test/packages/fcl-base/tascii85.pp svneol=native#text/plain
 tests/test/packages/fcl-base/tgettext1.pp svneol=native#text/plain
 tests/test/packages/fcl-db/assertions.pas svneol=native#text/plain

+ 9 - 2
compiler/nobjc.pas

@@ -227,7 +227,9 @@ function tobjcmessagesendnode.pass_1: tnode;
 
     tempresult:=nil;
     newparas:=tcallparanode(tcallnode(left).left);
-    { Find the self and msgsel parameters.  }
+    { Find the self and msgsel parameters, and if we have var/out parameters
+      that normally aren't passed by reference in C, add addrnodes
+    }
     para:=newparas;
     selfpara:=nil;
     msgselpara:=nil;
@@ -243,7 +245,12 @@ function tobjcmessagesendnode.pass_1: tnode;
           begin
             prerespara:=prevpara;
             respara:=para;
-          end;
+          end
+        { All parameters will be passed as varargs to objc_msg*, so make
+          sure that in case of var/out parameters, the address is passed. }
+        else if (para.parasym.varspez in [vs_var,vs_out]) and
+                not paramanager.push_addr_param(vs_value,para.parasym.vardef,pocall_cdecl) then
+          para.left:=caddrnode.create(para.left);
         prevpara:=para;
         para:=tcallparanode(para.right);
       end;

+ 75 - 0
tests/test/packages/cocoaint/tvarpara.pp

@@ -0,0 +1,75 @@
+{ %target=darwin }
+{ %cpu=powerpc,i386 }
+
+{$mode objfpc}{$H+}
+{$modeswitch objectivec1}
+program Start;
+uses
+  ctypes,
+  CocoaAll;
+
+type
+  unichar=word;
+  punichar = ^unichar;
+  MyObject = objcclass(NSObject)
+    procedure receiveByVar_length(var chars : unichar; length : culong); message 'receiveByVar:length:';
+    procedure receiveByPtr_length(chars : punichar; length : culong); message 'receiveByPtr:length:';
+  end;
+
+var
+  c: array[0..1] of unichar;
+
+procedure MyObject.receiveByVar_length(var chars : unichar; length : culong);
+  begin
+    Writeln('MyObject.receiveByVar_length');
+    writeln('address of `chars`: 0x', HexStr(Pointer(@chars)));
+    Writeln;
+    if @chars<>@c[0] then
+      halt(1);
+  end;
+
+procedure MyObject.receiveByPtr_length(chars : punichar; length : culong);
+  begin
+    Writeln('MyObject.receiveByPtr_length');
+    writeln('address of `chars`: 0x', HexStr(Pointer(chars)));
+    Writeln;
+    if chars<>@c[0] then
+      halt(2);
+  end;
+
+procedure passByVar(var chars : unichar);
+  begin
+    Writeln('passByVar');
+    writeln('address of `chars`: 0x', HexStr(Pointer(@chars)));
+    Writeln;
+    if @chars<>@c[0] then
+      halt(3);
+  end;
+
+procedure passByPtr(chars : punichar);
+  begin
+    Writeln('passByPtr');
+    writeln('address of `chars`: 0x', HexStr(Pointer(chars)));
+    Writeln;
+    if chars<>@c[0] then
+      halt(1);
+  end;
+
+procedure MyVarTest;
+  var
+    o: MyObject;
+  begin
+    o := MyObject(MyObject.alloc).init;
+    o.receiveByVar_length(c[0], 1);
+    o.receiveByPtr_length(@c[0], 1);
+    passByVar(c[0]);
+    passByPtr(@c[0]);
+    o.release
+  end;
+
+
+begin
+  c[0]:=unichar(widechar('c'));
+  c[1]:=unichar(widechar(#0));
+  MyVarTest;
+end.