Преглед изворни кода

pgenutil.pas, generate_specialization:
- Remove unneeded check for "parse_generic" (it's already checked in the outer if-clause).
+ Check whether we are trying to specialize one of the surrounding type declarations of a
nested type (as long as nested generics are forbidden this is always the outermost generic
or specialization). This check can not rely on the symbol, because while parsing the
generic or the specialization the symbol's def is still an errordef. This fixes
Mantis #19498 .

+ Added test from bug report.

git-svn-id: trunk@20247 -

svenbarth пре 13 година
родитељ
комит
04683c5f13
3 измењених фајлова са 81 додато и 14 уклоњено
  1. 1 0
      .gitattributes
  2. 53 14
      compiler/pgenutil.pas
  3. 27 0
      tests/webtbs/tw19498.pp

+ 1 - 0
.gitattributes

@@ -12106,6 +12106,7 @@ tests/webtbs/tw1936.pp svneol=native#text/plain
 tests/webtbs/tw19368.pp svneol=native#text/pascal
 tests/webtbs/tw1938.pp svneol=native#text/plain
 tests/webtbs/tw1948.pp svneol=native#text/plain
+tests/webtbs/tw19498.pp svneol=native#text/pascal
 tests/webtbs/tw1950.pp svneol=native#text/plain
 tests/webtbs/tw19500.pp svneol=native#text/pascal
 tests/webtbs/tw19548.pp svneol=native#text/pascal

+ 53 - 14
compiler/pgenutil.pas

@@ -74,7 +74,7 @@ uses
         err : boolean;
         i,
         gencount,crc : longint;
-        genericdef : tstoreddef;
+        genericdef,def : tstoreddef;
         generictype : ttypesym;
         genericdeflist : TFPObjectList;
         generictypelist : TFPObjectList;
@@ -118,7 +118,7 @@ uses
               consume(_RSHARPBRACKET);
             { we need to return a def that can later pass some checks like
               whether it's an interface or not }
-            if parse_generic and (not assigned(tt) or (tt.typ=undefineddef)) then
+            if not assigned(tt) or (tt.typ=undefineddef) then
               begin
                 if (symname='') and (df_generic in genericdef.defoptions) then
                   { this happens in non-Delphi modes }
@@ -134,19 +134,39 @@ uses
                       genname:=symname;
                     genname:=genname+'$'+countstr;
                     ugenname:=upper(genname);
-                    if not searchsym(ugenname,srsym,st) or
-                        (srsym.typ<>typesym) then
+                    { first check whether the found name is the same as that of
+                      the current def or one of its (generic) surrounding defs;
+                      this is necessary as the symbol of the generic can not yet
+                      be used for lookup as it still contains a reference to an
+                      errordef) }
+                    def:=current_genericdef;
+                    repeat
+                      if def.typ in [objectdef,recorddef] then
+                        if tabstractrecorddef(def).objname^=ugenname then
+                          begin
+                            tt:=def;
+                            break;
+                          end;
+                      def:=tstoreddef(def.owner.defowner);
+                    until not assigned(def) or not (df_generic in def.defoptions);
+                    { it's not part of the current object hierarchy, so search
+                      for the symbol }
+                    if not assigned(tt) then
                       begin
-                        identifier_not_found(genname);
-                        exit;
-                      end;
-                    tt:=ttypesym(srsym).typedef;
-                    { this happens in non-Delphi modes if we encounter a
-                      specialization of the generic class or record we're
-                      currently parsing }
-                    if (tt.typ=errordef) and assigned(current_structdef) and
-                        (current_structdef.objname^=ugenname) then
-                      tt:=current_structdef;
+                      if not searchsym(ugenname,srsym,st) or
+                          (srsym.typ<>typesym) then
+                        begin
+                          identifier_not_found(genname);
+                          exit;
+                        end;
+                      tt:=ttypesym(srsym).typedef;
+                      { this happens in non-Delphi modes if we encounter a
+                        specialization of the generic class or record we're
+                        currently parsing }
+                      if (tt.typ=errordef) and assigned(current_structdef) and
+                          (current_structdef.objname^=ugenname) then
+                        tt:=current_structdef;
+                    end;
                   end;
               end;
             exit;
@@ -312,6 +332,25 @@ uses
           specializest:=current_module.localsymtable;
 
         { Can we reuse an already specialized type? }
+
+        { for this first check whether we are currently specializing a nested
+          type of the current (main) specialization (this is necessary, because
+          during that time the symbol of the main specialization will still
+          contain a reference to an errordef) }
+        if not assigned(tt) and assigned(current_specializedef) then
+          begin
+            def:=current_specializedef;
+            repeat
+              if def.typ in [objectdef,recorddef] then
+                if tabstractrecorddef(def).objname^=ufinalspecializename then begin
+                  tt:=def;
+                  break;
+                end;
+              def:=tstoreddef(def.owner.defowner);
+            until not assigned(def) or not (df_specialization in def.defoptions);
+          end;
+
+        { now check whether there is a specialization somewhere else }
         if not assigned(tt) then
           begin
             hashedid.id:=ufinalspecializename;

+ 27 - 0
tests/webtbs/tw19498.pp

@@ -0,0 +1,27 @@
+{ %NORUN }
+
+{$MODE OBJFPC} { -*- text -*- }
+program tw19498;
+
+type
+   generic TFoo1 <T> = class
+    type
+     TFoo2 = class 
+        constructor Create(Owner: specialize TFoo1<T>);
+     end;
+   end;
+
+constructor TFoo1.TFoo2.Create(Owner: specialize TFoo1<T>);
+begin
+end;
+
+type
+   TIntegerFoo1 = specialize TFoo1<Integer>;
+
+var 
+   Foo1: TIntegerFoo1;
+   Foo2: TIntegerFoo1.TFoo2; 
+
+begin
+end.
+