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

+ added test
This commit is contained in:
Sven/Sarah Barth 2024-02-09 17:24:39 +01:00
parent ed8a05d697
commit 43721f21c4
3 changed files with 86 additions and 31 deletions

View File

@ -3245,17 +3245,19 @@ implementation
objfield.fieldname:=1 -> contextobjdef = def of objfield
}
function is_visible_for_object(symst:tsymtable;symvisibility:tvisibility;contextobjdef:tabstractrecorddef):boolean;
var
curstruct : tabstractrecorddef;
function is_current_unit(st:tsymtable):boolean;
begin
result :=
(
(
assigned(current_structdef) and
(st.moduleid=current_structdef.symtable.moduleid)
assigned(curstruct) and
(st.moduleid=curstruct.symtable.moduleid)
) or
(
not assigned(current_structdef) and
not assigned(curstruct) and
st.iscurrentunit
)
);
@ -3273,9 +3275,32 @@ implementation
not (symst.symtabletype in [objectsymtable,recordsymtable]) then
internalerror(200810285);
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 }
nonlocalst:=symownerdef.owner;
if tstoreddef(symst.defowner).is_specialization then
if tstoreddef(symownerdef).is_specialization then
while nonlocalst.symtabletype in [localsymtable,parasymtable] do
nonlocalst:=nonlocalst.defowner.owner;
isspezproc:=false;
@ -3297,49 +3322,49 @@ implementation
( // the case of specialize inside the generic declaration and nested types
(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
(
not assigned(current_structdef) and
not assigned(curstruct) and
(symownerdef.owner.iscurrentunit)
) or
{ access from a generic method that belongs to the class
but that is specialized elsewere }
(
isspezproc and
(current_procinfo.procdef.struct=current_structdef)
(current_procinfo.procdef.struct=curstruct)
) or
{ specializations may access private symbols that their
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;
vis_strictprivate :
begin
result:=assigned(current_structdef) and
is_owned_by(current_structdef,symownerdef);
result:=assigned(curstruct) and
is_owned_by(curstruct,symownerdef);
end;
vis_strictprotected :
begin
result:=(
{ access from nested class }
assigned(current_structdef) and
is_owned_by(current_structdef,symownerdef)
assigned(curstruct) and
is_owned_by(curstruct,symownerdef)
) or
(
{ access from child class }
assigned(contextobjdef) and
assigned(current_structdef) and
assigned(curstruct) and
def_is_related(contextobjdef,symownerdef) and
def_is_related(current_structdef,contextobjdef)
def_is_related(curstruct,contextobjdef)
) or
(
{ helpers can access strict protected symbols }
@ -3349,8 +3374,8 @@ implementation
(
{ same as above, but from context of call node inside
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;
vis_protected :
@ -3372,14 +3397,14 @@ implementation
( // the case of specialize inside the generic declaration and nested types
(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
(
not assigned(current_structdef) and
not assigned(curstruct) and
(symownerdef.owner.iscurrentunit)
) or
(
@ -3392,14 +3417,14 @@ implementation
but that is specialized elsewere }
(
isspezproc and
(current_procinfo.procdef.struct=current_structdef)
(current_procinfo.procdef.struct=curstruct)
) or
{ specializations may access private symbols that their
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;
@ -3414,9 +3439,9 @@ implementation
begin
{ capturers have access to anything as we assume checks were done
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;

16
tests/webtbf/tw40621.pp Normal file
View File

@ -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
tests/webtbf/uw40621.pp Normal file
View File

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