[fpc-devel] Local classes and interfaces
Blaise at blaise.ru
Blaise at blaise.ru
Mon Dec 21 16:22:12 CET 2020
On 19.12.2020 16:51, Sven Barth wrote:
> Considering that it's only intended for internal use, yes I'm aboard with that.
Here is the first change: http://hg.blaise.ru/public/fpc/rev/7c78bfdaed9a (attached).
Strictly speaking, some local classes and interfaces can be compiled without that -- the ICE 200204175 only occurs when they have their own entities such as nested classes (not used for Closures) and non-abstract methods:
-------8<-------
function Foo: TClass;
type Local = class
type Nested = class end;
procedure Method;
end;
procedure Local.Method;
begin
end;
begin
result := Local
end;
begin
Foo
end.
-------8<-------
To observe the effect, one could temporarily use the second attached patch to force FPC to compile the above test case. The following internal names are generated for it:
VMT_$P$PROGRAM$_$FOO_$$_LOCAL // no change
VMT_$P$PROGRAM$_$FOO_$LOCAL_$__$$_NESTED // was: ICE
P$PROGRAM$_$FOO_$LOCAL_$__$$_METHOD // was: ICE
Please check that such names are in line with the intended format.
> I'd say in this case the bug is that the declaration of those two Cls<> types is allowed.
Looking at the excerpt from object_dec:
> { objects and class types can't be declared local }
> if not(symtablestack.top.symtabletype in [globalsymtable,staticsymtable,objectsymtable,recordsymtable]) and
> not assigned(genericlist) then
> Message(parser_e_no_local_objects);
"assigned(genericlist)" seems intentional. Maybe, it misses a check for generic instantiation; however:
> If I remember correctly *specializations* are already placed in the more nested scope if they use local types.
Judging solely by the internal names, that is not what happens.
> or at least that was the plan
If you were to implement that, you would encounter the same ICE.
--
βþ
-------------- next part --------------
# HG changeset patch
# User Blaise.ru
+ make_mangledname: allow for local classes & interfaces
diff -r 7b102c2fd615 -r 4990da1ff00c symdef.pas
--- a/symdef.pas
+++ b/symdef.pas
@@ -1535,36 +1535,42 @@
prefix:='';
if not assigned(st) then
internalerror(200204212);
- { sub procedures }
- while (st.symtabletype in [localsymtable,parasymtable]) do
- begin
- if st.defowner.typ<>procdef then
- internalerror(200204173);
- { Add the full mangledname of procedure to prevent
- conflicts with 2 overloads having both a nested procedure
- with the same name, see tb0314 (PFV) }
- s:=tprocdef(st.defowner).procsym.name;
- s:=s+tprocdef(st.defowner).mangledprocparanames(Length(s));
- if prefix<>'' then
- prefix:=s+'_'+prefix
- else
- prefix:=s;
- if length(prefix)>100 then
- begin
- crc:=0;
- crc:=UpdateCrc32(crc,prefix[1],length(prefix));
- prefix:='$CRC'+hexstr(crc,8);
- end;
- st:=st.defowner.owner;
- end;
- { object/classes symtable, nested type definitions in classes require the while loop }
- while st.symtabletype in [ObjectSymtable,recordsymtable] do
- begin
- if not (st.defowner.typ in [objectdef,recorddef]) then
- internalerror(200204174);
- prefix:=tabstractrecorddef(st.defowner).objname^+'_$_'+prefix;
- st:=st.defowner.owner;
- end;
+ repeat
+ { sub procedures }
+ while (st.symtabletype in [localsymtable,parasymtable]) do
+ begin
+ if st.defowner.typ<>procdef then
+ internalerror(200204173);
+ { Add the full mangledname of the routine to prevent
+ conflicts with two overloads both having a local entity
+ -- routine (tb0314), class, interface -- with the same name }
+ s:=tprocdef(st.defowner).procsym.name;
+ s:=s+tprocdef(st.defowner).mangledprocparanames(Length(s));
+ if prefix<>'' then
+ prefix:=s+'_'+prefix
+ else
+ prefix:=s;
+ if length(prefix)>100 then
+ begin
+ crc:=0;
+ crc:=UpdateCrc32(crc,prefix[1],length(prefix));
+ prefix:='$CRC'+hexstr(crc,8);
+ end;
+ st:=st.defowner.owner;
+ end;
+ { object/classes symtable, nested type definitions in classes require the while loop }
+ while st.symtabletype in [ObjectSymtable,recordsymtable] do
+ begin
+ if not (st.defowner.typ in [objectdef,recorddef]) then
+ internalerror(200204174);
+ prefix:=tabstractrecorddef(st.defowner).objname^+'_$_'+prefix;
+ st:=st.defowner.owner;
+ end;
+ { local classes & interfaces are possible (because of closures) }
+ if st.symtabletype<>localsymtable then
+ break;
+ prefix:='$'+prefix;
+ until false;
{ symtable must now be static or global }
if not(st.symtabletype in [staticsymtable,globalsymtable]) then
internalerror(200204175);
-------------- next part --------------
# HG changeset patch
# User Blaise.ru
TEST: allow local classes/interfaces
diff -r 4990da1ff00c -r 98b295988049 pdecobj.pas
--- a/pdecobj.pas
+++ b/pdecobj.pas
@@ -1428,9 +1428,9 @@
current_specializedef:=nil;
{ objects and class types can't be declared local }
- if not(symtablestack.top.symtabletype in [globalsymtable,staticsymtable,objectsymtable,recordsymtable]) and
+ {if not(symtablestack.top.symtabletype in [globalsymtable,staticsymtable,objectsymtable,recordsymtable]) and
not assigned(genericlist) then
- Message(parser_e_no_local_objects);
+ Message(parser_e_no_local_objects);}
{ reuse forward objectdef? }
if assigned(fd) then
diff -r 4990da1ff00c -r 98b295988049 pdecsub.pas
--- a/pdecsub.pas
+++ b/pdecsub.pas
@@ -934,7 +934,7 @@
{ method ? }
srsym:=nil;
if not assigned(astruct) and
- (symtablestack.top.symtablelevel=main_program_level) and
+ //(symtablestack.top.symtablelevel=main_program_level) and
try_to_consume(_POINT) then
begin
repeat
More information about the fpc-devel
mailing list