Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

E2010 Incompatible Types, why?

I'm getting this error:

[DCC Error] JwaStrSafe.pas(2277): E2010 Incompatible types: 'PSTRSAFE_LPWSTR' and 'PSTRSAFE_LPTSTR'

The following is the relevant portion of code from JwaStrSafe.pas (from Jedi Api), I'm compiling with the symbol UNICODE defined:

type

STRSAFE_LPWSTR = PWIDECHAR;
PSTRSAFE_LPWSTR = ^STRSAFE_LPWSTR;

{$IFDEF UNICODE}
  STRSAFE_LPTSTR = STRSAFE_LPWSTR;
  PSTRSAFE_LPTSTR = ^STRSAFE_LPTSTR;
{$ELSE}
  ...
{$ENDIF}

...
//function declaration
function StringCchCopyExW(
  {__out_ecount(cchDest)}pszDest : STRSAFE_LPWSTR;
  {__in}cchDest : size_t;
  {__in}const pszSrc : STRSAFE_LPCWSTR;
  {__deref_opt_out_ecount(pcchRemaining^)}ppszDestEnd : PSTRSAFE_LPWSTR;
  {__out_opt}pcchRemaining : PSize_t;
  {__in}dwFlags : Cardinal) : HRESULT; stdcall; forward; external;

...
//var passed to function
ppszDestEnd : PSTRSAFE_LPTSTR;

...

{$IFDEF UNICODE}
  result := StringCchCopyExW(pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
{$ELSE}
  result := StringCchCopyExA(pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
{$ENDIF}

I get the error on the call of StringCchCopyExW, on parameter ppszDestEnd.

Looking at the type definition I understand that PSTRSAFE_LPTSTR is a pointer type to STRSAFE_LPTSTR which is just an alias of STRSAFE_LPWSTR, why are PSTRSAFE_LPTSTR and PSTRSAFE_LPWSTR incompatible?

Solution
Thanks to David's explanation I replaced

PSTRSAFE_LPTSTR = ^STRSAFE_LPTSTR;

with

PSTRSAFE_LPTSTR = PSTRSAFE_LPWSTR;

now the code compiles without errors.

Thanks

like image 977
Paolo Biondi Avatar asked Dec 01 '11 22:12

Paolo Biondi


1 Answers

I can reproduce this easily enough in XE2, and I imagine it will behave the same in all other versions. To make it simpler I've cut it down to this:

program PointerTypeCompatibility;
{$APPTYPE CONSOLE}
type
  A = Integer;
  B = Integer;
var
  ptA: ^A;
  ptB: ^B;
begin
  ptA := ptB;
end.

This also produces E2010. However, if you enable the type-checked pointers option, then the code compiles successfully. In fact the documentation of that compiler options states:

In the {$T-} state, distinct pointer types other than Pointer are incompatible (even if they are pointers to the same type). In the {$T+} state, pointers to the same type are compatible.


Thanks to Ken White for pointing me at the useful help topic Type Compatibility and Identity. The pertinent extracts are that types T1 and T2 are assignment compatible if:

T1 and T2 are compatible pointer types.

The documentation also states that types are type compatibile if:

Both types are (typed) pointers to the same type and the {$T+} compiler directive is in effect.

So this documents the observed behaviour and leads me to this example:

program PointerTypeCompatibilityTake2;
{$APPTYPE CONSOLE}
{$TYPEDADDRESS OFF}
var
  P1,P2: ^Integer;
  P3: ^Integer;
begin
  P1 := P2;//compiles
  P1 := P3;//E2008 Incompatible types
end.

So, to summarise:

  • When type-checked pointers is disabled, pointers are assignment compatible if the pointers are of the same type.
  • When type-checked pointers is enabled, pointers are assignment compatible if the pointers point to the the same type.

I have to confess to being ignorant of the history and reasoning behind the type-checked pointer setting, so I can't offer any explanation for why the compiler is the way it is.

like image 54
David Heffernan Avatar answered Nov 13 '22 08:11

David Heffernan