Bug 21537 – Pointer to function pointer cannot be converted to pointer to const function pointer with lower attributes

Status
REOPENED
Severity
normal
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-01-09T19:20:48Z
Last change time
2024-12-13T19:13:58Z
Keywords
rejects-valid
Assigned to
No Owner
Creator
Bolpat
Moved to GitHub: dmd#18016 →

Comments

Comment #0 by qs.il.paperinik — 2021-01-09T19:20:48Z
A function pointer with attributes such as @safe cannot be referenced by a const @system function pointer type: alias SysFP = void function(); alias SafeFP = void function() @safe; void g(const(SysFP)*) { } SafeFP safeFp = { }; g(&safeFp); // fails The same works perfectly when you s/function/delegate the types. This snipped gives you the full picture, also a comparison with delegates and class inheritance: https://run.dlang.io/is/zSNArx
Comment #1 by qs.il.paperinik — 2021-01-09T19:27:34Z
Related: interface I { void f(const(void function() @safe)* fpp) @safe; void g(const(void delegate() @safe)* dgp) @safe; } class C : I { override void f(const(void function())* fpp) @safe { } // error (unexpected) override void g(const(void delegate())* fpp) @safe { } // okay (expected) }
Comment #2 by moonlightsentinel — 2021-11-05T20:22:51Z
The premise of this bug report is wrong, it passes a_pointer_ to a function pointer instead of the function pointer. This fails because pointer conversions are only allowed if the pointee is const-convertible to the target. This is could be replaced by an enhancement request to make an exception for attribute changes in function pointers. But that would be an odd special case. The interface example is a duplicate of 21538
Comment #3 by qs.il.paperinik — 2021-11-22T14:16:16Z
> The premise of this bug report is wrong, it passes a_pointer_ to a function pointer instead of the function pointer. How is a pointer to a function pointer morally different from a pointer to a delegate or a pointer to a class object reference? If types T and S have a subtyping relationship like T ⊆ S, then const(T)* ⊆ const(S)*; at least, this is the case when T and S are class types or when T and S are delegate types, but fails when T and S are function pointer types.
Comment #4 by moonlightsentinel — 2021-11-22T14:41:53Z
(In reply to Bolpat from comment #3) > How is a pointer to a function pointer morally different from a pointer to a > delegate or a pointer to a class object reference? It isn't. > If types T and S have a subtyping relationship like T ⊆ S, then const(T)* ⊆ > const(S)*; at least, this is the case when T and S are class types or when T > and S are delegate types, but fails when T and S are function pointer types. No, such implicit conversion for pointer are already rejected: class A {} class B : A {} alias SysFP = void function(); alias SafeFP = void function() @safe; alias SysDG = void delegate(); alias SafeDG = void delegate() @safe; void main() { { A a; B b; a = b; // Fine }{ A* ap; B* bp; ap = bp; // Error: cannot implicitly convert expression `bp` of type `B*` to `A*` }{ SafeFP safeFp; SysFP sysFp; sysFp = safeFp; // Fine }{ SafeFP* safeFpPtr; SysFP* sysFpPtr; sysFpPtr = safeFpPtr; // Error: cannot implicitly convert expression `safeFpPtr` of type `void function() @safe*` to `void function()*` }{ SafeDG safeDg; SysDG sysDg; sysDg = safeDg; // Fine }{ SafeDG* safeDgPtr; SysDG* sysDgPtr; sysDgPtr = safeDgPtr; // Error: cannot implicitly convert expression `safeDgPtr` of type `void delegate() @safe*` to `void delegate()*` } }
Comment #5 by qs.il.paperinik — 2021-11-27T01:54:27Z
(In reply to moonlightsentinel from comment #4) > (In reply to Bolpat from comment #3) > > How is a pointer to a function pointer morally different from a pointer to a > > delegate or a pointer to a class object reference? > > It isn't. > > > If types T and S have a subtyping relationship like T ⊆ S, then const(T)* ⊆ > > const(S)*; at least, this is the case when T and S are class types or when T > > and S are delegate types, but fails when T and S are function pointer types. > > No, such implicit conversion for pointer are already rejected: > > [code] Of course, if you don't use const, the conversion is not safe. But I did. I checked it again if I missed it at some point by accident, but at a quick glance I couldn't find a spot. (Even if there is one, the overall use of const makes clear what I'm talking about.) Your example demonstrates conversation to a pointer a mutable supertype object, but the bug report is about pointers to a const supertype object. Neither of us is wrong, but we're talking about slightly, but meaningfully different things. The code you posted is rejected and for good reasons, but it does not invalidate the bug report.
Comment #6 by moonlightsentinel — 2021-11-27T14:31:55Z
Right, I've fixed the example. Conversions including const class references are accepted but both conversion including FP and delegates are rejected on nightly: For reference: class A {} class B : A {} alias SysFP = void function(); alias SafeFP = void function() @safe; alias SysDG = void delegate(); alias SafeDG = void delegate() @safe; void main() { { A a; B b; a = b; // Fine }{ const(A)* ap; const(B)* bp; ap = bp; // Accepted }{ SafeFP safeFp; SysFP sysFp; sysFp = safeFp; // Fine }{ const(SafeFP)* safeFpPtr; const(SysFP)* sysFpPtr; sysFpPtr = safeFpPtr; // Error: cannot implicitly convert expression `safeFpPtr` of type `const(void function() @safe)*` to `const(void function())*` }{ SafeDG safeDg; SysDG sysDg; sysDg = safeDg; // Fine }{ const(SafeDG)* safeDgPtr; const(SysDG)* sysDgPtr; sysDgPtr = safeDgPtr; // Error: cannot implicitly convert expression `safeDgPtr` of type `const(void delegate() @safe)*` to `const(void delegate())*` } }
Comment #7 by qs.il.paperinik — 2021-12-07T19:15:19Z
(In reply to moonlightsentinel from comment #6) > For reference: > > // Error: cannot implicitly convert expression > `safeDgPtr` of type `const(void delegate() @safe)*` to `const(void > delegate())*` Seems like it's become a regression, too. Compiling the code linked obove (https://run.dlang.io/is/zSNArx) with all DMDs gives: 2.079.1 to 2.095.1: Failure with output: ----- onlineapp.d(69): Error: function `onlineapp.FunctionPtrContext.g(const(void function())* _param_0)` is not callable using argument types `(void function() @safe*)` onlineapp.d(69): cannot pass argument `& safeFp` of type `void function() @safe*` to parameter `const(void function())* _param_0` ----- Since 2.096.1: Failure with output: ----- onlineapp.d(45): Error: function `onlineapp.DelegateContext.g(const(void delegate())* _param_0)` is not callable using argument types `(void delegate() @safe*)` onlineapp.d(45): cannot pass argument `& safeDG` of type `void delegate() @safe*` to parameter `const(void delegate())* _param_0` onlineapp.d(69): Error: function `onlineapp.FunctionPtrContext.g(const(void function())* _param_0)` is not callable using argument types `(void function() @safe*)` onlineapp.d(69): cannot pass argument `& safeFp` of type `void function() @safe*` to parameter `const(void function())* _param_0` ----- 2.079.1 to 2.095.1 has no problem with the delegates.
Comment #8 by robert.schadek — 2024-12-13T19:13:58Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18016 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB