mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-18 20:49:19 +02:00
* put the call to afterconstructor inside the implicit try/catch block
block of the constructor, so that exceptions thrown there also properly abort construction (mantis #16311) git-svn-id: trunk@15156 -
This commit is contained in:
parent
4a934bdb33
commit
f2e1819bae
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -10350,6 +10350,7 @@ tests/webtbs/tw16188.pp svneol=native#text/plain
|
|||||||
tests/webtbs/tw1622.pp svneol=native#text/plain
|
tests/webtbs/tw1622.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw16222.pp svneol=native#text/pascal
|
tests/webtbs/tw16222.pp svneol=native#text/pascal
|
||||||
tests/webtbs/tw1623.pp svneol=native#text/plain
|
tests/webtbs/tw1623.pp svneol=native#text/plain
|
||||||
|
tests/webtbs/tw16311.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw1634.pp svneol=native#text/plain
|
tests/webtbs/tw1634.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw1658.pp svneol=native#text/plain
|
tests/webtbs/tw1658.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw1677.pp svneol=native#text/plain
|
tests/webtbs/tw1677.pp svneol=native#text/plain
|
||||||
|
@ -388,30 +388,6 @@ implementation
|
|||||||
{ has been called, so it may no longer be valid (JM) }
|
{ has been called, so it may no longer be valid (JM) }
|
||||||
oldlocalswitches:=current_settings.localswitches;
|
oldlocalswitches:=current_settings.localswitches;
|
||||||
current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
|
current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
|
||||||
{ maybe call AfterConstruction for classes }
|
|
||||||
if (current_procinfo.procdef.proctypeoption=potype_constructor) and
|
|
||||||
is_class(current_objectdef) then
|
|
||||||
begin
|
|
||||||
srsym:=search_class_member(current_objectdef,'AFTERCONSTRUCTION');
|
|
||||||
if assigned(srsym) and
|
|
||||||
(srsym.typ=procsym) then
|
|
||||||
begin
|
|
||||||
{ Self can be nil when fail is called }
|
|
||||||
{ if self<>nil and vmt<>nil then afterconstruction }
|
|
||||||
addstatement(newstatement,cifnode.create(
|
|
||||||
caddnode.create(andn,
|
|
||||||
caddnode.create(unequaln,
|
|
||||||
load_self_pointer_node,
|
|
||||||
cnilnode.create),
|
|
||||||
caddnode.create(unequaln,
|
|
||||||
load_vmt_pointer_node,
|
|
||||||
cnilnode.create)),
|
|
||||||
ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
|
|
||||||
nil));
|
|
||||||
end
|
|
||||||
else
|
|
||||||
internalerror(200305106);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ a destructor needs a help procedure }
|
{ a destructor needs a help procedure }
|
||||||
if (current_procinfo.procdef.proctypeoption=potype_destructor) then
|
if (current_procinfo.procdef.proctypeoption=potype_destructor) then
|
||||||
@ -574,6 +550,47 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure maybe_add_afterconstruction(var tocode: tnode);
|
||||||
|
var
|
||||||
|
oldlocalswitches: tlocalswitches;
|
||||||
|
srsym: tsym;
|
||||||
|
newblock: tblocknode;
|
||||||
|
newstatement: tstatementnode;
|
||||||
|
begin
|
||||||
|
{ maybe call AfterConstruction for classes }
|
||||||
|
if (current_procinfo.procdef.proctypeoption=potype_constructor) and
|
||||||
|
is_class(current_objectdef) then
|
||||||
|
begin
|
||||||
|
srsym:=search_class_member(current_objectdef,'AFTERCONSTRUCTION');
|
||||||
|
if assigned(srsym) and
|
||||||
|
(srsym.typ=procsym) then
|
||||||
|
begin
|
||||||
|
{ Don't test self and the vmt here. See }
|
||||||
|
{ generate_bodyexit_block why (JM) }
|
||||||
|
oldlocalswitches:=current_settings.localswitches;
|
||||||
|
current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
|
||||||
|
newblock:=internalstatements(newstatement);
|
||||||
|
addstatement(newstatement,tocode);
|
||||||
|
{ Self can be nil when fail is called }
|
||||||
|
{ if self<>nil and vmt<>nil then afterconstruction }
|
||||||
|
addstatement(newstatement,cifnode.create(
|
||||||
|
caddnode.create(andn,
|
||||||
|
caddnode.create(unequaln,
|
||||||
|
load_self_pointer_node,
|
||||||
|
cnilnode.create),
|
||||||
|
caddnode.create(unequaln,
|
||||||
|
load_vmt_pointer_node,
|
||||||
|
cnilnode.create)),
|
||||||
|
ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
|
||||||
|
nil));
|
||||||
|
tocode:=newblock;
|
||||||
|
current_settings.localswitches:=oldlocalswitches;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
internalerror(200305106);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{****************************************************************************
|
{****************************************************************************
|
||||||
TCGProcInfo
|
TCGProcInfo
|
||||||
****************************************************************************}
|
****************************************************************************}
|
||||||
@ -641,6 +658,7 @@ implementation
|
|||||||
exitlabel_asmnode:=casmnode.create_get_position;
|
exitlabel_asmnode:=casmnode.create_get_position;
|
||||||
final_asmnode:=casmnode.create_get_position;
|
final_asmnode:=casmnode.create_get_position;
|
||||||
bodyexitcode:=generate_bodyexit_block;
|
bodyexitcode:=generate_bodyexit_block;
|
||||||
|
maybe_add_afterconstruction(code);
|
||||||
|
|
||||||
{ Generate procedure by combining init+body+final,
|
{ Generate procedure by combining init+body+final,
|
||||||
depending on the implicit finally we need to add
|
depending on the implicit finally we need to add
|
||||||
|
85
tests/webtbs/tw16311.pp
Normal file
85
tests/webtbs/tw16311.pp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
{ %opt=-gh }
|
||||||
|
|
||||||
|
{$APPTYPE CONSOLE}
|
||||||
|
|
||||||
|
{$ifdef fpc}
|
||||||
|
{$mode delphi}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
uses SysUtils;
|
||||||
|
|
||||||
|
var
|
||||||
|
CreatedCount, DestroyedCount: Integer;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TCntObject }
|
||||||
|
|
||||||
|
TCntObject = class(TObject)
|
||||||
|
public
|
||||||
|
constructor Create; virtual;
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TMyObject }
|
||||||
|
|
||||||
|
TMyObject = class(TCntObject)
|
||||||
|
private
|
||||||
|
FSubObject: TCntObject;
|
||||||
|
public
|
||||||
|
constructor Create; override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure AfterConstruction; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TCntObject }
|
||||||
|
|
||||||
|
constructor TCntObject.Create;
|
||||||
|
begin
|
||||||
|
Inc(CreatedCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TCntObject.Destroy;
|
||||||
|
begin
|
||||||
|
Inc(DestroyedCount);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TMyObject }
|
||||||
|
|
||||||
|
constructor TMyObject.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FSubObject := TCntObject.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TMyObject.Destroy;
|
||||||
|
begin
|
||||||
|
FSubObject.Free;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMyObject.AfterConstruction;
|
||||||
|
begin
|
||||||
|
raise Exception.Create('OnAfterConstruction');
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
A: TMyObject;
|
||||||
|
begin
|
||||||
|
HaltOnNotReleased := true;
|
||||||
|
CreatedCount := 0;
|
||||||
|
DestroyedCount := 0;
|
||||||
|
try
|
||||||
|
A := nil;
|
||||||
|
try
|
||||||
|
A := TMyObject.Create;
|
||||||
|
finally
|
||||||
|
A.Free;
|
||||||
|
end;
|
||||||
|
except
|
||||||
|
writeln('created objects = ', CreatedCount);
|
||||||
|
writeln('destroyed objects = ', DestroyedCount);
|
||||||
|
writeln;
|
||||||
|
end;
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user