diff --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h --- a/llvm/include/llvm/Support/Path.h +++ b/llvm/include/llvm/Support/Path.h @@ -455,6 +455,22 @@ /// @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 style absolute? +/// +/// LLVM \ref is_absolute matches C++17 behavior that essentially says that +/// the path must be unambiguous (i.e. that there must be a drive letter for +/// Windows). However GNU tools treat a path as absolute with or without the +/// drive letter. +/// +/// GNU style absolute define that: +/// 1) Paths starting with '/' are always absolute; +/// 2) On Windows, paths starting with '\\' are absolute; +/// 3) On Windows, paths starting with drive letter pattern are absolute. +/// +/// @param path Input path. +/// @result True if the path is GNU style absolute, false if it is not. +bool is_gnu_style_absolute(const Twine &path, Style style = Style::native); + /// Is path relative? /// /// @param path Input path. diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -687,6 +687,27 @@ return !is_absolute(path, style); } +bool is_gnu_style_absolute(const Twine &Path, Style Style) { + SmallString<128> PathStorage; + StringRef P = Path.toStringRef(PathStorage); + + // Handle '/' which should be true regardless Windows or POSIX. + if (!P.empty() && is_separator(P.front(), Style::posix)) + return true; + + if (real_style(Style) == Style::windows) { + // Handle '\\' on Windows. + if (!P.empty() && is_separator(P.front(), Style::windows)) + return true; + + // Handle drive letter pattern (i.e "c:") on Windows. + if (P.size() >= 2 && (P[0] && P[1] == ':')) + return true; + } + + return false; +} + StringRef remove_leading_dotslash(StringRef Path, Style style) { // Remove leading "./" (or ".//" or "././" etc.) while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) { diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -85,6 +85,25 @@ #endif } +TEST(is_gnu_style_absolute, Works) { + // Test tuple . + SmallVector, 5> Paths; + Paths.emplace_back("", false, false); + Paths.emplace_back("/", true, true); + Paths.emplace_back("\\", false, true); + Paths.emplace_back("foo", false, false); + Paths.emplace_back("c:", false, true); + + for (auto &Path : Paths) { + EXPECT_EQ( + path::is_gnu_style_absolute(std::get<0>(Path), path::Style::posix), + std::get<1>(Path)); + EXPECT_EQ( + path::is_gnu_style_absolute(std::get<0>(Path), path::Style::windows), + std::get<2>(Path)); + } +} + TEST(Support, Path) { SmallVector paths; paths.push_back(""); @@ -171,6 +190,7 @@ (void)path::has_extension(*i); (void)path::extension(*i); (void)path::is_absolute(*i); + (void)path::is_gnu_style_absolute(*i); (void)path::is_relative(*i); SmallString<128> temp_store;