fix(semantic): reject procedural/record/class types as WriteLn/Write arguments
WriteLn/Write had no type-check on their argument list — a procedural variable (or any other unprintable type: record, class, interface, array) was silently accepted by the semantic pass and handed to the codegen, which emitted it as an integer (the raw code pointer). The native backend printed the address; QBE rejected the IR with "invalid argument". Add a post-analyse check in the Write/WriteLn branch: after resolving each argument's type, reject tyProcedural, tyRecord, tyClass, tyInterface, tyMetaClass, tyStaticArray, tyDynArray, tyOpenArray, and tyPointer with a clear error message matching FPC's behaviour. Adds one semantic unit test covering the procedural-variable case.
This commit is contained in:
parent
1b0afaf3d3
commit
b3024facc0
|
|
@ -6928,9 +6928,21 @@ begin
|
|||
end
|
||||
else
|
||||
begin
|
||||
{ Other built-ins (WriteLn/Write/etc.) — just analyse arg expressions }
|
||||
{ Other built-ins (WriteLn/Write/etc.) — analyse args, then for
|
||||
Write/WriteLn specifically reject types that have no text representation. }
|
||||
for I := 0 to ACall.Args.Count - 1 do
|
||||
AnalyseExpr(TASTExpr(ACall.Args.Items[I]));
|
||||
begin
|
||||
ArgType := AnalyseExpr(TASTExpr(ACall.Args.Items[I]));
|
||||
if SameText(ACall.Name, 'WriteLn') or SameText(ACall.Name, 'Write') then
|
||||
if (ArgType <> nil) and
|
||||
(ArgType.Kind in [tyProcedural, tyRecord, tyClass, tyInterface,
|
||||
tyMetaClass, tyStaticArray, tyDynArray,
|
||||
tyOpenArray, tyPointer, tyNil]) then
|
||||
SemanticError(
|
||||
Format('Cannot pass a value of type ''%s'' to ''%s''',
|
||||
[ArgType.Name, ACall.Name]),
|
||||
ACall.Line, ACall.Col);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ type
|
|||
procedure TestProcCall_WriteLn_NoArgs_OK;
|
||||
procedure TestProcCall_WriteLn_StringArg_OK;
|
||||
procedure TestProcCall_WriteLn_IntArg_OK;
|
||||
procedure TestProcCall_WriteLn_ProceduralArg_RaisesError;
|
||||
procedure TestProcCall_UndeclaredProc_RaisesError;
|
||||
|
||||
{ Full program analysis }
|
||||
|
|
@ -421,6 +422,21 @@ begin
|
|||
Analyse('program P; begin WriteLn(99) end.').Free();
|
||||
end;
|
||||
|
||||
procedure TSemanticTests.TestProcCall_WriteLn_ProceduralArg_RaisesError;
|
||||
begin
|
||||
AnalyseExpectError(
|
||||
'''
|
||||
program TestProc;
|
||||
type TProc = procedure(A, B: Integer);
|
||||
procedure Dummy(A, B: Integer); begin end;
|
||||
var V: TProc;
|
||||
begin
|
||||
V := @Dummy;
|
||||
WriteLn(V)
|
||||
end.
|
||||
''');
|
||||
end;
|
||||
|
||||
procedure TSemanticTests.TestProcCall_UndeclaredProc_RaisesError;
|
||||
begin
|
||||
AnalyseExpectError('program P; begin NoSuchProc end.');
|
||||
|
|
|
|||
Loading…
Reference in a new issue