Fix issue 19058 - __traits(getUnitTests) works again with separate co…#8542
Fix issue 19058 - __traits(getUnitTests) works again with separate co…#8542MartinNowak merged 4 commits intodlang:stablefrom
Conversation
|
Thanks for your pull request and interest in making D better, @atilaneves! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub fetch digger
dub run digger -- build "stable + dmd#8542" |
520fa2c to
6017634
Compare
Try using I just rebased this to stable for you ;-) |
|
I did Anyway, the semaphore and buildkite failures are due to stable/master differences (I got that locally) between dmd and druntime. If druntime is at master and dmd at stable... this error occurs. It doesn't if druntime is also on stable. I don't know how these CI pipelines are set up. My old PR for this fix just passed on master, and the errors are nowhere near any files I touched. DAutoTest seems to be entering a pathological dub dependency graph that has nothing to do with this either. |
|
I'd rather get this merged to master and miss dmd 2.081.2 than deal with buildkite and semaphoreci failing for no good reason. |
| { | ||
| if(*ptr == '/' || *ptr == '\\' || *ptr == '.' || *ptr == '?' || *ptr == ':') | ||
| *ptr = '_'; | ||
| } |
There was a problem hiding this comment.
Can the linker (or any other tools that deal with mangled symbols) handle these symbols? I'm asking because of the comment and why demangle isn't updated instead.
There was a problem hiding this comment.
I don't know if the linker can handle it. Maybe updating demangle is a good idea, but even if it is it's not the responsibility of this PR to handle that.
Similar code existed before in the long chain of bug fixes mentioned in the comments.
src/dmd/identifier.d
Outdated
| // are compiled separately. See issues | ||
| // 16995, 18097, 18111, 18880, 18868, 19058. | ||
| OutBuffer fullPathIdBuf; | ||
| if(absPath) |
There was a problem hiding this comment.
Space between if/for/while etc. and the opening parenthesis.
src/dmd/identifier.d
Outdated
| uint counter = 1; | ||
|
|
||
| // loop until we can't find the absolute path ~ identifier, adding a counter suffix each time | ||
| while (fullPathStringTable.lookup(fullPathIdBuf.peekSlice().ptr, fullPathIdBuf.peekSlice().length) !is null) |
There was a problem hiding this comment.
Please add a const(char)[] overload to lookup.
There was a problem hiding this comment.
I thought about it, but again, PRs are supposed to be focused. I only made the changes to filename.d because I had to.
There was a problem hiding this comment.
We should avoid adding new code that uses C strings or passing pointer and length separately. We're trying to improve the code, not digging the hole deeper we are already in.
In this case it's very simple to add an overload that forwards to the existing method. Even if the actual implementation isn't using a D string it will reduce the surface of where C string are used.
There was a problem hiding this comment.
I agree that it's simple. I agree that it makes the code better. I agree that it should be done. However, it goes against what dlang-bot posted above: "My PR is as minimal as possible".
It also makes the code better to localise imports, yet in this same review you asked me to delete them.
I'm trying to fix a bug, not change the interface to StringTable.
Feel free to submit a PR that adds slice overloads.
There was a problem hiding this comment.
I've already submitted a PR that adds those overloads #8547.
There was a problem hiding this comment.
An overload taking const(char)[] has been added and merged. Please rebase and use the new overload.
There was a problem hiding this comment.
It's been merged to master, this is targeting stable.
There was a problem hiding this comment.
Master has been merged into stable now https://github.com/dlang/dmd/blob/stable/src/dmd/root/stringtable.d#L127.
src/dmd/identifier.d
Outdated
| const idStartIndex = fullPathIdLength - idBuf.peekSlice().length; | ||
|
|
||
| // Remember the full path identifier to avoid possible future collisions | ||
| fullPathStringTable.insert(fullPathIdBuf.peekString(), |
There was a problem hiding this comment.
Same here, add an overload for insert taking const(char)[].
There was a problem hiding this comment.
Same reply as the previous comment.
There was a problem hiding this comment.
An overload taking const(char)[] has been added and merged. Please rebase and use the new overload.
src/dmd/identifier.d
Outdated
| identifiers per module. See generateIdWithLoc and issues | ||
| 16995, 18097, 18111, 18880, 18868, 19058 | ||
| */ | ||
| private extern (C++) static __gshared StringTable fullPathStringTable; |
There was a problem hiding this comment.
If this is private there shouldn't be a reason for it being extern(C++).
There was a problem hiding this comment.
I don't know why the other one is. Maybe because of the backend. Speaking of which, I need to add this to the .h file.
I'm following the existing pattern.
There was a problem hiding this comment.
I recommend not following existing patterns. We need to get rid of this cruft somehow.
There was a problem hiding this comment.
There are header files here for a reason. Unless they disappear, I think extern(C++) is the way to go.
There was a problem hiding this comment.
static and __gshared are redundant. Dscanner which is in master would have complained about this.
src/dmd/root/filename.d
Outdated
| */ | ||
| private int _mkdir(const(char)* path) nothrow | ||
| { | ||
| import core.sys.windows.winbase: CreateDirectoryW; |
There was a problem hiding this comment.
Why is this necessary?
There was a problem hiding this comment.
It isn't, but I copied the code around and it failed to compile because of the import. It was one my one concession to "do only what you must". I don't mind deleting it.
There was a problem hiding this comment.
Please do, it's already imported elsewhere.
src/dmd/root/filename.d
Outdated
| package auto extendedPathThen(alias F)(const(char*) path) | ||
| auto extendedPathThen(alias F)(const(char*) path) | ||
| { | ||
| import core.sys.windows.winbase: GetFullPathNameW; |
There was a problem hiding this comment.
Why is this necessary?
There was a problem hiding this comment.
Same reply as above.
src/dmd/root/filename.d
Outdated
| return F(absPath); | ||
| } | ||
|
|
||
| extern(C) char* realpath(const(char)* file_name, char* resolved_name) @nogc nothrow; |
There was a problem hiding this comment.
- Why not import this from druntime?
- This should be private
There was a problem hiding this comment.
- That didn't occur to me. I didn't even know importing from druntime was allowed in dmd.
- Agreed.
There was a problem hiding this comment.
That didn't occur to me. I didn't even know importing from druntime was allowed in dmd.
To get access the the C bindings it is. Phobos is not allowed though.
| * Takes a callable F and applies it to the result of converting | ||
| * `fileName` to an absolute file path (char*) | ||
| */ | ||
| auto absPathThen(alias F)(const(char)* fileName) |
There was a problem hiding this comment.
Can a const(char)[] parameter be used instead.
There was a problem hiding this comment.
That would complicate the code given that the Win32 API only deals in null-terminated strings.
There was a problem hiding this comment.
We would prefer all new functions have full DDoc headers including Params and Returns. Also see https://dlang.org/dstyle.html#phobos_documentation
There was a problem hiding this comment.
Although a const(char)[] parameter would complicate the code, that complication would be encapsulated in this function, and that's good IMO.
There was a problem hiding this comment.
Loc.filename isn't char[], it's const(char)*. That would require a lot of conversions. const(char)* is used all over the codebase from the time it was written in C++. Converting const(char)* to char[] back to a C string for both the Windows and Posix APIs doesn't make much sense to me.
I'm trying to fix a bug, not refactor dmd. Yes, one should refactor as one goes, but C strings are so pervasive right now I'd need dozens of PRs just to get to the point that I can fix this regression, which seriously affects my workflow and is stopping us from upgrading the compiler version at work.
| scope (exit) | ||
| { | ||
| if (multibyteBuf != &buf[0]) | ||
| free(multibyteBuf); |
There was a problem hiding this comment.
Is there anything preventing the parameter to F from escaping?
There was a problem hiding this comment.
I changed auto to scope.
6017634 to
20234cd
Compare
Fix for Buildkite: dlang/ci#271
Yeah sadly that one is known :/
Fair enough, but keep in mind that the master-stable branch-off will happen around 15.8 (i.e. in one week). So if this hasn't been merged by then, you might need to rebase to stable again if you want this to be part of 2.082. Sorry for the CI annoyances here :/ |
20234cd to
4787f3f
Compare
|
I hope it gets merged soon but that's out of my control. It is a regression fix though... |
4787f3f to
9be2380
Compare
Fix: #8560 |
9be2380 to
45942c8
Compare
|
Green and ready to go. |
45942c8 to
e75fd78
Compare
src/dmd/root/filename.d
Outdated
| * Params: | ||
| * fileName: The file name to be converted to an absolute path | ||
| * Returns: Whatever `F` returns. | ||
| */ |
There was a problem hiding this comment.
Please remove the "*" prefix, and put a newline above "Params" and "Returns". See the example at https://dlang.org/dstyle.html#phobos_documentation
test/runnable/issue16995.d
Outdated
| { | ||
| import module_with_tests; | ||
| foreach(i, ut; __traits(getUnitTests, module_with_tests)) { | ||
| foreach(i, ut; __traits(getUnitTests, imports.module_with_tests)) { |
There was a problem hiding this comment.
We prefer consistent coding conventions even in the tests. i.e. { on a new line.
test/runnable/issue16995.d
Outdated
| } | ||
| } | ||
|
|
||
| foreach(i, ut; __traits(getUnitTests, imports.another_module_with_tests)) { |
There was a problem hiding this comment.
{ curly brace on new line.
Sorry, my fault. Should be fixed now. I restarted the build. |
|
I'd be happy to see a solution that could also be applied to 14894 – mangling of mixins and lambdas is not unique and depends on compilation flags, basically the same problem. Including absolute paths in mangling has a quite a smell (and also bloats symbols sizes, though that's less important for debug builds). It would likely break hard-linked folders and copies of sources (vendored folders). As you already said yourself, module names should be unique already (https://forum.dlang.org/post/krkinfxikztqvudjopao@forum.dlang.org). Also I'm not sure that we need to support lookup of unittests by their symbol name (hence they start with Overall we probably should spent more time on this and fix it once and for all, and at best also the similar problem with mixins and lambdas. Short summary of the suffix approaches and their problems: At least for unittests the suggested line/column number + counter on collision approach might be worth a second thought. If the importer can already see a unittest, why wouldn't it see all the other ones at the same loc/col? |
That's great, but that's not what this PR is about. It's about fixing 19058. It's hard enough to keep things focussed as it is.
This isn't what this PR does. It includes the absolute path iff there's a collision. Notice that none of the Phobos tests that check for error messages that print out unittest names had to be changed. And they didn't have to be changed because the absolute path isn't part of the symbol. Imagine having to write tests so that the absolute paths were part of the symbol that didn't depend on the filesystem layout of the autotester - it wouldn't be fun.
I also said that modules aren't available until semantic, which is far too late to generate the identifier, which was the cause of some of the bugs referenced in the comments of this PR. Without completely restructuring dmd, I don't see how these multiple issues can be solved simultaneously.
That wasn't the problem in that bug. It was the fact that linking failed after trying to get a reference to a unittest function. The included implementation-defined names were used as an illustration. There's nothing weird at all in trying to get a reference to a unittest function without using the actual identifier.
And, in the meanwhile, this bug has completely broken my workflow and is currently preventing us from upgrading the dmd version at work - we're still stuck on 2.080.1 on the figurative eve of the release of 2.082.0. This bug is not a detail. It's a regression blocking us at work. It breaks legitimate uses of the language's functionality and is currently taking a major vesion bump of 2 (or 3 or more if this carries on long enough) to get fixed despite a small PR with a fix that passes all tests.
This demonstrably does not, and cannot, work. It's literally the "fix" that caused this regression in the first place. The counter would need to be per module, and modules don't exist yet when the identifier is generated. |
|
Would it be possible to change or set the identifier later? I mean, we do have anonymous functions. |
|
@jacob-carlborg No, we can't set the identifier later. That's what I did in my original fix exactly as a suggestion from @klickverbot because lambdas are done that way, and it ended up causing issue 18097. There's a long list of issues related to this, which I chronicled in the already mentioned blog post where I asked for ideas to solve this problem. The laundry list of issues is also in the diffs of this PR. This fix works. This fix is small. This fix doesn't affect the vast majority of symbols. I've considered this every which way I can, asked for help, and nobody has come up with a better idea that also works. I don't understand why this hasn't been merged yet. Did I mention this is a work-blocking regression? |
|
@wilzbach The buildkite failure looks suspicious. Any ideas? |
|
It was broken last night but is fixed now. Retriggering the build did the trick. |
I proposed including the (unique) file path as replacement for the missing module. Isn't that enough? Edit: After a quick glance, this seems to be more or less how I imagined it. Lgtm. |
src/dmd/root/filename.d
Outdated
|
|
||
| if(!length) return F((char*).init); | ||
|
|
||
| char[1024] buf; |
There was a problem hiding this comment.
It's a minor optimization. No need to default-initialize it if you're just going to overwrite it.
|
|
||
| fullPathIdBuf.writestring(idBuf.peekSlice()); | ||
| const fullPathIdLength = fullPathIdBuf.peekSlice().length; | ||
| uint counter = 1; |
There was a problem hiding this comment.
I think the counter/StringTable could be simplified and possibly accelerated/requiring less memory via __gshared uint[string][Loc] counters, indexed by counters[loc][prefix]; checking if there's an existing entry and incrementing/setting it to 1 when done. I might give that a try as a follow-up.
31c4894 to
3a686c0
Compare
|
I'm going on holiday today. I'm not going to reply to anything until I'm back on the 12th of September. |
|
I would like to merge this before the next release. If there are any objections, please make them known soon. If there are no show-stoppers, but you have some recommended changes, let's do them as followups. |
What fails with 2.077.0 is |
Rework #8542 wrt. deterministic IDs via generateIdWithLoc() merged-on-behalf-of: Nicholas Wilson <thewilsonator@users.noreply.github.com>
I tried creating the PR to
stableinstead ofmasterbut for reasons I don't understand a whole lot of commits came along with it. And yes, I'd rebased toupstream/stable.