Search code examples
delphifreepascalconditional-compilation

Will Delphi compiler always fail when compiling a module with conditional-based type mismatch?


For practical example, suppose ModuleA have some type varying on conditional compilation:

unit ModuleA;

interface

type
  { explicit character width }
  PASTR = type PAnsiChar;
  PWSTR = type PWideChar;
  { imlicit character width }
  PTSTR = {$IFDEF UNICODE}PWSTR{$ELSE}PASTR{$ENDIF};

  { ... }

And now the set of functions in ModuleB is depending on the type declared in ModuleA:

unit ModuleB;

{ ... }    

implementation

uses ModuleA;

{ explicit }
function FuncA(Arg: PASTR): Integer;
begin
  { do something with 1 byte char }
end;

function FuncW(Arg: PWSTR): Integer;
begin
  { do something with 2 byte char }
end;

{ implicit - will compiler safeguard against mismatching UNICODE define? }
function Func(Arg: PTSTR): Integer;
begin
  { map to explicit one }
  Result := {$IFDEF UNICODE}FuncW(Arg){$ELSE}FuncA(Arg){$ENDIF};
end;

Now, suppose ModuleA has been compiled with UNICODE symbol defined and DCU file has been generated. And then ModuleB has been compiled using DCU information only without UNICODE symbol (or vice versa case - ModuleA.dcu generated as ANSI, and then there is an attempt to use it in Unicode ModuleB).

Will Delphi compiler always fail when compiling a module with such conditional-based type mismatch? With type keyword and without it? Is there any version specific behaviour?

As a bonus: I'm interested in the same for Free Pascal.


Solution

  • The compiler will fail to compile the program in that scenario. Both in Delphi and FPC.

    One way to think about it is to expand the conditional code. Once written that way it becomes much clearer what the compiler will do. And this is the right mental model because that is how the compiler processes conditional code. It simply does not see the code that is in conditional branches that are not active.

    Consider these two units:

    unit Unit1;
    // expanded with UNICODE defined
    
    interface
    
    type
      PASTR = type PAnsiChar;
      PWSTR = type PWideChar;
      PTSTR = PWSTR;
    
    implementation
    
    end.
    

    unit Unit2;
    // expanded with UNICODE undefined
    
    interface
    
    implementation
    
    uses
      Unit1;
    
    function FuncA(Arg: PASTR): Integer;
    begin
    end;
    
    function FuncW(Arg: PWSTR): Integer;
    begin
    end;
    
    function Func(Arg: PTSTR): Integer;
    begin
      Result := FuncA(Arg);
    end;
    
    end.
    

    The definition of PTSTR is found in Unit1 and it is an alias to PWSTR. Hence the call to FuncA will not compile.

    The use of type to make distinct types changes nothing either, because PAnsiChar and PWideChar are already incompatible.