Browse Source

* fix #40621: when checking for visibility of members then always use the genericdefs for specializations for correct scoping
+ added test

Sven/Sarah Barth 1 year ago
parent
commit
43721f21c4
3 changed files with 86 additions and 31 deletions
  1. 56 31
      compiler/symtable.pas
  2. 16 0
      tests/webtbf/tw40621.pp
  3. 14 0
      tests/webtbf/uw40621.pp

+ 56 - 31
compiler/symtable.pas

@@ -3245,17 +3245,19 @@ implementation
         objfield.fieldname:=1 -> contextobjdef = def of objfield
         objfield.fieldname:=1 -> contextobjdef = def of objfield
     }
     }
     function is_visible_for_object(symst:tsymtable;symvisibility:tvisibility;contextobjdef:tabstractrecorddef):boolean;
     function is_visible_for_object(symst:tsymtable;symvisibility:tvisibility;contextobjdef:tabstractrecorddef):boolean;
+      var
+        curstruct : tabstractrecorddef;
 
 
       function is_current_unit(st:tsymtable):boolean;
       function is_current_unit(st:tsymtable):boolean;
         begin
         begin
           result :=
           result :=
             (
             (
               (
               (
-                assigned(current_structdef) and
-                (st.moduleid=current_structdef.symtable.moduleid)
+                assigned(curstruct) and
+                (st.moduleid=curstruct.symtable.moduleid)
               ) or
               ) or
               (
               (
-                not assigned(current_structdef) and
+                not assigned(curstruct) and
                 st.iscurrentunit
                 st.iscurrentunit
               )
               )
             );
             );
@@ -3273,9 +3275,32 @@ implementation
            not (symst.symtabletype in [objectsymtable,recordsymtable]) then
            not (symst.symtabletype in [objectsymtable,recordsymtable]) then
           internalerror(200810285);
           internalerror(200810285);
         symownerdef:=tabstractrecorddef(symst.defowner);
         symownerdef:=tabstractrecorddef(symst.defowner);
