Overload resolution problem inside compiler
Summary
The compiler chooses a wrong overload
when two variants differ only by the fact that one
parameter is by var in one overload and by value in the second,
but only if the type of that var
variable is a pointer.
This bug also shows up currently inside trunk source,
for netbsd
and openbsd
OS targets with sem_init
function overloads,
see for instance i386-netbsd failure
Writing Resource String Table file: fptemplate.rsj
Compiling ./fcl-base/src/syncobjs.pp
syncobjs.pp(702,59) Error: Can't assign values to an address
syncobjs.pp(738,59) Error: Can't assign values to an address
syncobjs.pp(762,64) Error: Can't assign values to an address
System Information
- Operating system: Probably all
- Processor architecture: Probably all
- Compiler version: Tested on trunk compiler, but might be present in other versions
Steps to reproduce
Try to compile the file toverload.pp
given below.
fpc toverload.pp
results in this error:
fpc@idefix:~/pas/check$ fpc toverload.pp
Free Pascal Compiler version 3.3.1-14440-g51180e6823-unpushed [2023/11/22] for x86_64
Copyright (c) 1993-2023 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling toverload.pp
toverload.pp(38,7) Warning: Variable "i" does not seem to be initialized
toverload.pp(39,11) Error: Can't assign values to an address
toverload.pp(64) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /home/FPC/compilers/cross-compiling/pas/fpc-3.3.1/bin/ppcx64 returned an error exitcode
Example Project
fpc@idefix:~/pas/check$ cat toverload.pp
type
{$ifdef USE_RECORD}
trec = record
y : longint;
end;
{$else}
{$ifdef USE_PTRINT}
trec = ptrint;
{$else USE_PTRINT}
trec = pointer;
{$endif USE_PTRINT}
{$endif}
prec = ^trec;
const
value_version_used : longint = 0;
var_version_used : longint = 0;
has_error : boolean = false;
function test(p : prec;l : longint; k: dword) : boolean; overload;
begin
test:=(p<>nil);
inc(value_version_used);
end;
function test(var p : trec;l : longint; k: dword) : boolean; overload;
begin
test:=(@p<>nil);
inc(var_version_used);
end;
var
pt : trec;
i : trec;
begin
pt:=i;
test(@pt,23,56);
if (var_version_used>0) then
begin
writeln('call with @pt uses var version, which is wrong');
has_error:=true;
end
else
writeln('call with @pt uses value version');
var_version_used:=0;
value_version_used:=0;
test(pt,678,567890);
if (var_version_used>0) then
writeln('direct call uses var version')
else
writeln('direct call uses value version');
if has_error then
begin
writeln('This test revealed a problem');
halt(1);
end;
end.
What is the current bug behavior?
Bug inside compiler leads, at line 39 of toverload.pp, to a wrong choice of the overloaded test
function
having a by var
first parameter, which is incompatible with the fact that this
@pt
is incompatible with the var
modifier.
What is the expected (correct) behavior?
The compiler should choose the correct overload without the var
parameter.
Relevant logs and/or screenshots
Possible fixes
The fix is probably to change choose_best
function
in order to also consider the vs_value
or vs_var
varspez field of the parameters.