mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 03:39:40 +01:00 
			
		
		
		
	* fixed handling function results of inherited obj-c calls
(test program by Gorazd Krosl) git-svn-id: branches/objc@13720 -
This commit is contained in:
		
							parent
							
								
									14797e0ddb
								
							
						
					
					
						commit
						fb2a523976
					
				
							
								
								
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							@ -8348,6 +8348,7 @@ tests/test/opt/twpo5.pp svneol=native#text/plain
 | 
			
		||||
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/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
 | 
			
		||||
 | 
			
		||||
@ -175,8 +175,9 @@ constructor tobjcmessagesendnode.create(forcall: tnode);
 | 
			
		||||
  begin
 | 
			
		||||
    if (forcall.nodetype<>calln) then
 | 
			
		||||
      internalerror(2009032502);
 | 
			
		||||
    { typecheck pass (and pass1) must already have run on the call node,
 | 
			
		||||
      because pass1 of the callnode creates this node
 | 
			
		||||
    { typecheck pass must already have run on the call node,
 | 
			
		||||
      because pass1 of the callnode creates this node right
 | 
			
		||||
      at the beginning
 | 
			
		||||
    }
 | 
			
		||||
    inherited create(objcmessagesendn,forcall);
 | 
			
		||||
  end;
 | 
			
		||||
@ -199,7 +200,8 @@ function tobjcmessagesendnode.pass_1: tnode;
 | 
			
		||||
    block,
 | 
			
		||||
    selftree  : tnode;
 | 
			
		||||
    statements: tstatementnode;
 | 
			
		||||
    temp: ttempcreatenode;
 | 
			
		||||
    temp,
 | 
			
		||||
    tempresult: ttempcreatenode;
 | 
			
		||||
    objcsupertype: tdef;
 | 
			
		||||
    field: tfieldvarsym;
 | 
			
		||||
    selfpara,
 | 
			
		||||
@ -209,7 +211,7 @@ function tobjcmessagesendnode.pass_1: tnode;
 | 
			
		||||
    prerespara,
 | 
			
		||||
    prevpara: tcallparanode;
 | 
			
		||||
  begin
 | 
			
		||||
    { pass1 of left has already run, see constructor }
 | 
			
		||||
    { typecheckpass of left has already run, see constructor }
 | 
			
		||||
 | 
			
		||||
    { default behaviour: call objc_msgSend and friends;
 | 
			
		||||
      ppc64 and x86_64 for Mac OS X have to override this as they
 | 
			
		||||
@ -220,6 +222,7 @@ function tobjcmessagesendnode.pass_1: tnode;
 | 
			
		||||
      result type, and on whether or not it's an inherited call.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tempresult:=nil;
 | 
			
		||||
    newparas:=tcallparanode(tcallnode(left).left);
 | 
			
		||||
    { Find the self and msgsel parameters.  }
 | 
			
		||||
    para:=newparas;
 | 
			
		||||
@ -367,6 +370,11 @@ function tobjcmessagesendnode.pass_1: tnode;
 | 
			
		||||
    tcallnode(left).methodpointer:=nil;
 | 
			
		||||
    { and now the call to the Objective-C rtl }
 | 
			
		||||
    result:=ccallnode.createinternresfromunit('OBJC1',msgsendname,newparas,left.resultdef);
 | 
			
		||||
    { record whether or not the function result is used (remains
 | 
			
		||||
      the same for the new call).
 | 
			
		||||
    }
 | 
			
		||||
    if not(cnf_return_value_used in tcallnode(left).callnodeflags) then
 | 
			
		||||
      exclude(tcallnode(result).callnodeflags,cnf_return_value_used);
 | 
			
		||||
    { in case an explicit function result was specified, keep it }
 | 
			
		||||
    tcallnode(result).funcretnode:=tcallnode(left).funcretnode;
 | 
			
		||||
    tcallnode(left).funcretnode:=nil;
 | 
			
		||||
@ -376,14 +384,34 @@ function tobjcmessagesendnode.pass_1: tnode;
 | 
			
		||||
 | 
			
		||||
    if (cnf_inherited in tcallnode(left).callnodeflags) then
 | 
			
		||||
      begin
 | 
			
		||||
        { free the objc_super temp after the call. We cannout use
 | 
			
		||||
        block:=internalstatements(statements);
 | 
			
		||||
        { temp for the result of the inherited call }
 | 
			
		||||
        if not is_void(left.resultdef) and
 | 
			
		||||
           (cnf_return_value_used in tcallnode(left).callnodeflags) then
 | 
			
		||||
           begin
 | 
			
		||||
             tempresult:=ctempcreatenode.create(left.resultdef,left.resultdef.size,tt_persistent,true);
 | 
			
		||||
             addstatement(statements,tempresult);
 | 
			
		||||
           end;
 | 
			
		||||
 | 
			
		||||
        { make sure we return the result, if any }
 | 
			
		||||
        if not assigned(tempresult) then
 | 
			
		||||
          addstatement(statements,result)
 | 
			
		||||
        else
 | 
			
		||||
          addstatement(statements,
 | 
			
		||||
            cassignmentnode.create(ctemprefnode.create(tempresult),result));
 | 
			
		||||
        { free the objc_super temp after the call. We cannot use
 | 
			
		||||
          ctempdeletenode.create_normal_temp before the call, because then
 | 
			
		||||
          the temp will be released while evaluating the parameters, and thus
 | 
			
		||||
          may be reused while evaluating another parameter
 | 
			
		||||
        }
 | 
			
		||||
        block:=internalstatements(statements);
 | 
			
		||||
        addstatement(statements,result);
 | 
			
		||||
        addstatement(statements,ctempdeletenode.create(temp));
 | 
			
		||||
        if assigned(tempresult) then
 | 
			
		||||
          begin
 | 
			
		||||
            { mark the result temp as "free after next use" and return it }
 | 
			
		||||
            addstatement(statements,
 | 
			
		||||
              ctempdeletenode.create_normal_temp(tempresult));
 | 
			
		||||
            addstatement(statements,ctemprefnode.create(tempresult));
 | 
			
		||||
          end;
 | 
			
		||||
        typecheckpass(block);
 | 
			
		||||
        result:=block;
 | 
			
		||||
     end;
 | 
			
		||||
 | 
			
		||||
@ -1460,7 +1460,7 @@ ifndef LOG
 | 
			
		||||
export LOG:=$(TEST_OUTPUTDIR)/log
 | 
			
		||||
endif
 | 
			
		||||
TESTSUBDIRS=cg cg/variants cg/cdecl opt units/system units/dos units/crt units/objects units/strings units/sysutils units/math units/sharemem
 | 
			
		||||
TESTPACKAGESUBDIRS=cg packages/win-base packages/webtbs packages/hash packages/fcl-registry packages/fcl-process packages/zlib packages/fcl-db packages/fcl-base packages/fcl-xml
 | 
			
		||||
TESTPACKAGESUBDIRS=cg packages/win-base packages/webtbs packages/hash packages/fcl-registry packages/fcl-process packages/zlib packages/fcl-db packages/fcl-base packages/fcl-xml packages/cocoaint
 | 
			
		||||
ifdef QUICKTEST
 | 
			
		||||
export QUICKTEST
 | 
			
		||||
else
 | 
			
		||||
 | 
			
		||||
@ -121,7 +121,7 @@ endif
 | 
			
		||||
 | 
			
		||||
# Subdirs available in the test subdir
 | 
			
		||||
TESTSUBDIRS=cg cg/variants cg/cdecl opt units/system units/dos units/crt units/objects units/strings units/sysutils units/math units/sharemem
 | 
			
		||||
TESTPACKAGESUBDIRS=cg packages/win-base packages/webtbs packages/hash packages/fcl-registry packages/fcl-process packages/zlib packages/fcl-db packages/fcl-base packages/fcl-xml
 | 
			
		||||
TESTPACKAGESUBDIRS=cg packages/win-base packages/webtbs packages/hash packages/fcl-registry packages/fcl-process packages/zlib packages/fcl-db packages/fcl-base packages/fcl-xml packages/cocoaint
 | 
			
		||||
 | 
			
		||||
ifdef QUICKTEST
 | 
			
		||||
export QUICKTEST
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										100
									
								
								tests/test/packages/cocoaint/tobjcnh1.pp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								tests/test/packages/cocoaint/tobjcnh1.pp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
{ %target=darwin }
 | 
			
		||||
{ %cpu=powerpc,i386 }
 | 
			
		||||
 | 
			
		||||
{$mode objfpc}{$H+}
 | 
			
		||||
{$modeswitch objectivec1}
 | 
			
		||||
program Start;
 | 
			
		||||
uses
 | 
			
		||||
ctypes,
 | 
			
		||||
CFBase, CFString,
 | 
			
		||||
CocoaAll;
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
MyObject = objcclass(NSObject)
 | 
			
		||||
  function initMyObject : id; message 'initMyObject';
 | 
			
		||||
  function testFunction : cint; message 'testFunction';
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
MySubobject = objcclass(MyObject)
 | 
			
		||||
  function initMyObject : id; message 'initMyObject'; override;
 | 
			
		||||
  function testFunction : cint; message 'testFunction'; override;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure NSLog(fmt : CFStringRef); cdecl; varargs; external name 'NSLog';
 | 
			
		||||
 | 
			
		||||
function MyObject.initMyObject : id;
 | 
			
		||||
  var
 | 
			
		||||
    temp: id;
 | 
			
		||||
  begin
 | 
			
		||||
    Result:=nil;
 | 
			
		||||
    NSLog(CFSTR('MyObject.initMyObject entry, self = %p'), self);
 | 
			
		||||
    Result := inherited init;
 | 
			
		||||
    { default NSObject.init does not return anything different,
 | 
			
		||||
      so should be safe in test program }
 | 
			
		||||
    if result<>self then
 | 
			
		||||
      halt(1);
 | 
			
		||||
    NSLog(CFSTR('Result assigned by inherited init = %p'), Result);
 | 
			
		||||
    NSLog(CFSTR('self after inherited init = %p'), self);
 | 
			
		||||
    Result := self;
 | 
			
		||||
    NSLog(CFSTR('returning result = %p'), Result)
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
function MyObject.testFunction : cint;
 | 
			
		||||
  begin
 | 
			
		||||
    Result := 1;
 | 
			
		||||
    NSLog(CFSTR('MyObject.testFunction returning %d'), Result)
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
function MySubobject.initMyObject : id;
 | 
			
		||||
  begin
 | 
			
		||||
    Result:=nil;
 | 
			
		||||
    NSLog(CFSTR('MySubobject.initMyObject entry, self = %p'), self);
 | 
			
		||||
    Result := inherited initMyObject;
 | 
			
		||||
    if (result<>self) then
 | 
			
		||||
      halt(2);
 | 
			
		||||
    NSLog(CFSTR('Result assigned by inherited initMyObject = %p'), Result);
 | 
			
		||||
    NSLog(CFSTR('self after inherited init = %p'), self);
 | 
			
		||||
    Result := self;
 | 
			
		||||
    NSLog(CFSTR('returning result = %p'), Result)
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
function MySubobject.testFunction : cint;
 | 
			
		||||
  begin
 | 
			
		||||
    Result:=-1;
 | 
			
		||||
    writeln('MySubobject.testFunction calling inherited...');
 | 
			
		||||
    Result := inherited testFunction;
 | 
			
		||||
    if (result<>1) then
 | 
			
		||||
      halt(3);
 | 
			
		||||
    NSLog(CFSTR('Return from inherited = %d'), Result);
 | 
			
		||||
    Result := 2;
 | 
			
		||||
    NSLog(CFSTR('MySubobject.testFunction returning %d'), Result)
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
procedure MyTest;
 | 
			
		||||
  var
 | 
			
		||||
    ap: NSAutoreleasePool;
 | 
			
		||||
    o: MyObject;
 | 
			
		||||
    oo: MySubobject;
 | 
			
		||||
    n: cint;
 | 
			
		||||
  begin
 | 
			
		||||
    ap := NSAutoreleasePool.new;
 | 
			
		||||
    writeln('========== Initializing MyObject and MySubobject ==========');
 | 
			
		||||
    o := MyObject(MyObject.alloc).initMyObject;
 | 
			
		||||
    writeln;
 | 
			
		||||
    oo := MySubobject(MySubobject.alloc).initMyObject;
 | 
			
		||||
    writeln; writeln;
 | 
			
		||||
    writeln('========== Testing testFunction ==========');
 | 
			
		||||
    n := o.testFunction;
 | 
			
		||||
    writeln('MyObject.testFunction returned ', n);
 | 
			
		||||
    writeln;
 | 
			
		||||
    n := oo.testFunction;
 | 
			
		||||
    writeln('MySubobject.testFunction returned ', n);
 | 
			
		||||
    o.release;
 | 
			
		||||
    oo.release;
 | 
			
		||||
    ap.drain
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
  MyTest;
 | 
			
		||||
end.
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user