Browse Source

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 years ago
parent
commit
a1ef0add65
3 changed files with 56 additions and 2 deletions
  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.