Bug 23907 – __traits(child) respects visibility

Status
NEW
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-05-08T16:31:32Z
Last change time
2024-12-13T19:28:47Z
Keywords
rejects-valid
Assigned to
No Owner
Creator
Bolpat
Moved to GitHub: dmd#20276 →

Comments

Comment #0 by qs.il.paperinik — 2023-05-08T16:31:32Z
The `child` trait is a reflection tool. It should **not** respect visibility (in the second parameter, i.e. the alias of a member function). If respecting visibility is desired, `getVisibility` can be used. This is consistent with other reflection traits, the reason being that a library that uses reflection may be passed a private symbol in the module in which it is defined. Visibility is (correctly) bypassed when the address of the expression is taken. Example (suitable for run.dlang.io): ```d --- a.d module a; struct S { private void f(int i) { import std.stdio; writeln("S.f(", i, ")"); } } alias publicAlias = S.f; --- playground.d #line 17 "playground.d" import a; void main() { S s; s.f(0); // okay: fails because `f` is private __traits(child, s, publicAlias)(42); // bug: fails (&__traits(child, s, publicAlias))(42); // okay } ```d
Comment #1 by razvan.nitu1305 — 2023-05-09T11:33:17Z
> This is consistent with other reflection traits Which ones? I tried getMember and that doesn't bypass private. I would argue that this is intended behavior and if the opposite occurs for other traits then that is the bug.
Comment #2 by qs.il.paperinik — 2023-05-09T15:37:33Z
> I would argue that this is intended behavior and if the opposite occurs for other traits then that is the bug. I strongly disagree. If you were right, that would mean that you cannot e.g. create a serialization library that can serialize private data members. A module could reasonably pass a private symbol as an argument to an `alias` parameter of a template imported from another module. That template should be able to do its job, regardless whether the symbol is private. > Which ones? * `getProtection` for a trivial one. * `getOverloads` allows accessing private overloads in a private aggregate * `hasMember` and `allMembers` returns/lists private members * `hasCopyConstructor` does not fail if the argument is an alias to a private struct I didn’t check all of them, just a sample. > I tried `getMember` and that doesn't bypass private. I have no idea what you tried, but in my tests, it does. Here is what I tried (suitable for run.dlang.io): ```d --- a.d #line 3 "a.d" private struct _S { private int x; private void f() @safe {} private static int f(int x) @safe pure => x; } // only way to access anything in this module: alias S = _S; --- playground.d #line 16 "playground.d" import a; void main() { S s; static foreach (ov; __traits(getOverloads, s, "f")) { static if (is(typeof(ov(0)))) { ov(0); } } static assert(__traits(hasMember, S, "f")); static assert(__traits(hasMember, s, "f")); static assert(!__traits(compiles, s.x = 2 )); // x is private __traits(getMember, s, "x") = 2; static assert(!__traits(compiles, assert(s.x == 2) )); // x is private assert(__traits(getMember, s, "x") == 2); static assert(__traits(getProtection, S) == "private"); static assert(__traits(getProtection, __traits(getMember, s, "x")) == "private"); } ```
Comment #3 by robert.schadek — 2024-12-13T19:28:47Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/20276 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB