I stumbled upon different behavior of std::filesystem::path::parent_path() when a path contains leading slashes. Clang says that the parent of ///a is /// (which is what I would expect), but GCC says that the parent is / (that is, it strips the extra slashes). At the same time, GCC does not strip the slashes from the path /// (i.e. the parent of /// is ///).
Is this an acceptable behavior, or a GCC bug?
The code:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
for (fs::path p : {"///", "///a"})
std::cout
<< p
<< "\nparent: " << p.parent_path()
<< "\nbegin: " << *p.begin()
<< "\nroot_dir: " << p.root_directory()
<< "\n\n";
}
GCC 16 output:
"///"
parent: "///"
begin: "///"
root_dir: "/"
"///a"
parent: "/" <- ???
begin: "/"
root_dir: "/"
Clang 22 output:
"///"
parent: "///"
begin: "/"
root_dir: "/"
"///a"
parent: "///" <- OK
begin: "/"
root_dir: "/"
I tried reading the draft of the standard, where parent_path() is documented to return a path whose generic format pathname is the longest prefix of the generic format pathname of *this that produces one fewer element in its iteration., but the iteration confuses me even more. The thing is, the path iterators are documented to return the root name first (does not exist in the examples above), and then the root directory. As you can see in the above, root_directory() is / everywhere and is equal to begin() in all cases except for the /// path in GCC, where begin() is ///. In this case, GCC seems to agree with the standard (as I understand it) as the first element of the iteration is always equal to the root directory, while Clang now strips the extra slashes from the first element.
///is equivalent to/, so///usrand/usrare equivalent (e.g. refer to the same directory). From that perspective, both gcc and clang's approach are "acceptable" - they still resolve as the same path.