Index: llvm/include/llvm/Support/Path.h =================================================================== --- llvm/include/llvm/Support/Path.h +++ llvm/include/llvm/Support/Path.h @@ -455,6 +455,32 @@ /// @result True if the path is absolute, false if it is not. bool is_absolute(const Twine &path, Style style = Style::native); +/// Is path GNU absolute? +/// +/// GNU absolute defines the following rules: +/// 1) Paths starting with a path separator are absolute. +/// 2) Windows style paths are also absolute if they start with a character +/// followed by ':'. +/// 3) No other paths are absolute. +/// +/// LLVM \ref is_absolute rules are different and defined as: +/// 1) Only paths with a root name and a root directory are absolute. +/// 2) No other paths are absolute. +/// +/// All paths on POSIX style are considered to have a root name. On Windows +/// style the path "C:\Users\Default" has "C:" as a root name and "\" as a root +/// directory. +/// +/// Hence "c:" on Windows which is considered absolute on GNU is not absolute +/// on LLVM because it has no root directory. Likewise "/" and "\" on Windows +/// are absolute on GNU and are not on LLVM due to missing root name. +/// +/// @param path Input path. +/// @param style The style of \p path (e.g. Windows or POSIX). "native" style +/// means to derive the style from the host. +/// @result True if the path is GNU absolute, false if it is not. +bool is_gnu_absolute(const Twine &path, Style style = Style::native); + /// Is path relative? /// /// @param path Input path. Index: llvm/lib/Support/Path.cpp =================================================================== --- llvm/lib/Support/Path.cpp +++ llvm/lib/Support/Path.cpp @@ -683,6 +683,25 @@ return rootDir && rootName; } +bool is_gnu_absolute(const Twine &path, Style style) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + // Handle '/' which is absolute on GNU for both Windows and POSIX systems. + // Handle '\\' on Windows. + if (!p.empty() && is_separator(p.front(), style)) + return true; + + if (real_style(style) == Style::windows) { + // Handle drive letter pattern (i.e "c:") and a character followed + // by ':' on Windows. + if (p.size() >= 2 && (p[0] && p[1] == ':')) + return true; + } + + return false; +} + bool is_relative(const Twine &path, Style style) { return !is_absolute(path, style); } Index: llvm/unittests/Support/Path.cpp =================================================================== --- llvm/unittests/Support/Path.cpp +++ llvm/unittests/Support/Path.cpp @@ -85,6 +85,23 @@ #endif } +TEST(is_gnu_absolute, Works) { + // Test tuple . + const SmallVector, 13> Paths = { + {"", false, false}, {"/", true, true}, {"/foo", true, true}, + {"\\", false, true}, {"\\foo", false, true}, {"foo", false, false}, + {"c", false, false}, {"c:", false, true}, {"c:\\", false, true}, + {"!:", false, true}, {"xx:", false, false}, {"c:abc\\", false, true}, + {":", false, false}}; + + for (const auto &Path : Paths) { + EXPECT_EQ(path::is_gnu_absolute(std::get<0>(Path), path::Style::posix), + std::get<1>(Path)); + EXPECT_EQ(path::is_gnu_absolute(std::get<0>(Path), path::Style::windows), + std::get<2>(Path)); + } +} + TEST(Support, Path) { SmallVector paths; paths.push_back(""); @@ -171,6 +188,7 @@ (void)path::has_extension(*i); (void)path::extension(*i); (void)path::is_absolute(*i); + (void)path::is_gnu_absolute(*i); (void)path::is_relative(*i); SmallString<128> temp_store;