Pārlūkot izejas kodu

When searching for the generic def of nested types inside specializations we first need to check local declarations inside the method if we are in one. Only then we may search inside the type's declaration. Fixes #20836 .

git-svn-id: trunk@19777 -
svenbarth 13 gadi atpakaļ
vecāks
revīzija
a1ef0add65
3 mainītis faili ar 56 papildinājumiem un 2 dzēšanām
  1. 1 0
      .gitattributes
  2. 26 2
      compiler/pdecl.pas
  3. 29 0
      tests/webtbs/tw20836.pp

+ 1 - 0
.gitattributes

@@ -11942,6 +11942,7 @@ tests/webtbs/tw2069.pp svneol=native#text/plain
 tests/webtbs/tw20690.pp svneol=native#text/pascal
 tests/webtbs/tw2072.pp svneol=native#text/plain
 tests/webtbs/tw20744.pp svneol=native#text/plain
+tests/webtbs/tw20836.pp svneol=native#text/pascal
 tests/webtbs/tw2109.pp svneol=native#text/plain
 tests/webtbs/tw2110.pp svneol=native#text/plain
 tests/webtbs/tw2128.pp svneol=native#text/plain

+ 26 - 2
compiler/pdecl.pas

@@ -363,6 +363,8 @@ implementation
          p:tnode;
          gendef : tstoreddef;
          s : shortstring;
+         pd: tprocdef;
+         hashedid : thashedidstring;
       begin
          old_block_type:=block_type;
          { save unit container of forward declarations -
@@ -535,9 +537,31 @@ implementation
                       if not assigned(current_structdef.genericdef) or
                           not (current_structdef.genericdef.typ in [recorddef,objectdef]) then
                         internalerror(2011052301);
-                      sym:=tsym(tabstractrecorddef(current_structdef.genericdef).symtable.Find(gentypename));
+                      hashedid.id:=gentypename;
+                      { we could be inside a method of the specialization
+                        instead of its declaration, so check that first (as
+                        local nested types aren't allowed we don't need to
+                        walk the symtablestack to find the localsymtable) }
+                      if symtablestack.top.symtabletype=localsymtable then
+                        begin
+                          { we are in a method }
+                          if not assigned(symtablestack.top.defowner) or
+                              (symtablestack.top.defowner.typ<>procdef) then
+                            internalerror(2011120701);
+                          pd:=tprocdef(symtablestack.top.defowner);
+                          if not assigned(pd.genericdef) or (pd.genericdef.typ<>procdef) then
+                            internalerror(2011120702);
+                          sym:=tsym(tprocdef(pd.genericdef).localst.findwithhash(hashedid));
+                        end
+                      else
+                        sym:=nil;
                       if not assigned(sym) or not (sym.typ=typesym) then
-                        internalerror(2011052302);
+                        begin
+                          { now search in the declaration of the generic }
+                          sym:=tsym(tabstractrecorddef(current_structdef.genericdef).symtable.findwithhash(hashedid));
+                          if not assigned(sym) or not (sym.typ=typesym) then
+                            internalerror(2011052302);
+                        end;
                       { use the corresponding type in the generic's symtable as
                         genericdef for the specialized type }
                       gendef:=tstoreddef(ttypesym(sym).typedef);

+ 29 - 0
tests/webtbs/tw20836.pp

@@ -0,0 +1,29 @@
+program tw20836;
+
+{$mode objfpc}{$H+}
+
+uses
+  {$IFDEF UNIX}{$IFDEF UseCThreads}
+  cthreads,
+  {$ENDIF}{$ENDIF}
+  Classes
+  { you can add units after this };
+
+{.$R *.res}
+type
+  generic TGObjectChangeCommand<_T>=object
+                                        private
+                                        DoData,UnDoData:_T;
+                                        method:tmethod;
+                                        public
+                                        procedure UnDo;virtual;
+                                    end;
+  TCommand=specialize TGObjectChangeCommand<Integer>;
+procedure TGObjectChangeCommand.UnDo;
+type
+    TCangeMethod=procedure(const data:_T)of object;
+begin
+     TCangeMethod(method)(UnDoData);
+end;
+begin
+end.