Jelajahi Sumber

compiler: don't create enum defs for specializations declarations. Enums are stored in the unit symtables and generic declarations already add them there. Therefore specializations should search for enum defs declared by generics and use them instead of own.

git-svn-id: trunk@16686 -
paul 14 tahun lalu
induk
melakukan
7c33505916
4 mengubah file dengan 69 tambahan dan 9 penghapusan
  1. 1 0
      .gitattributes
  2. 44 8
      compiler/ptype.pas
  3. 1 1
      tests/test/tgeneric24.pp
  4. 23 0
      tests/test/tgeneric27.pp

+ 1 - 0
.gitattributes

@@ -9415,6 +9415,7 @@ tests/test/tgeneric23.pp svneol=native#text/pascal
 tests/test/tgeneric24.pp svneol=native#text/pascal
 tests/test/tgeneric25.pp svneol=native#text/pascal
 tests/test/tgeneric26.pp svneol=native#text/pascal
+tests/test/tgeneric27.pp svneol=native#text/pascal
 tests/test/tgeneric3.pp svneol=native#text/plain
 tests/test/tgeneric4.pp svneol=native#text/plain
 tests/test/tgeneric5.pp svneol=native#text/plain

+ 44 - 8
compiler/ptype.pas

@@ -1240,10 +1240,13 @@ implementation
         hdef : tdef;
         pd : tabstractprocdef;
         is_func,
-        enumdupmsg, first : boolean;
+        enumdupmsg, first, is_specialize : boolean;
         newtype : ttypesym;
         oldlocalswitches : tlocalswitches;
         bitpacking: boolean;
+        stitem: psymtablestackitem;
+        sym: tsym;
+        st: tsymtable;
       begin
          def:=nil;
          case token of
@@ -1258,8 +1261,37 @@ implementation
                 { allow negativ value_str }
                 l:=int64(-1);
                 enumdupmsg:=false;
-                aktenumdef:=tenumdef.create;
+                { check that we are not adding an enum from specialization
+                  we can't just use current_specializedef because of inner types
+                  like specialize array of record }
+                is_specialize:=false;
+                stitem:=symtablestack.stack;
+                while assigned(stitem) do
+                  begin
+                    { check records, classes and arrays because they can be specialized }
+                    if stitem^.symtable.symtabletype in [recordsymtable,ObjectSymtable,arraysymtable] then
+                      begin
+                        is_specialize:=is_specialize or (df_specialization in tstoreddef(stitem^.symtable.defowner).defoptions);
+                        stitem:=stitem^.next;
+                      end
+                    else
+                      break;
+                  end;
+                if not is_specialize then
+                  aktenumdef:=tenumdef.create
+                else
+                  aktenumdef:=nil;
                 repeat
+                  { if it is a specialization then search the first enum member
+                    and get the member owner instead of just created enumdef }
+                  if not assigned(aktenumdef) then
+                    begin
+                      searchsym(pattern,sym,st);
+                      if sym.typ=enumsym then
+                        aktenumdef:=tenumsym(sym).definition
+                      else
+                        internalerror(201101021);
+                    end;
                   s:=orgpattern;
                   defpos:=current_tokenpos;
                   consume(_ID);
@@ -1303,12 +1335,16 @@ implementation
                   else
                     inc(l.svalue);
                   first:=false;
-                  storepos:=current_tokenpos;
-                  current_tokenpos:=defpos;
-                  tenumsymtable(aktenumdef.symtable).insert(tenumsym.create(s,aktenumdef,longint(l.svalue)));
-                  if not (cs_scopedenums in current_settings.localswitches) then
-                    tstoredsymtable(aktenumdef.owner).insert(tenumsym.create(s,aktenumdef,longint(l.svalue)));
-                  current_tokenpos:=storepos;
+                  { don't generate enum members is this is a specialization because aktenumdef is copied from the generic type }
+                  if not is_specialize then
+                    begin
+                      storepos:=current_tokenpos;
+                      current_tokenpos:=defpos;
+                      tenumsymtable(aktenumdef.symtable).insert(tenumsym.create(s,aktenumdef,longint(l.svalue)));
+                      if not (cs_scopedenums in current_settings.localswitches) then
+                        tstoredsymtable(aktenumdef.owner).insert(tenumsym.create(s,aktenumdef,longint(l.svalue)));
+                      current_tokenpos:=storepos;
+                    end;
                 until not try_to_consume(_COMMA);
                 def:=aktenumdef;
                 consume(_RKLAMMER);

+ 1 - 1
tests/test/tgeneric24.pp

@@ -1,4 +1,4 @@
-program project1;
+program tgeneric24;
 
 {$mode objfpc}{$H+}
 {$apptype console}

+ 23 - 0
tests/test/tgeneric27.pp

@@ -0,0 +1,23 @@
+program tgeneric27;
+
+{ check that specialization does not add enum members to the static symtable and reuses the generic enum definintion }
+
+{$mode objfpc}{$H+}
+type
+  generic TRecArr<T> = array[0..1] of record
+    case enum:(one, two, three) of
+      one: (F: Integer);
+      two: (Z: Byte);
+      three: (Y: PChar);
+  end;
+
+var
+  A: specialize TRecArr<Integer>;
+  B: specialize TRecArr<String>;
+begin
+  A[0].enum := one;
+  B[0].enum := one;
+  if A[0].enum <> B[0].enum then
+    halt(1);
+end.
+