mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-12 11:58:20 +02:00

change, resulting in slightly different DWARF debug information (mantis #13508) The cause was saving a node pointer in a local variable, processing it further, and later on checking whether it changed by comparing the stored and the current instance pointer. The problem was that the node could have been freed and reallocated at the same address (but with different contents), so this check sometimes resulted in (hard to reproduce) false negatives. git-svn-id: trunk@13580 -
254 lines
7.9 KiB
ObjectPascal
254 lines
7.9 KiB
ObjectPascal
{
|
|
Copyright (c) 1998-2002 by Florian Klaempfl
|
|
|
|
This unit handles the pass_typecheck and node conversion pass
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
****************************************************************************
|
|
}
|
|
unit pass_1;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
node;
|
|
|
|
procedure typecheckpass(var p : tnode);
|
|
function do_typecheckpass(var p : tnode) : boolean;
|
|
function do_typecheckpass_changed(var p : tnode; out nodechanged: boolean) : boolean;
|
|
|
|
procedure firstpass(var p : tnode);
|
|
function do_firstpass(var p : tnode) : boolean;
|
|
{$ifdef state_tracking}
|
|
procedure do_track_state_pass(p:Tnode);
|
|
{$endif}
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
globtype,comphook,systems,cclasses,
|
|
cutils,globals,
|
|
procinfo,
|
|
cgbase,symdef
|
|
{$ifdef extdebug}
|
|
,verbose,htypechk
|
|
{$endif extdebug}
|
|
{$ifdef state_tracking}
|
|
,nstate
|
|
{$endif}
|
|
;
|
|
|
|
{*****************************************************************************
|
|
Global procedures
|
|
*****************************************************************************}
|
|
|
|
procedure typecheckpass_internal(var p : tnode; out node_changed: boolean);
|
|
var
|
|
oldcodegenerror : boolean;
|
|
oldlocalswitches : tlocalswitches;
|
|
oldverbosity : longint;
|
|
oldpos : tfileposinfo;
|
|
hp : tnode;
|
|
begin
|
|
node_changed:=false;
|
|
if (p.resultdef=nil) then
|
|
begin
|
|
oldcodegenerror:=codegenerror;
|
|
oldpos:=current_filepos;
|
|
oldlocalswitches:=current_settings.localswitches;
|
|
oldverbosity:=status.verbosity;
|
|
codegenerror:=false;
|
|
current_filepos:=p.fileinfo;
|
|
current_settings.localswitches:=p.localswitches;
|
|
status.verbosity:=p.verbosity;
|
|
hp:=p.pass_typecheck;
|
|
{ should the node be replaced? }
|
|
if assigned(hp) then
|
|
begin
|
|
node_changed:=true;
|
|
p.free;
|
|
{ run typecheckpass }
|
|
typecheckpass(hp);
|
|
{ switch to new node }
|
|
p:=hp;
|
|
end;
|
|
current_settings.localswitches:=oldlocalswitches;
|
|
current_filepos:=oldpos;
|
|
status.verbosity:=oldverbosity;
|
|
if codegenerror then
|
|
begin
|
|
include(p.flags,nf_error);
|
|
{ default to errortype if no type is set yet }
|
|
if p.resultdef=nil then
|
|
p.resultdef:=generrordef;
|
|
end;
|
|
codegenerror:=codegenerror or oldcodegenerror;
|
|
end
|
|
else
|
|
begin
|
|
{ update the codegenerror boolean with the previous result of this node }
|
|
if (nf_error in p.flags) then
|
|
codegenerror:=true;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure typecheckpass(var p : tnode);
|
|
var
|
|
node_changed: boolean;
|
|
begin
|
|
typecheckpass_internal(p,node_changed);
|
|
end;
|
|
|
|
|
|
function do_typecheckpass_changed(var p : tnode; out nodechanged: boolean) : boolean;
|
|
begin
|
|
codegenerror:=false;
|
|
typecheckpass_internal(p,nodechanged);
|
|
do_typecheckpass_changed:=codegenerror;
|
|
end;
|
|
|
|
|
|
function do_typecheckpass(var p : tnode) : boolean;
|
|
var
|
|
nodechanged: boolean;
|
|
begin
|
|
result:=do_typecheckpass_changed(p,nodechanged);
|
|
end;
|
|
|
|
|
|
procedure firstpass(var p : tnode);
|
|
var
|
|
oldcodegenerror : boolean;
|
|
oldlocalswitches : tlocalswitches;
|
|
oldpos : tfileposinfo;
|
|
oldverbosity: longint;
|
|
hp : tnode;
|
|
begin
|
|
if (nf_pass1_done in p.flags) then
|
|
exit;
|
|
if not(nf_error in p.flags) then
|
|
begin
|
|
oldcodegenerror:=codegenerror;
|
|
oldpos:=current_filepos;
|
|
oldlocalswitches:=current_settings.localswitches;
|
|
oldverbosity:=status.verbosity;
|
|
codegenerror:=false;
|
|
current_filepos:=p.fileinfo;
|
|
current_settings.localswitches:=p.localswitches;
|
|
status.verbosity:=p.verbosity;
|
|
{ checks make always a call }
|
|
if ([cs_check_range,cs_check_overflow,cs_check_stack] * current_settings.localswitches <> []) then
|
|
include(current_procinfo.flags,pi_do_call);
|
|
{ determine the resultdef if not done }
|
|
if (p.resultdef=nil) then
|
|
begin
|
|
hp:=p.pass_typecheck;
|
|
{ should the node be replaced? }
|
|
if assigned(hp) then
|
|
begin
|
|
p.free;
|
|
{ run typecheckpass }
|
|
typecheckpass(hp);
|
|
{ switch to new node }
|
|
p:=hp;
|
|
end;
|
|
if codegenerror then
|
|
begin
|
|
include(p.flags,nf_error);
|
|
{ default to errortype if no type is set yet }
|
|
if p.resultdef=nil then
|
|
p.resultdef:=generrordef;
|
|
end;
|
|
codegenerror:=codegenerror or oldcodegenerror;
|
|
end;
|
|
if not(nf_error in p.flags) then
|
|
begin
|
|
{ first pass }
|
|
hp:=p.pass_1;
|
|
{ should the node be replaced? }
|
|
if assigned(hp) then
|
|
begin
|
|
p.free;
|
|
{ run firstpass }
|
|
firstpass(hp);
|
|
{ switch to new node }
|
|
p:=hp;
|
|
end
|
|
else
|
|
begin
|
|
{ inlining happens in pass_1 and can cause new }
|
|
{ simplify opportunities }
|
|
hp:=p.simplify;
|
|
if assigned(hp) then
|
|
begin
|
|
p.free;
|
|
firstpass(hp);
|
|
p:=hp;
|
|
end;
|
|
end;
|
|
if codegenerror then
|
|
include(p.flags,nf_error)
|
|
else
|
|
begin
|
|
{$ifdef EXTDEBUG}
|
|
if (p.expectloc=LOC_INVALID) then
|
|
Comment(V_Warning,'Expectloc is not set in firstpass: '+nodetype2str[p.nodetype]);
|
|
{$endif EXTDEBUG}
|
|
end;
|
|
end;
|
|
include(p.flags,nf_pass1_done);
|
|
codegenerror:=codegenerror or oldcodegenerror;
|
|
current_settings.localswitches:=oldlocalswitches;
|
|
current_filepos:=oldpos;
|
|
status.verbosity:=oldverbosity;
|
|
end
|
|
else
|
|
codegenerror:=true;
|
|
end;
|
|
|
|
|
|
function do_firstpass(var p : tnode) : boolean;
|
|
begin
|
|
codegenerror:=false;
|
|
firstpass(p);
|
|
{$ifdef state_tracking}
|
|
writeln('TRACKSTART');
|
|
writeln('before');
|
|
writenode(p);
|
|
do_track_state_pass(p);
|
|
writeln('after');
|
|
writenode(p);
|
|
writeln('TRACKDONE');
|
|
{$endif}
|
|
do_firstpass:=codegenerror;
|
|
end;
|
|
|
|
{$ifdef state_tracking}
|
|
procedure do_track_state_pass(p:Tnode);
|
|
|
|
begin
|
|
aktstate:=Tstate_storage.create;
|
|
p.track_state_pass(true);
|
|
aktstate.destroy;
|
|
end;
|
|
{$endif}
|
|
|
|
end.
|