I can confirm, that it is not an issue of preconditions and in my opinion GCC is right, but my guess is, that clarification of the standard on that point would be helpful.
For a long time it is quite common usage pattern to mark directories with a trailing separator, to distinguish them from files. And I would expect an implementation of std::filesystem::create_directories
to return true if a path about to be created is not existing before the call, and exists after the call, as a result of the call.
Let's extend the example a little bit:
#include <filesystem>
#include <iostream>
#include <system_error>
int main() {
std::error_code ec;
std::cout << std::boolalpha << std::filesystem::exists("a/b/c/") << "/";
std::cout << std::filesystem::create_directories("a/b/c/", ec) << "/";
std::cout << !!ec << "/" << std::filesystem::exists("a/b/c/");
}
Now we can use godbolt: https://godbolt.org/z/5883uY
And it shows for GCC/libstdc++ false/true/false/true
as we would expect, it doesn't exist, it was created by the create_directories
call, there was no error and it exists after that.
Now clang/libc++ results in false/false/false/true
, so it didn't exists, it tells us it didn't create it, but it did, there is no error, and we have prove after the call.
Looking into the github version of MSVC stl, it looks like it calls CreateDirectoryW
with: a
, a\b
, a\b\c
and finally a\b\c\
, and that last one reports ERROR_ALREADY_EXISTS
, which leads to the return of false
as it seemed we didn't do anything, but I think that is an implementation detail bleeding out of the function.
My guess is, the Clang code works similar, but I didn't check the libc++ source yet.
And the standard reads: "Returns: true if a new directory was created, otherwise false. The signature with argument ec returns false if an error occurs."
So the standard wants true
if a directory was created, not the last one, and for the ec variant false
signals an error, yet clang tells us via ec
there was none.
I might still be wrong, as I'm not in any WG, but my conclusion: GCC is right, and it seems like a bug in MSVC and Clang.
As I already collected discrepancies between the implementations while verifying my own one, I'll "happily" add this one to my collection, if that's okay.
Update: I just dug into the other sources and Clang/libc++ works with a recursive parent_path()
based mechanism that in the end leads to the same sequence like MSVC where the last ::mkdir("a/b/c/")
was preceded by a ::mkdir("a/b/c")
so it reports false as it assumes it didn't create the directories.