diff --git a/clang/include/clang/Basic/DiagnosticOptions.def b/clang/include/clang/Basic/DiagnosticOptions.def index ba8ce8f2e6d4f..11047a36b869d 100644 --- a/clang/include/clang/Basic/DiagnosticOptions.def +++ b/clang/include/clang/Basic/DiagnosticOptions.def @@ -101,6 +101,9 @@ DIAGOPT(ShowSafeBufferUsageSuggestions, 1, 0) // TO_UPSTREAM(BoundsSafety) DIAGOPT(BoundsSafetyAdoptionMode, 1, 0) +// TO_UPSTREAM(CAS) +DIAGOPT(FallbackRealFileSystemAbsolutePaths, 1, 0) + #undef DIAGOPT #undef ENUM_DIAGOPT #undef VALUE_DIAGOPT diff --git a/clang/lib/Frontend/CompileJobCache.cpp b/clang/lib/Frontend/CompileJobCache.cpp index 82e7b56260f39..05d152ce9ad83 100644 --- a/clang/lib/Frontend/CompileJobCache.cpp +++ b/clang/lib/Frontend/CompileJobCache.cpp @@ -328,6 +328,9 @@ std::optional CompileJobCache::initialize(CompilerInstance &Clang) { return Error::success(); }; + // Ensure path canonicalization in text diagnostics. + Invocation.getDiagnosticOpts().FallbackRealFileSystemAbsolutePaths = true; + llvm::PrefixMapper PrefixMapper; llvm::SmallVector Split; llvm::MappedPrefix::transformPairs(CacheOpts.PathPrefixMappings, Split); @@ -638,6 +641,9 @@ Expected> CompileJobCache::replayCachedResult( assert(!Clang.getDiagnostics().hasErrorOccurred()); + // Ensure path canonicalization in text diagnostics. + Clang.getDiagnosticOpts().FallbackRealFileSystemAbsolutePaths = true; + std::optional MCOutputID; ObjectStoreCachingOutputs CachingOutputs( Clang, WorkingDir, std::move(PrefixMapper), WriteOutputAsCASID, diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp index e6f592f9ca0c3..007c5167fdb44 100644 --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -16,7 +16,10 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/IOSandbox.h" #include "llvm/Support/Locale.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include #include @@ -813,9 +816,7 @@ void TextDiagnostic::printDiagnosticMessage(raw_ostream &OS, } void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) { -#ifdef _WIN32 - SmallString<4096> TmpFilename; -#endif + SmallString<256> TmpFilename; if (DiagOpts.AbsolutePath) { auto File = SM.getFileManager().getOptionalFileRef(Filename); if (File) { @@ -843,6 +844,18 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) { Filename = SM.getFileManager().getCanonicalName(*File); #endif } + + // TO_UPSTREAM(CAS) + if (DiagOpts.FallbackRealFileSystemAbsolutePaths && !Filename.empty() && + !llvm::sys::path::is_absolute(Filename)) { + // When caching, the above may fail to canonicalize due to using the + // IncludeTreeFileSystem. In that case, we can safely fallback to the real + // filesytem since the text diagnostic output is not captured directly. + auto BypassSandbox = llvm::sys::sandbox::scopedDisable(); + auto FS = llvm::vfs::getRealFileSystem(); + if (FS->getRealPath(Filename, TmpFilename) == std::error_code()) + Filename = TmpFilename; + } } OS << Filename; diff --git a/clang/test/CAS/include-tree-fdiagnostics-absolute-paths.c b/clang/test/CAS/include-tree-fdiagnostics-absolute-paths.c new file mode 100644 index 0000000000000..9a2911c112d4b --- /dev/null +++ b/clang/test/CAS/include-tree-fdiagnostics-absolute-paths.c @@ -0,0 +1,38 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// RUN: env LLVM_CACHE_CAS_PATH=%t/cas %clang-cache \ +// RUN: %clang subdir/tu.c -I. -fdiagnostics-absolute-paths -E \ +// RUN: -Rcompile-job-cache > %t/stdout-miss 2> %t/stderr-miss +// RUN: FileCheck %s -DPREFIX=%/t -check-prefix=PP -input-file=%t/stdout-miss +// RUN: FileCheck %s -DPREFIX=%/t -check-prefix=DIAG -input-file=%t/stderr-miss +// RUN: FileCheck %s -DPREFIX=%/t -check-prefix=MISS -input-file=%t/stderr-miss + +// Again, but with a cache hit. +// RUN: env LLVM_CACHE_CAS_PATH=%t/cas %clang-cache \ +// RUN: %clang subdir/tu.c -I. -fdiagnostics-absolute-paths -E \ +// RUN: -Rcompile-job-cache > %t/stdout-hit 2> %t/stderr-hit +// RUN: FileCheck %s -DPREFIX=%/t -check-prefix=PP -input-file=%t/stdout-hit +// RUN: FileCheck %s -DPREFIX=%/t -check-prefix=DIAG -input-file=%t/stderr-hit +// RUN: FileCheck %s -DPREFIX=%/t -check-prefix=HIT -input-file=%t/stderr-hit + +// Preprocessor does not force absolute paths. +// PP: # 1 "subdir/tu.c" +// PP: # 1 "./h1.h" +// PP: const char *filename = "./h1.h"; + +// Diagnostics force absolute paths. +// DIAG: [[PREFIX]]/subdir/tu.c:1:2: warning: "from tu" +// DIAG: In file included from [[PREFIX]]/subdir/tu.c +// DIAG: [[PREFIX]]/h1.h:1:2: warning: "from h1" + +// MISS: remark: compile job cache miss +// HIT: remark: compile job cache hit + +//--- subdir/tu.c +#warning "from tu" +#include "h1.h" + +//--- h1.h +#warning "from h1" +const char *filename = __FILE__; diff --git a/clang/test/CAS/libclang-replay-job.c b/clang/test/CAS/libclang-replay-job.c index e81c07bd94add..1ba1ad6f7bf9c 100644 --- a/clang/test/CAS/libclang-replay-job.c +++ b/clang/test/CAS/libclang-replay-job.c @@ -78,6 +78,25 @@ // RUN: diff -u %t/t1.d %t/a/b/rel.d // FIXME: Get clang's `-working-directory` to affect relative path for serialized diagnostics. +// Check with -fdiagnostics-absolute-path +// RUN: cd %t +// RUN: c-index-test core -replay-cached-job -cas-path %t/cas @%t/cache-key \ +// RUN: -fcas-plugin-path %llvmshlibdir/libCASPluginTest%pluginext \ +// RUN: -fcas-plugin-option no-logging \ +// RUN: -working-dir %t \ +// RUN: -- @%t/cc1.rsp \ +// RUN: -fdiagnostics-absolute-paths \ +// RUN: -Rcompile-job-cache-hit \ +// RUN: -dependency-file %t/t3.d -o %t/output3.o 2> %t/output3.txt +// RUN: FileCheck %s -input-file=%t/output2.txt -check-prefix=REL_DIAG +// RUN: FileCheck %s -input-file=%t/output3.txt -check-prefix=ABS_DIAG +// RUN: diff %t/output1.o %t/output3.o +// RUN: diff -u %t/t1.d %t/t3.d +// REL_DIAG: remark: compile job cache hit for +// REL_DIAG: {{^}}main.c:1:2: warning: +// ABS_DIAG: remark: compile job cache hit for +// ABS_DIAG: libclang-replay-job.c.tmp{{.}}main.c:1:2: warning: + // Use relative path to inputs and outputs. //--- cdb.json.template [{ diff --git a/clang/test/Modules/feature-availability.c b/clang/test/Modules/feature-availability.c index e21522facc9d7..d9fdd1120d49a 100644 --- a/clang/test/Modules/feature-availability.c +++ b/clang/test/Modules/feature-availability.c @@ -1,3 +1,4 @@ +// RUN: rm -rf %t // RUN: %clang_cc1 -triple arm64-apple-macosx -fmodules %S/Inputs/feature-availability/module.modulemap -fmodule-name=Feature1 -emit-module -o %t/feature1.pcm // RUN: %clang_cc1 -triple arm64-apple-macosx -fmodules %S/Inputs/feature-availability/module.modulemap -fmodule-name=Feature2 -fmodule-file=%t/feature1.pcm -emit-module -o %t/feature2.pcm // RUN: %clang_cc1 -triple arm64-apple-macosx -fmodules -fmodule-file=%t/feature2.pcm -I %S/Inputs/feature-availability -emit-llvm -o - %s | FileCheck %s