Skip to content

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 netbsdand 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 varmodifier.

What is the expected (correct) behavior?

The compiler should choose the correct overload without the varparameter.

Relevant logs and/or screenshots

Possible fixes

The fix is probably to change choose_best function in order to also consider the vs_valueor vs_var varspez field of the parameters.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information