+        { for specializations we need to check the visibility of the generic,
+          not the specialization (at least when comparing outside of the
+          specialization }
+        if df_specialization in symownerdef.defoptions then
+          begin
+            if not (symownerdef.genericdef.typ in [objectdef,recorddef]) then
+              internalerror(2024020901);
+            symownerdef:=tabstractrecorddef(symownerdef.genericdef);
+          end;
+        if assigned(contextobjdef) and (df_specialization in contextobjdef.defoptions) then
+          begin
+            if not (contextobjdef.genericdef.typ in [objectdef,recorddef]) then
+              internalerror(2024020902);
+            contextobjdef:=tabstractrecorddef(contextobjdef.genericdef);
+          end;
+        if assigned(current_structdef) and (df_specialization in current_structdef.defoptions) then
+          begin
+            if not (current_structdef.genericdef.typ in [objectdef,recorddef]) then
+              internalerror(2024030903);
+            curstruct:=tabstractrecorddef(current_structdef.genericdef)
+          end
+        else
+          curstruct:=current_structdef;
         { specializations might belong to a localsymtable or parasymtable }
         { specializations might belong to a localsymtable or parasymtable }
         nonlocalst:=symownerdef.owner;
         nonlocalst:=symownerdef.owner;
-        if tstoreddef(symst.defowner).is_specialization then
+        if tstoreddef(symownerdef).is_specialization then
           while nonlocalst.symtabletype in [localsymtable,parasymtable] do
           while nonlocalst.symtabletype in [localsymtable,parasymtable] do
             nonlocalst:=nonlocalst.defowner.owner;
             nonlocalst:=nonlocalst.defowner.owner;
         isspezproc:=false;
         isspezproc:=false;
@@ -3297,49 +3322,49 @@ implementation
                       ( // the case of specialize inside the generic declaration and nested types
                       ( // the case of specialize inside the generic declaration and nested types
                        (nonlocalst.symtabletype in [objectsymtable,recordsymtable]) and
                        (nonlocalst.symtabletype in [objectsymtable,recordsymtable]) and
                        (
                        (
-                         assigned(current_structdef) and
+                         assigned(curstruct) and
                          (
                          (
-                           (current_structdef=symownerdef) or
-                           (current_structdef.owner.moduleid=symownerdef.symtable.moduleid)
+                           (curstruct=symownerdef) or
+                           (curstruct.owner.moduleid=symownerdef.symtable.moduleid)
                          )
                          )
                        ) or
                        ) or
                        (
                        (
-                         not assigned(current_structdef) and
+                         not assigned(curstruct) and
                          (symownerdef.owner.iscurrentunit)
                          (symownerdef.owner.iscurrentunit)
                        ) or
                        ) or
                        { access from a generic method that belongs to the class
                        { access from a generic method that belongs to the class
                          but that is specialized elsewere }
                          but that is specialized elsewere }
                        (
                        (
                          isspezproc and
                          isspezproc and
-                         (current_procinfo.procdef.struct=current_structdef)
+                         (current_procinfo.procdef.struct=curstruct)
                        ) or
                        ) or
                        { specializations may access private symbols that their
                        { specializations may access private symbols that their
                          generics are allowed to access }
                          generics are allowed to access }
                        (
                        (
-                         assigned(current_structdef) and
-                         (df_specialization in current_structdef.defoptions) and
-                         (symst.moduleid=current_structdef.genericdef.owner.moduleid)
+                         assigned(curstruct) and
+                         (df_specialization in curstruct.defoptions) and
+                         (symst.moduleid=curstruct.genericdef.owner.moduleid)
                        )
                        )
                       );
                       );
             end;
             end;
           vis_strictprivate :
           vis_strictprivate :
             begin
             begin
-              result:=assigned(current_structdef) and
-                      is_owned_by(current_structdef,symownerdef);
+              result:=assigned(curstruct) and
+                      is_owned_by(curstruct,symownerdef);
             end;
             end;
           vis_strictprotected :
           vis_strictprotected :
             begin
             begin
                result:=(
                result:=(
                          { access from nested class }
                          { access from nested class }
-                         assigned(current_structdef) and
-                         is_owned_by(current_structdef,symownerdef)
+                         assigned(curstruct) and
+                         is_owned_by(curstruct,symownerdef)
                        ) or
                        ) or
                        (
                        (
                          { access from child class }
                          { access from child class }
                          assigned(contextobjdef) and
                          assigned(contextobjdef) and
-                         assigned(current_structdef) and
+                         assigned(curstruct) and
                          def_is_related(contextobjdef,symownerdef) and
                          def_is_related(contextobjdef,symownerdef) and
-                         def_is_related(current_structdef,contextobjdef)
+                         def_is_related(curstruct,contextobjdef)
                        ) or
                        ) or
                        (
                        (
                          { helpers can access strict protected symbols }
                          { helpers can access strict protected symbols }
@@ -3349,8 +3374,8 @@ implementation
                        (
                        (
                          { same as above, but from context of call node inside
                          { same as above, but from context of call node inside
                            helper method }
                            helper method }
-                         is_objectpascal_helper(current_structdef) and
-                         def_is_related(tobjectdef(current_structdef).extendeddef,symownerdef)
+                         is_objectpascal_helper(curstruct) and
+                         def_is_related(tobjectdef(curstruct).extendeddef,symownerdef)
                        );
                        );
             end;
             end;
           vis_protected :
           vis_protected :
@@ -3372,14 +3397,14 @@ implementation
                        ( // the case of specialize inside the generic declaration and nested types
                        ( // the case of specialize inside the generic declaration and nested types
                         (nonlocalst.symtabletype in [objectsymtable,recordsymtable]) and
                         (nonlocalst.symtabletype in [objectsymtable,recordsymtable]) and
                         (
                         (
-                          assigned(current_structdef) and
+                          assigned(curstruct) and
                           (
                           (
-                            (current_structdef=symownerdef) or
-                            (current_structdef.owner.moduleid=symownerdef.symtable.moduleid)
+                            (curstruct=symownerdef) or
+                            (curstruct.owner.moduleid=symownerdef.symtable.moduleid)
                           )
                           )
                         ) or
                         ) or
                         (
                         (
-                          not assigned(current_structdef) and
+                          not assigned(curstruct) and
                           (symownerdef.owner.iscurrentunit)
                           (symownerdef.owner.iscurrentunit)
                         ) or
                         ) or
                         (
                         (
@@ -3392,14 +3417,14 @@ implementation
                          but that is specialized elsewere }
                          but that is specialized elsewere }
                        (
                        (
                          isspezproc and
                          isspezproc and
-                         (current_procinfo.procdef.struct=current_structdef)
+                         (current_procinfo.procdef.struct=curstruct)
                        ) or
                        ) or
                        { specializations may access private symbols that their
                        { specializations may access private symbols that their
                          generics are allowed to access }
                          generics are allowed to access }
                        (
                        (
-                         assigned(current_structdef) and
-                         (df_specialization in current_structdef.defoptions) and
-                         (symst.moduleid=current_structdef.genericdef.owner.moduleid)
+                         assigned(curstruct) and
+                         (df_specialization in curstruct.defoptions) and
+                         (symst.moduleid=curstruct.genericdef.owner.moduleid)
                        )
                        )
                       );
                       );
             end;
             end;
@@ -3414,9 +3439,9 @@ implementation
           begin
           begin
             { capturers have access to anything as we assume checks were done
             { capturers have access to anything as we assume checks were done
               before the procdef was inserted into the capturer }
               before the procdef was inserted into the capturer }
-            result:=assigned(current_structdef) and
-                    (current_structdef.typ=objectdef) and
-                    (oo_is_capturer in tobjectdef(current_structdef).objectoptions);
+            result:=assigned(curstruct) and
+                    (curstruct.typ=objectdef) and
+                    (oo_is_capturer in tobjectdef(curstruct).objectoptions);
           end;
           end;
       end;
       end;
 
 

+ 16 - 0
tests/webtbf/tw40621.pp

@@ -0,0 +1,16 @@
+{ %FAIL }
+
+program tw40621;
+{$mode delphi}{$H+}
+uses uw40621;
+
+var
+  X: TRecord< int32 >; // declared in unitFault
+
+begin
+  X.PrivateMember := 'Should not be able to assign this.';
+  //Writeln( X.PrivateMember );
+  //Readln;
+end.
+
+

+ 14 - 0
tests/webtbf/uw40621.pp

@@ -0,0 +1,14 @@
+unit uw40621;
+{$mode delphiunicode}{$H+}
+
+interface
+
+type
+  TRecord< T > = record
+  private
+    PrivateMember: string;
+  end;
+
+implementation
+end.
+