Fix issue 17394 - mkdirRecurse isn't @safe#5386
Conversation
std/file.d
Outdated
| if (isConvertibleToString!R) | ||
| { | ||
| return mkdirRecurse!(StringTypeOf!R)(pathname); | ||
| } |
There was a problem hiding this comment.
mkdir accepts auto ref, so I guessed that it was probably an oversight that mkdirRecurse doesn't?
There was a problem hiding this comment.
mkdirRecurse accepted a char array only - not much point for auto ref there
There was a problem hiding this comment.
Well there's the following API for mkdir:
void mkdir(R)(auto ref R pathname)
if (isConvertibleToString!R)
{
return mkdir!(StringTypeOf!R)(pathname);
}|
|
||
| immutable basepath = deleteme ~ "_dir"; | ||
| scope(exit) rmdirRecurse(basepath); | ||
| scope(exit) () @trusted { rmdirRecurse(basepath); }(); |
There was a problem hiding this comment.
This was done to keep this PR small and go in steady baby steps
std/file.d
Outdated
| void mkdirRecurse(in char[] pathname) | ||
| void mkdirRecurse(R)(R pathname) | ||
| if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && | ||
| !isConvertibleToString!R) |
There was a problem hiding this comment.
mkdirRecurse accepts an arbitrary range then tries to call ensureDirExists which accepts only in char[]. ensureDirExists thus either needs to be changed to accept a range or mkdirRecurse's signature change undone.
There was a problem hiding this comment.
Oh good catch! I went with changing ensureDirExists, but I don't have a strong feeling about this.
std/file.d
Outdated
| version(Windows) | ||
| { | ||
| if (CreateDirectoryW(pathname.tempCStringW(), null)) | ||
| if (() @trusted { return CreateDirectoryW(pathname.tempCStringW(), null); }()) |
There was a problem hiding this comment.
in mkdir static @trusted functions are used:
static auto trustedCreateDirectoryW(const(FSChar)* pathz) @trusted
{
return CreateDirectoryW(pathz, null);
}I like the temporary lambdas more, but AFAIK they do create an overhead. Does by chance anyone know whether this overhead is negligible after optimization?
There was a problem hiding this comment.
Doesn't matter as long as they don't create garbage.
There was a problem hiding this comment.
Does by chance anyone know whether this overhead is negligible after optimization?
Depends on the in-liner. Chances are DMD won't in-line this, but I wouldn't change this, as optimizing for DMD's in-liner is a deep rabbit hole we don't want to go down.
There was a problem hiding this comment.
I'm a bit uneasy on this, as you are trusting the pathname's range operations when you do tempCStringW (as well as assuming the range doesn't have such a member name and you aren't calling the wrong thing). Is it possible to do this outside the trusted lambda?
There was a problem hiding this comment.
mkdir does auto pathz = pathname.tempCString!FSChar();, same could be done here
std/file.d
Outdated
| private bool ensureDirExists(in char[] pathname) | ||
| private bool ensureDirExists(R)(R pathname) | ||
| if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && | ||
| !isConvertibleToString!R) |
There was a problem hiding this comment.
I don't think you want !isConvertibleToString!R as unlike mkdir there is no overload with if(isConvertibleToString!R).
std/file.d
Outdated
| import std.conv : octal; | ||
|
|
||
| if (core.sys.posix.sys.stat.mkdir(pathname.tempCString(), octal!777) == 0) | ||
| if (() @trusted { return core.sys.posix.sys.stat.mkdir(pathname.tempCString(), octal!777); }() == 0) |
There was a problem hiding this comment.
Same thing here, try and make the tempCString outside the lambda.
7fe771e to
e50531d
Compare
|
I removed the API unification to avoid any controversial issues - the unification between |
|
Thanks, LGTM. |
std/file.d
Outdated
| */ | ||
|
|
||
| void mkdirRecurse(in char[] pathname) | ||
| void mkdirRecurse()(in char[] pathname) |
There was a problem hiding this comment.
Why did this become a template? Templatizing things increases user code compilation times and is, strictly speaking, a breaking API change, so shouldn't be done without good reason.
There was a problem hiding this comment.
It will need to become a template anyway to accept arbitrary char ranges as all the other stuff in std.file.
There was a problem hiding this comment.
YAGNI for now and change it once it's actually required? If you are happy with the change, feel free to merge, though.
There was a problem hiding this comment.
@klickverbot This can't be merged with your request for changes still pending
There was a problem hiding this comment.
There was a problem hiding this comment.
@klickverbot the other option is to manually add the attributes, and then remove them all later when we change to a range interface. Neither path is super-appealing.
Can you explain why this is a breaking API change?
There was a problem hiding this comment.
The first thing that comes to mind is that you can't take its address anymore. When it's not a template, the function name can be used on its own, but once it is, it has to be instantiated. When calling it, that's not a big deal, because IFTI takes care of the instantiation for you, but for other cases, it has to be done manually.
Of course, even changing a single attribute is an API change, so we're actually really terrible in general about maintaining API compatibility. We usually do a fairly good job with avoiding breaking the common cases, but we frequently break the corner cases.
There was a problem hiding this comment.
Of course, even changing a single attribute is an API change
Being pedantic here, but isn't adding something like nothrow an ABI and not an API change?
There was a problem hiding this comment.
I suppose that that depends on whether it affects who can call the code if it's recompiled rather than simply linked. I don't know. I tend to think of the API as being anything in the function signature, whereas the ABI has to do with the resulting binary, and changing the attributes changes the function signature.
Regardless, we routinely make changes that break compatibility in small ways, and the way that D is designed (particularly with attribute inference), you'd have to be pretty disciplined about it to never break any code with changes.
|
@wilzbach I just removed the template for now. In the next go-around when you want to add range support, just remove the |
There are a lot of lot hanging fruits in
std.fileand in general imho we should invest a lot more work in making Phobos work nicely with@safebecause currently it's really an empty promise as every second standard library function needs to be@trusted...