Make -Wnonportable-include-path ignore drive case on Windows.

See PR45812 for motivation.

No explicit test since I couldn't figure out how to get the
current disk drive in lower case into a form in lit where I could
mkdir it and cd to it. But the change does have test coverage in
that I can remove the case normalization in lit, and tests failed
on several bots (and for me locally if in a pwd with a lower-case
drive) without that normalization prior to this change.

Differential Revision: https://reviews.llvm.org/D79531
This commit is contained in:
Nico Weber
2020-05-06 20:19:14 -04:00
parent ed86058b53
commit d03838343f
3 changed files with 55 additions and 5 deletions

View File

@@ -2074,6 +2074,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
if (Callbacks && !IsImportDecl) {
// Notify the callback object that we've seen an inclusion directive.
// FIXME: Use a different callback for a pp-import?
// FIXME: Passes wrong filename if LookupHeaderIncludeOrImport() did
// typo correction.
Callbacks->InclusionDirective(
HashLoc, IncludeTok, LookupFilename, isAngled, FilenameRange,
File ? &File->getFileEntry() : nullptr, SearchPath, RelativePath,
@@ -2100,10 +2102,41 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
!IsMapped && !File->getFileEntry().tryGetRealPathName().empty();
if (CheckIncludePathPortability) {
// FIXME: Looks at the wrong filename if we did typo correction.
StringRef Name = LookupFilename;
StringRef NameWithoriginalSlashes = Filename;
#if defined(_WIN32)
// Skip UNC prefix if present. (tryGetRealPathName() always
// returns a path with the prefix skipped.)
bool NameWasUNC = Name.consume_front("\\\\?\\");
NameWithoriginalSlashes.consume_front("\\\\?\\");
#endif
StringRef RealPathName = File->getFileEntry().tryGetRealPathName();
SmallVector<StringRef, 16> Components(llvm::sys::path::begin(Name),
llvm::sys::path::end(Name));
#if defined(_WIN32)
// -Wnonportable-include-path is designed to diagnose includes using
// case even on systems with a case-insensitive file system.
// On Windows, RealPathName always starts with an upper-case drive
// letter for absolute paths, but Name might start with either
// case depending on if `cd c:\foo` or `cd C:\foo` was used in the shell.
// ("foo" will always have on-disk case, no matter which case was
// used in the cd command). To not emit this warning solely for
// the drive letter, whose case is dependent on if `cd` is used
// with upper- or lower-case drive letters, always consider the
// given drive letter case as correct for the purpose of this warning.
SmallString<128> FixedDriveRealPath;
if (llvm::sys::path::is_absolute(Name) &&
llvm::sys::path::is_absolute(RealPathName) &&
toLowercase(Name[0]) == toLowercase(RealPathName[0]) &&
isLowercase(Name[0]) != isLowercase(RealPathName[0])) {
assert(Components.size() >= 3 && "should have drive, backslash, name");
assert(Components[0].size() == 2 && "should start with drive");
assert(Components[0][1] == ':' && "should have colon");
FixedDriveRealPath = (Name.substr(0, 1) + RealPathName.substr(1)).str();
RealPathName = FixedDriveRealPath;
}
#endif
if (trySimplifyPath(Components, RealPathName)) {
SmallString<128> Path;
@@ -2132,15 +2165,23 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
continue;
// Append the separator(s) the user used, or the close quote
if (Path.size() > Filename.size()) {
if (Path.size() > NameWithoriginalSlashes.size()) {
Path.push_back(isAngled ? '>' : '"');
continue;
}
assert(IsSep(Filename[Path.size()-1]));
assert(IsSep(NameWithoriginalSlashes[Path.size()-1]));
do
Path.push_back(Filename[Path.size()-1]);
while (Path.size() <= Filename.size() && IsSep(Filename[Path.size()-1]));
Path.push_back(NameWithoriginalSlashes[Path.size()-1]);
while (Path.size() <= NameWithoriginalSlashes.size() &&
IsSep(NameWithoriginalSlashes[Path.size()-1]));
}
#if defined(_WIN32)
// Restore UNC prefix if it was there.
if (NameWasUNC)
Path = (Path.substr(0, 1) + "\\\\?\\" + Path.substr(1)).str();
#endif
// For user files and known standard headers, issue a diagnostic.
// For other system headers, don't. They can be controlled separately.
auto DiagId =

View File

@@ -0,0 +1,10 @@
// Most Microsoft-specific testing should go in case-insensitive-include-ms.c
// This file should only include code that really needs a Windows host OS to
// run.
// REQUIRES: system-windows
// RUN: mkdir -p %t.dir
// RUN: touch %t.dir/foo.h
// RUN: not %clang_cl /FI\\?\%t.dir\FOO.h /WX -Xclang -verify -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: non-portable path to file '"\\?\

View File

@@ -1499,7 +1499,6 @@ string(CONCAT LLVM_LIT_PATH_FUNCTION
"def path(p):\n"
" if not p: return ''\n"
" p = os.path.join(os.path.dirname(os.path.abspath(__file__)), p)\n"
" if os.name == 'nt' and os.path.isabs(p): return p[0].upper() + p[1:]\n"
" return p\n"
)