diff options
Diffstat (limited to 'clang/lib/Frontend')
20 files changed, 942 insertions, 899 deletions
diff --git a/clang/lib/Frontend/ASTConsumers.cpp b/clang/lib/Frontend/ASTConsumers.cpp index 96f5926c0d7e..7b58eaa04df9 100644 --- a/clang/lib/Frontend/ASTConsumers.cpp +++ b/clang/lib/Frontend/ASTConsumers.cpp @@ -183,21 +183,20 @@ std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() { /// ASTViewer - AST Visualization namespace { - class ASTViewer : public ASTConsumer { - ASTContext *Context; - public: - void Initialize(ASTContext &Context) override { - this->Context = &Context; - } +class ASTViewer : public ASTConsumer { + ASTContext *Context = nullptr; - bool HandleTopLevelDecl(DeclGroupRef D) override { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) - HandleTopLevelSingleDecl(*I); - return true; - } +public: + void Initialize(ASTContext &Context) override { this->Context = &Context; } - void HandleTopLevelSingleDecl(Decl *D); - }; + bool HandleTopLevelDecl(DeclGroupRef D) override { + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) + HandleTopLevelSingleDecl(*I); + return true; + } + + void HandleTopLevelSingleDecl(Decl *D); +}; } void ASTViewer::HandleTopLevelSingleDecl(Decl *D) { diff --git a/clang/lib/Frontend/ASTMerge.cpp b/clang/lib/Frontend/ASTMerge.cpp index 14d781ccdf93..057ea4fd5bb3 100644 --- a/clang/lib/Frontend/ASTMerge.cpp +++ b/clang/lib/Frontend/ASTMerge.cpp @@ -48,7 +48,7 @@ void ASTMergeAction::ExecuteAction() { /*ShouldOwnClient=*/true)); std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile( ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, - CI.getFileSystemOpts(), false); + CI.getFileSystemOpts(), CI.getHeaderSearchOptsPtr(), false); if (!Unit) continue; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 3b4f25182ac9..c13cec2dfa58 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -68,7 +68,6 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -83,7 +82,6 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/FileUtilities.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Timer.h" @@ -322,6 +320,7 @@ static uint64_t getDeclShowContexts(const NamedDecl *ND, if (ID->getDefinition()) Contexts |= (1LL << CodeCompletionContext::CCC_Expression); Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName); + Contexts |= (1LL << CodeCompletionContext::CCC_ObjCClassForwardDecl); } // Deal with tag names. @@ -785,7 +784,8 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags, std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( const std::string &Filename, const PCHContainerReader &PCHContainerRdr, WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, - const FileSystemOptions &FileSystemOpts, bool UseDebugInfo, + const FileSystemOptions &FileSystemOpts, + std::shared_ptr<HeaderSearchOptions> HSOpts, bool UseDebugInfo, bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors, bool UserFilesAreVolatile, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) { @@ -810,8 +810,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( AST->getFileManager(), UserFilesAreVolatile); AST->ModuleCache = new InMemoryModuleCache; - AST->HSOpts = std::make_shared<HeaderSearchOptions>(); - AST->HSOpts->ModuleFormat = std::string(PCHContainerRdr.getFormat()); + AST->HSOpts = HSOpts ? HSOpts : std::make_shared<HeaderSearchOptions>(); + AST->HSOpts->ModuleFormat = std::string(PCHContainerRdr.getFormats().front()); AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts, AST->getSourceManager(), AST->getDiagnostics(), @@ -822,7 +822,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( // Gather Info for preprocessor construction later on. HeaderSearch &HeaderInfo = *AST->HeaderInfo; - unsigned Counter; AST->PP = std::make_shared<Preprocessor>( AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts, @@ -846,6 +845,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( /*isysroot=*/"", /*DisableValidationKind=*/disableValid, AllowASTWithCompilerErrors); + unsigned Counter = 0; AST->Reader->setListener(std::make_unique<ASTInfoCollector>( *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts, AST->TargetOpts, AST->Target, Counter)); @@ -859,7 +859,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( AST->Ctx->setExternalSource(AST->Reader); switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile, - SourceLocation(), ASTReader::ARR_None)) { + SourceLocation(), ASTReader::ARR_None)) { case ASTReader::Success: break; @@ -877,6 +877,10 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( PP.setCounterValue(Counter); + Module *M = HeaderInfo.lookupModule(AST->getLangOpts().CurrentModule); + if (M && AST->getLangOpts().isCompilingModule() && M->isModulePurview()) + AST->Ctx->setCurrentNamedModule(M); + // Create an AST consumer, even though it isn't used. if (ToLoad >= LoadASTOnly) AST->Consumer.reset(new ASTConsumer); @@ -1141,6 +1145,7 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, // Create the compiler instance to use for building the AST. std::unique_ptr<CompilerInstance> Clang( new CompilerInstance(std::move(PCHContainerOps))); + Clang->setInvocation(CCInvocation); // Clean up on error, disengage it if the function returns successfully. auto CleanOnError = llvm::make_scope_exit([&]() { @@ -1167,7 +1172,6 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(Clang.get()); - Clang->setInvocation(CCInvocation); OriginalSourceFile = std::string(Clang->getFrontendOpts().Inputs[0].getFile()); @@ -1393,7 +1397,8 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build( PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS, - PCHContainerOps, /*StoreInMemory=*/false, Callbacks); + PCHContainerOps, StorePreamblesInMemory, PreambleStoragePath, + Callbacks); PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies = PreviousSkipFunctionBodies; @@ -1733,10 +1738,11 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( return AST; } -ASTUnit *ASTUnit::LoadFromCommandLine( +std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr<PCHContainerOperations> PCHContainerOps, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath, + bool StorePreamblesInMemory, StringRef PreambleStoragePath, bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, ArrayRef<RemappedFile> RemappedFiles, bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, @@ -1748,6 +1754,12 @@ ASTUnit *ASTUnit::LoadFromCommandLine( IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) { assert(Diags.get() && "no DiagnosticsEngine was provided"); + // If no VFS was provided, create one that tracks the physical file system. + // If '-working-directory' was passed as an argument, 'createInvocation' will + // set this as the current working directory of the VFS. + if (!VFS) + VFS = llvm::vfs::createPhysicalFileSystem(); + SmallVector<StoredDiagnostic, 4> StoredDiagnostics; std::shared_ptr<CompilerInvocation> CI; @@ -1793,10 +1805,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine( ConfigureDiags(Diags, *AST, CaptureDiagnostics); AST->Diagnostics = Diags; AST->FileSystemOpts = CI->getFileSystemOpts(); - if (!VFS) - VFS = llvm::vfs::getRealFileSystem(); VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); + AST->StorePreamblesInMemory = StorePreamblesInMemory; + AST->PreambleStoragePath = PreambleStoragePath; AST->ModuleCache = new InMemoryModuleCache; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; @@ -1829,7 +1841,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine( return nullptr; } - return AST.release(); + return AST; } bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, @@ -2019,6 +2031,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context, case CodeCompletionContext::CCC_IncludedFile: case CodeCompletionContext::CCC_Attribute: case CodeCompletionContext::CCC_NewName: + case CodeCompletionContext::CCC_ObjCClassForwardDecl: // We're looking for nothing, or we're looking for names that cannot // be hidden. return; @@ -2304,16 +2317,11 @@ bool ASTUnit::Save(StringRef File) { if (HadModuleLoaderFatalFailure) return true; - // Write to a temporary file and later rename it to the actual file, to avoid - // possible race conditions. - SmallString<128> TempPath; - TempPath = File; - TempPath += "-%%%%%%%%"; // FIXME: Can we somehow regenerate the stat cache here, or do we need to // unconditionally create a stat cache when we parse the file? - if (llvm::Error Err = llvm::writeFileAtomically( - TempPath, File, [this](llvm::raw_ostream &Out) { + if (llvm::Error Err = llvm::writeToOutput( + File, [this](llvm::raw_ostream &Out) { return serialize(Out) ? llvm::make_error<llvm::StringError>( "ASTUnit serialization failed", llvm::inconvertibleErrorCode()) @@ -2636,9 +2644,9 @@ bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) { return true; } -const FileEntry *ASTUnit::getPCHFile() { +OptionalFileEntryRef ASTUnit::getPCHFile() { if (!Reader) - return nullptr; + return std::nullopt; serialization::ModuleFile *Mod = nullptr; Reader->getModuleManager().visit([&Mod](serialization::ModuleFile &M) { @@ -2661,7 +2669,7 @@ const FileEntry *ASTUnit::getPCHFile() { if (Mod) return Mod->File; - return nullptr; + return std::nullopt; } bool ASTUnit::isModuleFile() const { diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index ecc1c4cf51c1..92e0b74e38f0 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -46,7 +46,6 @@ #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/LockFileManager.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -55,6 +54,7 @@ #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" #include <optional> #include <time.h> #include <utility> @@ -113,7 +113,7 @@ bool CompilerInstance::createTarget() { // Check whether AuxTarget exists, if not, then create TargetInfo for the // other side of CUDA/OpenMP/SYCL compilation. if (!getAuxTarget() && - (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice || + (getLangOpts().CUDA || getLangOpts().OpenMPIsTargetDevice || getLangOpts().SYCLIsDevice) && !getFrontendOpts().AuxTriple.empty()) { auto TO = std::make_shared<TargetOptions>(); @@ -605,8 +605,9 @@ struct ReadModuleNames : ASTReaderListener { Module *Current = Stack.pop_back_val(); if (Current->IsUnimportable) continue; Current->IsAvailable = true; - Stack.insert(Stack.end(), - Current->submodule_begin(), Current->submodule_end()); + auto SubmodulesRange = Current->submodules(); + Stack.insert(Stack.end(), SubmodulesRange.begin(), + SubmodulesRange.end()); } } } @@ -851,6 +852,9 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary, // relative to that. std::optional<SmallString<128>> AbsPath; if (OutputPath != "-" && !llvm::sys::path::is_absolute(OutputPath)) { + assert(hasFileManager() && + "File Manager is required to fix up relative path.\n"); + AbsPath.emplace(OutputPath); FileMgr->FixupRelativePath(*AbsPath); OutputPath = *AbsPath; @@ -891,10 +895,12 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary, TempPath += "-%%%%%%%%"; TempPath += OutputExtension; TempPath += ".tmp"; + llvm::sys::fs::OpenFlags BinaryFlags = + Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text; Expected<llvm::sys::fs::TempFile> ExpectedFile = llvm::sys::fs::TempFile::create( TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write, - Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text); + BinaryFlags); llvm::Error E = handleErrors( ExpectedFile.takeError(), [&](const llvm::ECError &E) -> llvm::Error { @@ -904,7 +910,9 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary, StringRef Parent = llvm::sys::path::parent_path(OutputPath); EC = llvm::sys::fs::create_directories(Parent); if (!EC) { - ExpectedFile = llvm::sys::fs::TempFile::create(TempPath); + ExpectedFile = llvm::sys::fs::TempFile::create( + TempPath, llvm::sys::fs::all_read | llvm::sys::fs::all_write, + BinaryFlags); if (!ExpectedFile) return llvm::errorCodeToError( llvm::errc::no_such_file_or_directory); @@ -978,10 +986,9 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, ? FileMgr.getSTDIN() : FileMgr.getFileRef(InputFile, /*OpenFile=*/true); if (!FileOrErr) { - // FIXME: include the error in the diagnostic even when it's not stdin. auto EC = llvm::errorToErrorCode(FileOrErr.takeError()); if (InputFile != "-") - Diags.Report(diag::err_fe_error_reading) << InputFile; + Diags.Report(diag::err_fe_error_reading) << InputFile << EC.message(); else Diags.Report(diag::err_fe_error_reading_stdin) << EC.message(); return false; @@ -1084,9 +1091,12 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { } StringRef StatsFile = getFrontendOpts().StatsFile; if (!StatsFile.empty()) { + llvm::sys::fs::OpenFlags FileFlags = llvm::sys::fs::OF_TextWithCRLF; + if (getFrontendOpts().AppendStats) + FileFlags |= llvm::sys::fs::OF_Append; std::error_code EC; - auto StatS = std::make_unique<llvm::raw_fd_ostream>( - StatsFile, EC, llvm::sys::fs::OF_TextWithCRLF); + auto StatS = + std::make_unique<llvm::raw_fd_ostream>(StatsFile, EC, FileFlags); if (EC) { getDiagnostics().Report(diag::warn_fe_unable_to_open_stats_file) << StatsFile << EC.message(); @@ -1983,14 +1993,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, Module = PP->getHeaderSearchInfo().lookupModule( ModuleName, ImportLoc, /*AllowSearch*/ true, /*AllowExtraModuleMapSearch*/ !IsInclusionDirective); - /// FIXME: perhaps we should (a) look for a module using the module name - // to file map (PrebuiltModuleFiles) and (b) diagnose if still not found? - //if (Module == nullptr) { - // getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) - // << ModuleName; - // DisableGeneratingGlobalModuleIndex = true; - // return ModuleLoadResult(); - //} + MM.cacheModuleLoad(*Path[0].first, Module); } else { ModuleLoadResult Result = findOrCompileModuleAndReadAST( @@ -2028,8 +2031,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, PrivateModule, PP->getIdentifierInfo(Module->Name)->getTokenID()); PrivPath.push_back(std::make_pair(&II, Path[0].second)); + std::string FileName; + // If there is a modulemap module or prebuilt module, load it. if (PP->getHeaderSearchInfo().lookupModule(PrivateModule, ImportLoc, true, - !IsInclusionDirective)) + !IsInclusionDirective) || + selectModuleSource(nullptr, PrivateModule, FileName, BuiltModules, + PP->getHeaderSearchInfo()) != MS_ModuleNotFound) Sub = loadModule(ImportLoc, PrivPath, Visibility, IsInclusionDirective); if (Sub) { MapPrivateSubModToTopLevel = true; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 0bb9c8c83c63..1fba91bed041 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -12,7 +12,6 @@ #include "clang/Basic/CharInfo.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/CommentOptions.h" -#include "clang/Basic/DebugInfoOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/DiagnosticOptions.h" @@ -57,9 +56,9 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Frontend/Debug/Options.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Linker/Linker.h" #include "llvm/MC/MCTargetOptions.h" @@ -77,7 +76,6 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/HashBuilder.h" -#include "llvm/Support/Host.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -87,6 +85,8 @@ #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetOptions.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #include <algorithm> #include <atomic> #include <cassert> @@ -427,8 +427,10 @@ static T extractMaskValue(T KeyPath) { } #define PARSE_OPTION_WITH_MARSHALLING( \ - ARGS, DIAGS, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) \ + ARGS, DIAGS, PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ + PARAM, HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, \ + KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \ + DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ if ((FLAGS)&options::CC1Option) { \ KEYPATH = MERGER(KEYPATH, DEFAULT_VALUE); \ if (IMPLIED_CHECK) \ @@ -442,9 +444,10 @@ static T extractMaskValue(T KeyPath) { // Capture the extracted value as a lambda argument to avoid potential issues // with lifetime extension of the reference. #define GENERATE_OPTION_WITH_MARSHALLING( \ - ARGS, STRING_ALLOCATOR, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, \ - TABLE_INDEX) \ + ARGS, STRING_ALLOCATOR, PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, \ + ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, VALUES, SPELLING, \ + SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, \ + IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ if ((FLAGS)&options::CC1Option) { \ [&](const auto &Extracted) { \ if (ALWAYS_EMIT || \ @@ -641,18 +644,31 @@ using GenerateFn = llvm::function_ref<void( CompilerInvocation &, SmallVectorImpl<const char *> &, CompilerInvocation::StringAllocator)>; -// May perform round-trip of command line arguments. By default, the round-trip -// is enabled in assert builds. This can be overwritten at run-time via the -// "-round-trip-args" and "-no-round-trip-args" command line flags. -// During round-trip, the command line arguments are parsed into a dummy -// instance of CompilerInvocation which is used to generate the command line -// arguments again. The real CompilerInvocation instance is then created by -// parsing the generated arguments, not the original ones. +/// May perform round-trip of command line arguments. By default, the round-trip +/// is enabled in assert builds. This can be overwritten at run-time via the +/// "-round-trip-args" and "-no-round-trip-args" command line flags, or via the +/// ForceRoundTrip parameter. +/// +/// During round-trip, the command line arguments are parsed into a dummy +/// CompilerInvocation, which is used to generate the command line arguments +/// again. The real CompilerInvocation is then created by parsing the generated +/// arguments, not the original ones. This (in combination with tests covering +/// argument behavior) ensures the generated command line is complete (doesn't +/// drop/mangle any arguments). +/// +/// Finally, we check the command line that was used to create the real +/// CompilerInvocation instance. By default, we compare it to the command line +/// the real CompilerInvocation generates. This checks whether the generator is +/// deterministic. If \p CheckAgainstOriginalInvocation is enabled, we instead +/// compare it to the original command line to verify the original command-line +/// was canonical and can round-trip exactly. static bool RoundTrip(ParseFn Parse, GenerateFn Generate, CompilerInvocation &RealInvocation, CompilerInvocation &DummyInvocation, ArrayRef<const char *> CommandLineArgs, - DiagnosticsEngine &Diags, const char *Argv0) { + DiagnosticsEngine &Diags, const char *Argv0, + bool CheckAgainstOriginalInvocation = false, + bool ForceRoundTrip = false) { #ifndef NDEBUG bool DoRoundTripDefault = true; #else @@ -660,11 +676,15 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, #endif bool DoRoundTrip = DoRoundTripDefault; - for (const auto *Arg : CommandLineArgs) { - if (Arg == StringRef("-round-trip-args")) - DoRoundTrip = true; - if (Arg == StringRef("-no-round-trip-args")) - DoRoundTrip = false; + if (ForceRoundTrip) { + DoRoundTrip = true; + } else { + for (const auto *Arg : CommandLineArgs) { + if (Arg == StringRef("-round-trip-args")) + DoRoundTrip = true; + if (Arg == StringRef("-no-round-trip-args")) + DoRoundTrip = false; + } } // If round-trip was not requested, simply run the parser with the real @@ -719,30 +739,34 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, // Generate arguments from the dummy invocation. If Generate is the // inverse of Parse, the newly generated arguments must have the same // semantics as the original. - SmallVector<const char *> GeneratedArgs1; - Generate(DummyInvocation, GeneratedArgs1, SA); + SmallVector<const char *> GeneratedArgs; + Generate(DummyInvocation, GeneratedArgs, SA); // Run the second parse, now on the generated arguments, and with the real // invocation and diagnostics. The result is what we will end up using for the // rest of compilation, so if Generate is not inverse of Parse, something down // the line will break. - bool Success2 = Parse(RealInvocation, GeneratedArgs1, Diags, Argv0); + bool Success2 = Parse(RealInvocation, GeneratedArgs, Diags, Argv0); // The first parse on original arguments succeeded, but second parse of // generated arguments failed. Something must be wrong with the generator. if (!Success2) { Diags.Report(diag::err_cc1_round_trip_ok_then_fail); Diags.Report(diag::note_cc1_round_trip_generated) - << 1 << SerializeArgs(GeneratedArgs1); + << 1 << SerializeArgs(GeneratedArgs); return false; } - // Generate arguments again, this time from the options we will end up using - // for the rest of the compilation. - SmallVector<const char *> GeneratedArgs2; - Generate(RealInvocation, GeneratedArgs2, SA); + SmallVector<const char *> ComparisonArgs; + if (CheckAgainstOriginalInvocation) + // Compare against original arguments. + ComparisonArgs.assign(CommandLineArgs.begin(), CommandLineArgs.end()); + else + // Generate arguments again, this time from the options we will end up using + // for the rest of the compilation. + Generate(RealInvocation, ComparisonArgs, SA); - // Compares two lists of generated arguments. + // Compares two lists of arguments. auto Equal = [](const ArrayRef<const char *> A, const ArrayRef<const char *> B) { return std::equal(A.begin(), A.end(), B.begin(), B.end(), @@ -754,23 +778,41 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, // If we generated different arguments from what we assume are two // semantically equivalent CompilerInvocations, the Generate function may // be non-deterministic. - if (!Equal(GeneratedArgs1, GeneratedArgs2)) { + if (!Equal(GeneratedArgs, ComparisonArgs)) { Diags.Report(diag::err_cc1_round_trip_mismatch); Diags.Report(diag::note_cc1_round_trip_generated) - << 1 << SerializeArgs(GeneratedArgs1); + << 1 << SerializeArgs(GeneratedArgs); Diags.Report(diag::note_cc1_round_trip_generated) - << 2 << SerializeArgs(GeneratedArgs2); + << 2 << SerializeArgs(ComparisonArgs); return false; } Diags.Report(diag::remark_cc1_round_trip_generated) - << 1 << SerializeArgs(GeneratedArgs1); + << 1 << SerializeArgs(GeneratedArgs); Diags.Report(diag::remark_cc1_round_trip_generated) - << 2 << SerializeArgs(GeneratedArgs2); + << 2 << SerializeArgs(ComparisonArgs); return Success2; } +bool CompilerInvocation::checkCC1RoundTrip(ArrayRef<const char *> Args, + DiagnosticsEngine &Diags, + const char *Argv0) { + CompilerInvocation DummyInvocation1, DummyInvocation2; + return RoundTrip( + [](CompilerInvocation &Invocation, ArrayRef<const char *> CommandLineArgs, + DiagnosticsEngine &Diags, const char *Argv0) { + return CreateFromArgsImpl(Invocation, CommandLineArgs, Diags, Argv0); + }, + [](CompilerInvocation &Invocation, SmallVectorImpl<const char *> &Args, + StringAllocator SA) { + Args.push_back("-cc1"); + Invocation.generateCC1CommandLine(Args, SA); + }, + DummyInvocation1, DummyInvocation2, Args, Diags, Argv0, + /*CheckAgainstOriginalInvocation=*/true, /*ForceRoundTrip=*/true); +} + static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group, OptSpecifier GroupWithValue, std::vector<std::string> &Diagnostics) { @@ -809,14 +851,8 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts, CompilerInvocation::StringAllocator SA) { const AnalyzerOptions *AnalyzerOpts = &Opts; -#define ANALYZER_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define ANALYZER_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef ANALYZER_OPTION_WITH_MARSHALLING @@ -877,14 +913,20 @@ static void GenerateAnalyzerArgs(AnalyzerOptions &Opts, AnalyzerOptions ConfigOpts; parseAnalyzerConfigs(ConfigOpts, nullptr); - for (const auto &C : Opts.Config) { + // Sort options by key to avoid relying on StringMap iteration order. + SmallVector<std::pair<StringRef, StringRef>, 4> SortedConfigOpts; + for (const auto &C : Opts.Config) + SortedConfigOpts.emplace_back(C.getKey(), C.getValue()); + llvm::sort(SortedConfigOpts, llvm::less_first()); + + for (const auto &[Key, Value] : SortedConfigOpts) { // Don't generate anything that came from parseAnalyzerConfigs. It would be // redundant and may not be valid on the command line. - auto Entry = ConfigOpts.Config.find(C.getKey()); - if (Entry != ConfigOpts.Config.end() && Entry->getValue() == C.getValue()) + auto Entry = ConfigOpts.Config.find(Key); + if (Entry != ConfigOpts.Config.end() && Entry->getValue() == Value) continue; - GenerateArg(Args, OPT_analyzer_config, C.getKey() + "=" + C.getValue(), SA); + GenerateArg(Args, OPT_analyzer_config, Key + "=" + Value, SA); } // Nothing to generate for FullCompilerInvocation. @@ -896,14 +938,8 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, AnalyzerOptions *AnalyzerOpts = &Opts; -#define ANALYZER_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define ANALYZER_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef ANALYZER_OPTION_WITH_MARSHALLING @@ -1020,15 +1056,6 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, A->claim(); Opts.Config[key] = std::string(val); - - // FIXME: Remove this hunk after clang-17 released. - constexpr auto SingleFAM = - "consider-single-element-arrays-as-flexible-array-members"; - if (key == SingleFAM) { - Diags.Report(diag::warn_analyzer_deprecated_option_with_alternative) - << SingleFAM << "clang-17" - << "-fstrict-flex-arrays=<N>"; - } } } @@ -1304,8 +1331,9 @@ static std::string serializeXRayInstrumentationBundle(const XRayInstrSet &S) { // Set the profile kind using fprofile-instrument-use-path. static void setPGOUseInstrumentor(CodeGenOptions &Opts, const Twine &ProfileName, + llvm::vfs::FileSystem &FS, DiagnosticsEngine &Diags) { - auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName); + auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName, FS); if (auto E = ReaderOrErr.takeError()) { unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "Error in reading profile %0: %1"); @@ -1339,14 +1367,8 @@ void CompilerInvocation::GenerateCodeGenArgs( else GenerateArg(Args, OPT_O, Twine(Opts.OptimizationLevel), SA); -#define CODEGEN_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define CODEGEN_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef CODEGEN_OPTION_WITH_MARSHALLING @@ -1366,28 +1388,28 @@ void CompilerInvocation::GenerateCodeGenArgs( std::optional<StringRef> DebugInfoVal; switch (Opts.DebugInfo) { - case codegenoptions::DebugLineTablesOnly: + case llvm::codegenoptions::DebugLineTablesOnly: DebugInfoVal = "line-tables-only"; break; - case codegenoptions::DebugDirectivesOnly: + case llvm::codegenoptions::DebugDirectivesOnly: DebugInfoVal = "line-directives-only"; break; - case codegenoptions::DebugInfoConstructor: + case llvm::codegenoptions::DebugInfoConstructor: DebugInfoVal = "constructor"; break; - case codegenoptions::LimitedDebugInfo: + case llvm::codegenoptions::LimitedDebugInfo: DebugInfoVal = "limited"; break; - case codegenoptions::FullDebugInfo: + case llvm::codegenoptions::FullDebugInfo: DebugInfoVal = "standalone"; break; - case codegenoptions::UnusedTypeInfo: + case llvm::codegenoptions::UnusedTypeInfo: DebugInfoVal = "unused-types"; break; - case codegenoptions::NoDebugInfo: // default value + case llvm::codegenoptions::NoDebugInfo: // default value DebugInfoVal = std::nullopt; break; - case codegenoptions::LocTrackingOnly: // implied value + case llvm::codegenoptions::LocTrackingOnly: // implied value DebugInfoVal = std::nullopt; break; } @@ -1432,10 +1454,10 @@ void CompilerInvocation::GenerateCodeGenArgs( GenerateArg(Args, OPT_gpubnames, SA); auto TNK = Opts.getDebugSimpleTemplateNames(); - if (TNK != codegenoptions::DebugTemplateNamesKind::Full) { - if (TNK == codegenoptions::DebugTemplateNamesKind::Simple) + if (TNK != llvm::codegenoptions::DebugTemplateNamesKind::Full) { + if (TNK == llvm::codegenoptions::DebugTemplateNamesKind::Simple) GenerateArg(Args, OPT_gsimple_template_names_EQ, "simple", SA); - else if (TNK == codegenoptions::DebugTemplateNamesKind::Mangled) + else if (TNK == llvm::codegenoptions::DebugTemplateNamesKind::Mangled) GenerateArg(Args, OPT_gsimple_template_names_EQ, "mangled", SA); } // ProfileInstrumentUsePath is marshalled automatically, no need to generate @@ -1505,8 +1527,8 @@ void CompilerInvocation::GenerateCodeGenArgs( F.Filename, SA); } - GenerateArg( - Args, Opts.EmulatedTLS ? OPT_femulated_tls : OPT_fno_emulated_tls, SA); + if (Opts.EmulatedTLS) + GenerateArg(Args, OPT_femulated_tls, SA); if (Opts.FPDenormalMode != llvm::DenormalMode::getIEEE()) GenerateArg(Args, OPT_fdenormal_fp_math_EQ, Opts.FPDenormalMode.str(), SA); @@ -1529,6 +1551,9 @@ void CompilerInvocation::GenerateCodeGenArgs( if (Opts.EnableAIXExtendedAltivecABI) GenerateArg(Args, OPT_mabi_EQ_vec_extabi, SA); + if (Opts.XCOFFReadOnlyPointers) + GenerateArg(Args, OPT_mxcoff_roptr, SA); + if (!Opts.OptRecordPasses.empty()) GenerateArg(Args, OPT_opt_record_passes, Opts.OptRecordPasses, SA); @@ -1601,14 +1626,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, // variable name and type. const LangOptions *LangOpts = &LangOptsRef; -#define CODEGEN_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define CODEGEN_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef CODEGEN_OPTION_WITH_MARSHALLING @@ -1642,18 +1661,19 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, if (Arg *A = Args.getLastArg(OPT_debug_info_kind_EQ)) { unsigned Val = llvm::StringSwitch<unsigned>(A->getValue()) - .Case("line-tables-only", codegenoptions::DebugLineTablesOnly) - .Case("line-directives-only", codegenoptions::DebugDirectivesOnly) - .Case("constructor", codegenoptions::DebugInfoConstructor) - .Case("limited", codegenoptions::LimitedDebugInfo) - .Case("standalone", codegenoptions::FullDebugInfo) - .Case("unused-types", codegenoptions::UnusedTypeInfo) + .Case("line-tables-only", llvm::codegenoptions::DebugLineTablesOnly) + .Case("line-directives-only", + llvm::codegenoptions::DebugDirectivesOnly) + .Case("constructor", llvm::codegenoptions::DebugInfoConstructor) + .Case("limited", llvm::codegenoptions::LimitedDebugInfo) + .Case("standalone", llvm::codegenoptions::FullDebugInfo) + .Case("unused-types", llvm::codegenoptions::UnusedTypeInfo) .Default(~0U); if (Val == ~0U) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); else - Opts.setDebugInfo(static_cast<codegenoptions::DebugInfoKind>(Val)); + Opts.setDebugInfo(static_cast<llvm::codegenoptions::DebugInfoKind>(Val)); } // If -fuse-ctor-homing is set and limited debug info is already on, then use @@ -1661,23 +1681,21 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, if (const Arg *A = Args.getLastArg(OPT_fuse_ctor_homing, OPT_fno_use_ctor_homing)) { if (A->getOption().matches(OPT_fuse_ctor_homing) && - Opts.getDebugInfo() == codegenoptions::LimitedDebugInfo) - Opts.setDebugInfo(codegenoptions::DebugInfoConstructor); + Opts.getDebugInfo() == llvm::codegenoptions::LimitedDebugInfo) + Opts.setDebugInfo(llvm::codegenoptions::DebugInfoConstructor); if (A->getOption().matches(OPT_fno_use_ctor_homing) && - Opts.getDebugInfo() == codegenoptions::DebugInfoConstructor) - Opts.setDebugInfo(codegenoptions::LimitedDebugInfo); + Opts.getDebugInfo() == llvm::codegenoptions::DebugInfoConstructor) + Opts.setDebugInfo(llvm::codegenoptions::LimitedDebugInfo); } for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) { auto Split = StringRef(Arg).split('='); - Opts.DebugPrefixMap.insert( - {std::string(Split.first), std::string(Split.second)}); + Opts.DebugPrefixMap.emplace_back(Split.first, Split.second); } for (const auto &Arg : Args.getAllArgValues(OPT_fcoverage_prefix_map_EQ)) { auto Split = StringRef(Arg).split('='); - Opts.CoveragePrefixMap.insert( - {std::string(Split.first), std::string(Split.second)}); + Opts.CoveragePrefixMap.emplace_back(Split.first, Split.second); } const llvm::Triple::ArchType DebugEntryValueArchs[] = { @@ -1720,13 +1738,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, << A->getSpelling() << A->getValue(); Opts.setDebugSimpleTemplateNames( StringRef(A->getValue()) == "simple" - ? codegenoptions::DebugTemplateNamesKind::Simple - : codegenoptions::DebugTemplateNamesKind::Mangled); + ? llvm::codegenoptions::DebugTemplateNamesKind::Simple + : llvm::codegenoptions::DebugTemplateNamesKind::Mangled); } - if (!Opts.ProfileInstrumentUsePath.empty()) - setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath, Diags); - if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ)) { Opts.TimePasses = true; @@ -1752,6 +1767,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.PrepareForThinLTO = true; else if (S != "full") Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S; + if (Args.hasArg(OPT_funified_lto)) + Opts.PrepareForThinLTO = true; } if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) { if (IK.getLanguage() != Language::LLVM_IR) @@ -1777,7 +1794,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.MemoryProfileOutput = MemProfileBasename; memcpy(Opts.CoverageVersion, "408*", 4); - if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) { + if (Opts.CoverageNotesFile.size() || Opts.CoverageDataFile.size()) { if (Args.hasArg(OPT_coverage_version_EQ)) { StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ); if (CoverageVersion.size() != 4) { @@ -1867,15 +1884,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.LinkBitcodeFiles.push_back(F); } - if (!Args.getLastArg(OPT_femulated_tls) && - !Args.getLastArg(OPT_fno_emulated_tls)) { - Opts.EmulatedTLS = T.hasDefaultEmulatedTLS(); - } - if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) { if (T.isOSAIX()) { StringRef Name = A->getValue(); - if (Name != "global-dynamic") + if (Name != "global-dynamic" && Name != "local-exec") Diags.Report(diag::err_aix_unsupported_tls_model) << Name; } } @@ -1917,14 +1929,23 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } - if (Arg *A = - Args.getLastArg(OPT_mabi_EQ_vec_default, OPT_mabi_EQ_vec_extabi)) { + if (Arg *A = Args.getLastArg(OPT_mxcoff_roptr)) { if (!T.isOSAIX()) Diags.Report(diag::err_drv_unsupported_opt_for_target) << A->getSpelling() << T.str(); - const Option &O = A->getOption(); - Opts.EnableAIXExtendedAltivecABI = O.matches(OPT_mabi_EQ_vec_extabi); + // Since the storage mapping class is specified per csect, + // without using data sections, it is less effective to use read-only + // pointers. Using read-only pointers may cause other RO variables in the + // same csect to become RW when the linker acts upon `-bforceimprw`; + // therefore, we require that separate data sections + // are used when `-mxcoff-roptr` is in effect. We respect the setting of + // data-sections since we have not found reasons to do otherwise that + // overcome the user surprise of not respecting the setting. + if (!Args.hasFlag(OPT_fdata_sections, OPT_fno_data_sections, false)) + Diags.Report(diag::err_roptr_requires_data_sections); + + Opts.XCOFFReadOnlyPointers = true; } if (Arg *A = Args.getLastArg(OPT_mabi_EQ_quadword_atomics)) { @@ -1962,8 +1983,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.OptimizationRemarkAnalysis.hasValidPattern(); bool UsingSampleProfile = !Opts.SampleProfileFile.empty(); - bool UsingProfile = UsingSampleProfile || - (Opts.getProfileUse() != CodeGenOptions::ProfileNone); + bool UsingProfile = + UsingSampleProfile || !Opts.ProfileInstrumentUsePath.empty(); if (Opts.DiagnosticsWithHotness && !UsingProfile && // An IR file will contain PGO as metadata @@ -2018,8 +2039,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, // If the user requested a flag that requires source locations available in // the backend, make sure that the backend tracks source location information. - if (NeedLocTracking && Opts.getDebugInfo() == codegenoptions::NoDebugInfo) - Opts.setDebugInfo(codegenoptions::LocTrackingOnly); + if (NeedLocTracking && + Opts.getDebugInfo() == llvm::codegenoptions::NoDebugInfo) + Opts.setDebugInfo(llvm::codegenoptions::LocTrackingOnly); // Parse -fsanitize-recover= arguments. // FIXME: Report unrecoverable sanitizers incorrectly specified here. @@ -2050,14 +2072,8 @@ GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts, SmallVectorImpl<const char *> &Args, CompilerInvocation::StringAllocator SA) { const DependencyOutputOptions &DependencyOutputOpts = Opts; -#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING @@ -2091,14 +2107,8 @@ static bool ParseDependencyOutputArgs(DependencyOutputOptions &Opts, unsigned NumErrorsBefore = Diags.getNumErrors(); DependencyOutputOptions &DependencyOutputOpts = Opts; -#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING @@ -2214,14 +2224,8 @@ static void GenerateFileSystemArgs(const FileSystemOptions &Opts, CompilerInvocation::StringAllocator SA) { const FileSystemOptions &FileSystemOpts = Opts; -#define FILE_SYSTEM_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define FILE_SYSTEM_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef FILE_SYSTEM_OPTION_WITH_MARSHALLING } @@ -2232,14 +2236,8 @@ static bool ParseFileSystemArgs(FileSystemOptions &Opts, const ArgList &Args, FileSystemOptions &FileSystemOpts = Opts; -#define FILE_SYSTEM_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define FILE_SYSTEM_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef FILE_SYSTEM_OPTION_WITH_MARSHALLING @@ -2250,14 +2248,8 @@ static void GenerateMigratorArgs(const MigratorOptions &Opts, SmallVectorImpl<const char *> &Args, CompilerInvocation::StringAllocator SA) { const MigratorOptions &MigratorOpts = Opts; -#define MIGRATOR_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define MIGRATOR_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef MIGRATOR_OPTION_WITH_MARSHALLING } @@ -2268,14 +2260,8 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, const ArgList &Args, MigratorOptions &MigratorOpts = Opts; -#define MIGRATOR_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define MIGRATOR_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef MIGRATOR_OPTION_WITH_MARSHALLING @@ -2286,14 +2272,8 @@ void CompilerInvocation::GenerateDiagnosticArgs( const DiagnosticOptions &Opts, SmallVectorImpl<const char *> &Args, StringAllocator SA, bool DefaultDiagColor) { const DiagnosticOptions *DiagnosticOpts = &Opts; -#define DIAG_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define DIAG_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef DIAG_OPTION_WITH_MARSHALLING @@ -2354,10 +2334,20 @@ clang::CreateAndPopulateDiagOpts(ArrayRef<const char *> Argv) { unsigned MissingArgIndex, MissingArgCount; InputArgList Args = getDriverOptTable().ParseArgs( Argv.slice(1), MissingArgIndex, MissingArgCount); + + bool ShowColors = true; + if (std::optional<std::string> NoColor = + llvm::sys::Process::GetEnv("NO_COLOR"); + NoColor && !NoColor->empty()) { + // If the user set the NO_COLOR environment variable, we'll honor that + // unless the command line overrides it. + ShowColors = false; + } + // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. // Any errors that would be diagnosed here will also be diagnosed later, // when the DiagnosticsEngine actually exists. - (void)ParseDiagnosticArgs(*DiagOpts, Args); + (void)ParseDiagnosticArgs(*DiagOpts, Args, /*Diags=*/nullptr, ShowColors); return DiagOpts; } @@ -2377,14 +2367,8 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, // "DiagnosticOpts->". Let's provide the expected variable name and type. DiagnosticOptions *DiagnosticOpts = &Opts; -#define DIAG_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, *Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define DIAG_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, *Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef DIAG_OPTION_WITH_MARSHALLING @@ -2413,9 +2397,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagMask = DiagnosticLevelMask::All; Opts.setVerifyIgnoreUnexpected(DiagMask); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { - Opts.TabStop = DiagnosticOptions::DefaultTabStop; Diags->Report(diag::warn_ignoring_ftabstop_value) << Opts.TabStop << DiagnosticOptions::DefaultTabStop; + Opts.TabStop = DiagnosticOptions::DefaultTabStop; } addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings); @@ -2530,14 +2514,8 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts, CompilerInvocation::StringAllocator SA, bool IsHeader) { const FrontendOptions &FrontendOpts = Opts; -#define FRONTEND_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define FRONTEND_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef FRONTEND_OPTION_WITH_MARSHALLING @@ -2706,14 +2684,8 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, FrontendOptions &FrontendOpts = Opts; -#define FRONTEND_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define FRONTEND_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef FRONTEND_OPTION_WITH_MARSHALLING @@ -2965,14 +2937,8 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts, SmallVectorImpl<const char *> &Args, CompilerInvocation::StringAllocator SA) { const HeaderSearchOptions *HeaderSearchOpts = &Opts; -#define HEADER_SEARCH_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define HEADER_SEARCH_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef HEADER_SEARCH_OPTION_WITH_MARSHALLING @@ -3095,14 +3061,8 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, HeaderSearchOptions *HeaderSearchOpts = &Opts; -#define HEADER_SEARCH_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define HEADER_SEARCH_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef HEADER_SEARCH_OPTION_WITH_MARSHALLING @@ -3217,7 +3177,7 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, Opts.AddSystemHeaderPrefix( A->getValue(), A->getOption().matches(OPT_system_header_prefix)); - for (const auto *A : Args.filtered(OPT_ivfsoverlay)) + for (const auto *A : Args.filtered(OPT_ivfsoverlay, OPT_vfsoverlay)) Opts.AddVFSOverlayFile(A->getValue()); return Diags.getNumErrors() == NumErrorsBefore; @@ -3348,14 +3308,8 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, const LangOptions *LangOpts = &Opts; -#define LANG_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define LANG_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef LANG_OPTION_WITH_MARSHALLING @@ -3443,14 +3397,14 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, if (Opts.OpenMP && !Opts.OpenMPSimd) { GenerateArg(Args, OPT_fopenmp, SA); - if (Opts.OpenMP != 50) + if (Opts.OpenMP != 51) GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA); if (!Opts.OpenMPUseTLS) GenerateArg(Args, OPT_fnoopenmp_use_tls, SA); - if (Opts.OpenMPIsDevice) - GenerateArg(Args, OPT_fopenmp_is_device, SA); + if (Opts.OpenMPIsTargetDevice) + GenerateArg(Args, OPT_fopenmp_is_target_device, SA); if (Opts.OpenMPIRBuilder) GenerateArg(Args, OPT_fopenmp_enable_irbuilder, SA); @@ -3459,7 +3413,7 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, if (Opts.OpenMPSimd) { GenerateArg(Args, OPT_fopenmp_simd, SA); - if (Opts.OpenMP != 50) + if (Opts.OpenMP != 51) GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA); } @@ -3671,14 +3625,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, // "LangOpts->". Let's provide the expected variable name and type. LangOptions *LangOpts = &Opts; -#define LANG_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define LANG_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef LANG_OPTION_WITH_MARSHALLING @@ -3796,9 +3744,9 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.Blocks = Args.hasArg(OPT_fblocks) || (Opts.OpenCL && Opts.OpenCLVersion == 200); - Opts.ConvergentFunctions = Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || - Opts.SYCLIsDevice || - Args.hasArg(OPT_fconvergent_functions); + Opts.ConvergentFunctions = Args.hasArg(OPT_fconvergent_functions) || + Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || + Opts.SYCLIsDevice; Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; if (!Opts.NoBuiltin) @@ -3833,7 +3781,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, } // Check if -fopenmp is specified and set default version to 5.0. - Opts.OpenMP = Args.hasArg(OPT_fopenmp) ? 50 : 0; + Opts.OpenMP = Args.hasArg(OPT_fopenmp) ? 51 : 0; // Check if -fopenmp-simd is specified. bool IsSimdSpecified = Args.hasFlag(options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd, @@ -3841,23 +3789,24 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.OpenMPSimd = !Opts.OpenMP && IsSimdSpecified; Opts.OpenMPUseTLS = Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls); - Opts.OpenMPIsDevice = - Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_device); + Opts.OpenMPIsTargetDevice = + Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_target_device); Opts.OpenMPIRBuilder = Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_enable_irbuilder); bool IsTargetSpecified = - Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ); + Opts.OpenMPIsTargetDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ); - Opts.ConvergentFunctions = Opts.ConvergentFunctions || Opts.OpenMPIsDevice; + Opts.ConvergentFunctions = + Opts.ConvergentFunctions || Opts.OpenMPIsTargetDevice; if (Opts.OpenMP || Opts.OpenMPSimd) { if (int Version = getLastArgIntValue( Args, OPT_fopenmp_version_EQ, - (IsSimdSpecified || IsTargetSpecified) ? 50 : Opts.OpenMP, Diags)) + (IsSimdSpecified || IsTargetSpecified) ? 51 : Opts.OpenMP, Diags)) Opts.OpenMP = Version; // Provide diagnostic when a given target is not expected to be an OpenMP // device or host. - if (!Opts.OpenMPIsDevice) { + if (!Opts.OpenMPIsTargetDevice) { switch (T.getArch()) { default: break; @@ -3872,13 +3821,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, // Set the flag to prevent the implementation from emitting device exception // handling code for those requiring so. - if ((Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN())) || + if ((Opts.OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())) || Opts.OpenCLCPlusPlus) { Opts.Exceptions = 0; Opts.CXXExceptions = 0; } - if (Opts.OpenMPIsDevice && T.isNVPTX()) { + if (Opts.OpenMPIsTargetDevice && T.isNVPTX()) { Opts.OpenMPCUDANumSMs = getLastArgIntValue(Args, options::OPT_fopenmp_cuda_number_of_sm_EQ, Opts.OpenMPCUDANumSMs, Diags); @@ -3892,15 +3841,15 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, // Set the value of the debugging flag used in the new offloading device RTL. // Set either by a specific value or to a default if not specified. - if (Opts.OpenMPIsDevice && (Args.hasArg(OPT_fopenmp_target_debug) || - Args.hasArg(OPT_fopenmp_target_debug_EQ))) { + if (Opts.OpenMPIsTargetDevice && (Args.hasArg(OPT_fopenmp_target_debug) || + Args.hasArg(OPT_fopenmp_target_debug_EQ))) { Opts.OpenMPTargetDebug = getLastArgIntValue( Args, OPT_fopenmp_target_debug_EQ, Opts.OpenMPTargetDebug, Diags); if (!Opts.OpenMPTargetDebug && Args.hasArg(OPT_fopenmp_target_debug)) Opts.OpenMPTargetDebug = 1; } - if (Opts.OpenMPIsDevice) { + if (Opts.OpenMPIsTargetDevice) { if (Args.hasArg(OPT_fopenmp_assume_teams_oversubscription)) Opts.OpenMPTeamSubscription = true; if (Args.hasArg(OPT_fopenmp_assume_threads_oversubscription)) @@ -3948,7 +3897,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, } // Set CUDA mode for OpenMP target NVPTX/AMDGCN if specified in options - Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN()) && + Opts.OpenMPCUDAMode = Opts.OpenMPIsTargetDevice && + (T.isNVPTX() || T.isAMDGCN()) && Args.hasArg(options::OPT_fopenmp_cuda_mode); // FIXME: Eliminate this dependency. @@ -4179,14 +4129,8 @@ static void GeneratePreprocessorArgs(PreprocessorOptions &Opts, const CodeGenOptions &CodeGenOpts) { PreprocessorOptions *PreprocessorOpts = &Opts; -#define PREPROCESSOR_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define PREPROCESSOR_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef PREPROCESSOR_OPTION_WITH_MARSHALLING @@ -4254,14 +4198,8 @@ static bool ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, PreprocessorOptions *PreprocessorOpts = &Opts; -#define PREPROCESSOR_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define PREPROCESSOR_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef PREPROCESSOR_OPTION_WITH_MARSHALLING @@ -4354,14 +4292,8 @@ static void GeneratePreprocessorOutputArgs( CompilerInvocation::StringAllocator SA, frontend::ActionKind Action) { const PreprocessorOutputOptions &PreprocessorOutputOpts = Opts; -#define PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING @@ -4381,14 +4313,8 @@ static bool ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, PreprocessorOutputOptions &PreprocessorOutputOpts = Opts; -#define PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING @@ -4403,14 +4329,8 @@ static void GenerateTargetArgs(const TargetOptions &Opts, SmallVectorImpl<const char *> &Args, CompilerInvocation::StringAllocator SA) { const TargetOptions *TargetOpts = &Opts; -#define TARGET_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - GENERATE_OPTION_WITH_MARSHALLING( \ - Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX) +#define TARGET_OPTION_WITH_MARSHALLING(...) \ + GENERATE_OPTION_WITH_MARSHALLING(Args, SA, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef TARGET_OPTION_WITH_MARSHALLING @@ -4428,14 +4348,8 @@ static bool ParseTargetArgs(TargetOptions &Opts, ArgList &Args, TargetOptions *TargetOpts = &Opts; -#define TARGET_OPTION_WITH_MARSHALLING( \ - PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ - DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ - MERGER, EXTRACTOR, TABLE_INDEX) \ - PARSE_OPTION_WITH_MARSHALLING( \ - Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) +#define TARGET_OPTION_WITH_MARSHALLING(...) \ + PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__) #include "clang/Driver/Options.inc" #undef TARGET_OPTION_WITH_MARSHALLING @@ -4522,7 +4436,7 @@ bool CompilerInvocation::CreateFromArgsImpl( } // Set the triple of the host for OpenMP device compile. - if (LangOpts.OpenMPIsDevice) + if (LangOpts.OpenMPIsTargetDevice) Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple; ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags, T, @@ -4563,6 +4477,17 @@ bool CompilerInvocation::CreateFromArgsImpl( append_range(Res.getCodeGenOpts().CommandLineArgs, CommandLineArgs); } + // Set PGOOptions. Need to create a temporary VFS to read the profile + // to determine the PGO type. + if (!Res.getCodeGenOpts().ProfileInstrumentUsePath.empty()) { + auto FS = + createVFSFromOverlayFiles(Res.getHeaderSearchOpts().VFSOverlayFiles, + Diags, llvm::vfs::getRealFileSystem()); + setPGOUseInstrumentor(Res.getCodeGenOpts(), + Res.getCodeGenOpts().ProfileInstrumentUsePath, *FS, + Diags); + } + FixupInvocation(Res, Diags, Args, DashX); return Diags.getNumErrors() == NumErrorsBefore; diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 35b5e2144e6d..1df3a12fce14 100644 --- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -22,7 +22,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/Host.h" using namespace clang; using namespace llvm::opt; diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp index fe4218b6e672..44268e71dc24 100644 --- a/clang/lib/Frontend/DependencyFile.cpp +++ b/clang/lib/Frontend/DependencyFile.cpp @@ -49,6 +49,7 @@ struct DepCollectorPPCallbacks : public PPCallbacks { DepCollector.maybeAddDependency( llvm::sys::path::remove_leading_dotslash(*Filename), /*FromModule*/ false, isSystem(FileType), /*IsModuleFile*/ false, + &PP.getFileManager(), /*IsMissing*/ false); } @@ -56,9 +57,11 @@ struct DepCollectorPPCallbacks : public PPCallbacks { SrcMgr::CharacteristicKind FileType) override { StringRef Filename = llvm::sys::path::remove_leading_dotslash(SkippedFile.getName()); - DepCollector.maybeAddDependency(Filename, /*FromModule=*/false, + DepCollector.maybeAddDependency(Filename, + /*FromModule=*/false, /*IsSystem=*/isSystem(FileType), /*IsModuleFile=*/false, + &PP.getFileManager(), /*IsMissing=*/false); } @@ -69,9 +72,12 @@ struct DepCollectorPPCallbacks : public PPCallbacks { StringRef RelativePath, const Module *Imported, SrcMgr::CharacteristicKind FileType) override { if (!File) - DepCollector.maybeAddDependency(FileName, /*FromModule*/false, - /*IsSystem*/false, /*IsModuleFile*/false, - /*IsMissing*/true); + DepCollector.maybeAddDependency(FileName, + /*FromModule*/ false, + /*IsSystem*/ false, + /*IsModuleFile*/ false, + &PP.getFileManager(), + /*IsMissing*/ true); // Files that actually exist are handled by FileChanged. } @@ -82,9 +88,11 @@ struct DepCollectorPPCallbacks : public PPCallbacks { return; StringRef Filename = llvm::sys::path::remove_leading_dotslash(File->getName()); - DepCollector.maybeAddDependency(Filename, /*FromModule=*/false, + DepCollector.maybeAddDependency(Filename, + /*FromModule=*/false, /*IsSystem=*/isSystem(FileType), /*IsModuleFile=*/false, + &PP.getFileManager(), /*IsMissing=*/false); } @@ -100,10 +108,12 @@ struct DepCollectorMMCallbacks : public ModuleMapCallbacks { void moduleMapFileRead(SourceLocation Loc, const FileEntry &Entry, bool IsSystem) override { StringRef Filename = Entry.getName(); - DepCollector.maybeAddDependency(Filename, /*FromModule*/false, - /*IsSystem*/IsSystem, - /*IsModuleFile*/false, - /*IsMissing*/false); + DepCollector.maybeAddDependency(Filename, + /*FromModule*/ false, + /*IsSystem*/ IsSystem, + /*IsModuleFile*/ false, + /*FileMgr*/ nullptr, + /*IsMissing*/ false); } }; @@ -118,9 +128,11 @@ struct DepCollectorASTListener : public ASTReaderListener { } void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind) override { - DepCollector.maybeAddDependency(Filename, /*FromModule*/true, - /*IsSystem*/false, /*IsModuleFile*/true, - /*IsMissing*/false); + DepCollector.maybeAddDependency(Filename, + /*FromModule*/ true, + /*IsSystem*/ false, /*IsModuleFile*/ true, + /*FileMgr*/ nullptr, + /*IsMissing*/ false); } bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden, bool IsExplicitModule) override { @@ -132,8 +144,9 @@ struct DepCollectorASTListener : public ASTReaderListener { if (auto FE = FileMgr.getOptionalFileRef(Filename)) Filename = FE->getName(); - DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem, - /*IsModuleFile*/false, /*IsMissing*/false); + DepCollector.maybeAddDependency(Filename, /*FromModule*/ true, IsSystem, + /*IsModuleFile*/ false, /*FileMgr*/ nullptr, + /*IsMissing*/ false); return true; } }; @@ -142,9 +155,15 @@ struct DepCollectorASTListener : public ASTReaderListener { void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, + FileManager *FileMgr, bool IsMissing) { - if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing)) + if (sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing)) { + if (IsSystem && FileMgr && shouldCanonicalizeSystemDependencies()) { + if (auto F = FileMgr->getFile(Filename)) + Filename = FileMgr->getCanonicalName(*F); + } addDependency(Filename); + } } bool DependencyCollector::addDependency(StringRef Filename) { @@ -192,6 +211,7 @@ DependencyFileGenerator::DependencyFileGenerator( const DependencyOutputOptions &Opts) : OutputFile(Opts.OutputFile), Targets(Opts.Targets), IncludeSystemHeaders(Opts.IncludeSystemHeaders), + CanonicalSystemHeaders(Opts.CanonicalSystemHeaders), PhonyTarget(Opts.UsePhonyTargets), AddMissingHeaderDeps(Opts.AddMissingHeaderDeps), SeenMissingHeader(false), IncludeModuleFiles(Opts.IncludeModuleFiles), diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp index 9177ba9f4f06..18c8be7a7293 100644 --- a/clang/lib/Frontend/DiagnosticRenderer.cpp +++ b/clang/lib/Frontend/DiagnosticRenderer.cpp @@ -493,20 +493,18 @@ static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc, SmallVector<CharSourceRange, 4> SpellingRanges; mapDiagnosticRanges(Loc, Ranges, SpellingRanges); - /// Count all valid ranges. - unsigned ValidCount = 0; - for (const auto &Range : Ranges) - if (Range.isValid()) - ValidCount++; + // Count all valid ranges. + unsigned ValidCount = + llvm::count_if(Ranges, [](const auto &R) { return R.isValid(); }); if (ValidCount > SpellingRanges.size()) return false; - /// To store the source location of the argument location. + // To store the source location of the argument location. FullSourceLoc ArgumentLoc; - /// Set the ArgumentLoc to the beginning location of the expansion of Loc - /// so to check if the ranges expands to the same beginning location. + // Set the ArgumentLoc to the beginning location of the expansion of Loc + // so to check if the ranges expands to the same beginning location. if (!Loc.isMacroArgExpansion(&ArgumentLoc)) return false; diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 1e276642016d..c6f958a6077b 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -364,22 +364,22 @@ static std::error_code collectModuleHeaderIncludes( } // Note that Module->PrivateHeaders will not be a TopHeader. - if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { - Module->addTopHeader(UmbrellaHeader.Entry); + if (std::optional<Module::Header> UmbrellaHeader = + Module->getUmbrellaHeaderAsWritten()) { + Module->addTopHeader(UmbrellaHeader->Entry); if (Module->Parent) // Include the umbrella header for submodules. - addHeaderInclude(UmbrellaHeader.PathRelativeToRootModuleDirectory, + addHeaderInclude(UmbrellaHeader->PathRelativeToRootModuleDirectory, Includes, LangOpts, Module->IsExternC); - } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { + } else if (std::optional<Module::DirectoryName> UmbrellaDir = + Module->getUmbrellaDirAsWritten()) { // Add all of the headers we find in this subdirectory. std::error_code EC; SmallString<128> DirNative; - llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); + llvm::sys::path::native(UmbrellaDir->Entry.getName(), DirNative); llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); - SmallVector< - std::pair<std::string, OptionalFileEntryRefDegradesToFileEntryPtr>, 8> - Headers; + SmallVector<std::pair<std::string, FileEntryRef>, 8> Headers; for (llvm::vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; Dir != End && !EC; Dir.increment(EC)) { // Check whether this entry has an extension typically associated with @@ -406,7 +406,7 @@ static std::error_code collectModuleHeaderIncludes( for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) Components.push_back(*PathIt); SmallString<128> RelativeHeader( - UmbrellaDir.PathRelativeToRootModuleDirectory); + UmbrellaDir->PathRelativeToRootModuleDirectory); for (auto It = Components.rbegin(), End = Components.rend(); It != End; ++It) llvm::sys::path::append(RelativeHeader, *It); @@ -429,11 +429,9 @@ static std::error_code collectModuleHeaderIncludes( } // Recurse into submodules. - for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), - SubEnd = Module->submodule_end(); - Sub != SubEnd; ++Sub) + for (auto *Submodule : Module->submodules()) if (std::error_code Err = collectModuleHeaderIncludes( - LangOpts, FileMgr, Diag, ModMap, *Sub, Includes)) + LangOpts, FileMgr, Diag, ModMap, Submodule, Includes)) return Err; return std::error_code(); @@ -448,7 +446,8 @@ static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem, // Map the current input to a file. FileID ModuleMapID = SrcMgr.getMainFileID(); - const FileEntry *ModuleMap = SrcMgr.getFileEntryForID(ModuleMapID); + OptionalFileEntryRef ModuleMap = SrcMgr.getFileEntryRefForID(ModuleMapID); + assert(ModuleMap && "MainFileID without FileEntry"); // If the module map is preprocessed, handle the initial line marker; // line directives are not part of the module map syntax in general. @@ -461,7 +460,7 @@ static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem, } // Load the module map file. - if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset, + if (HS.loadModuleMapFile(*ModuleMap, IsSystem, ModuleMapID, &Offset, PresumedModuleMapFile)) return true; @@ -470,10 +469,11 @@ static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem, // Infer framework module if possible. if (HS.getModuleMap().canInferFrameworkModule(ModuleMap->getDir())) { - SmallString<128> InferredFrameworkPath = ModuleMap->getDir()->getName(); + SmallString<128> InferredFrameworkPath = ModuleMap->getDir().getName(); llvm::sys::path::append(InferredFrameworkPath, CI.getLangOpts().ModuleName + ".framework"); - if (auto Dir = CI.getFileManager().getDirectory(InferredFrameworkPath)) + if (auto Dir = + CI.getFileManager().getOptionalDirectoryRef(InferredFrameworkPath)) (void)HS.getModuleMap().inferFrameworkModule(*Dir, IsSystem, nullptr); } @@ -510,7 +510,7 @@ static Module *prepareToBuildModule(CompilerInstance &CI, // Inform the preprocessor that includes from within the input buffer should // be resolved relative to the build directory of the module map file. - CI.getPreprocessor().setMainFileDir(M->Directory); + CI.getPreprocessor().setMainFileDir(*M->Directory); // If the module was inferred from a different module map (via an expanded // umbrella module definition), track that fact. @@ -552,8 +552,9 @@ getInputBufferForModule(CompilerInstance &CI, Module *M) { // Collect the set of #includes we need to build the module. SmallString<256> HeaderContents; std::error_code Err = std::error_code(); - if (Module::Header UmbrellaHeader = M->getUmbrellaHeader()) - addHeaderInclude(UmbrellaHeader.PathRelativeToRootModuleDirectory, + if (std::optional<Module::Header> UmbrellaHeader = + M->getUmbrellaHeaderAsWritten()) + addHeaderInclude(UmbrellaHeader->PathRelativeToRootModuleDirectory, HeaderContents, CI.getLangOpts(), M->IsExternC); Err = collectModuleHeaderIncludes( CI.getLangOpts(), FileMgr, CI.getDiagnostics(), @@ -614,7 +615,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( std::string(InputFile), CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly, ASTDiags, CI.getFileSystemOpts(), - CI.getCodeGenOpts().DebugTypeExtRefs); + /*HeaderSearchOptions=*/nullptr, CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) return false; @@ -682,6 +683,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile( std::string(InputFile), CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(), + CI.getHeaderSearchOptsPtr(), CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) @@ -821,11 +823,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, "trying to build a header unit without a Pre-processor?"); HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); // Relative searches begin from CWD. - const DirectoryEntry *Dir = nullptr; - if (auto DirOrErr = CI.getFileManager().getDirectory(".")) - Dir = *DirOrErr; - SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1> CWD; - CWD.push_back({nullptr, Dir}); + auto Dir = CI.getFileManager().getOptionalDirectoryRef("."); + SmallVector<std::pair<const FileEntry *, DirectoryEntryRef>, 1> CWD; + CWD.push_back({nullptr, *Dir}); OptionalFileEntryRef FE = HS.LookupFile(FileName, SourceLocation(), /*Angled*/ Input.getKind().getHeaderUnitKind() == @@ -910,7 +910,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // If we were asked to load any module map files, do so now. for (const auto &Filename : CI.getFrontendOpts().ModuleMapFiles) { - if (auto File = CI.getFileManager().getFile(Filename)) + if (auto File = CI.getFileManager().getOptionalFileRef(Filename)) CI.getPreprocessor().getHeaderSearchInfo().loadModuleMapFile( *File, /*IsSystem*/false); else @@ -1117,6 +1117,9 @@ void FrontendAction::EndSourceFile() { // FrontendAction. CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles()); + // The resources are owned by AST when the current file is AST. + // So we reset the resources here to avoid users accessing it + // accidently. if (isCurrentFileAST()) { if (DisableFree) { CI.resetAndLeakPreprocessor(); diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 2d81178fa60e..8a4a4cf6823d 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -202,7 +202,8 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, /*AllowASTWithErrors=*/ +CI.getFrontendOpts().AllowPCMWithCompilerErrors, /*IncludeTimestamps=*/ - +CI.getFrontendOpts().BuildingImplicitModule, + +CI.getFrontendOpts().BuildingImplicitModule && + +CI.getFrontendOpts().IncludeTimestamps, /*ShouldCacheASTInMemory=*/ +CI.getFrontendOpts().BuildingImplicitModule)); Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator( @@ -250,11 +251,6 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, bool GenerateModuleInterfaceAction::BeginSourceFileAction( CompilerInstance &CI) { - if (!CI.getLangOpts().ModulesTS && !CI.getLangOpts().CPlusPlusModules) { - CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules); - return false; - } - CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); return GenerateModuleAction::BeginSourceFileAction(CI); @@ -376,6 +372,8 @@ private: return "ExplicitTemplateArgumentSubstitution"; case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: return "DeducedTemplateArgumentSubstitution"; + case CodeSynthesisContext::LambdaExpressionSubstitution: + return "LambdaExpressionSubstitution"; case CodeSynthesisContext::PriorTemplateArgumentSubstitution: return "PriorTemplateArgumentSubstitution"; case CodeSynthesisContext::DefaultTemplateArgumentChecking: @@ -414,6 +412,8 @@ private: return "MarkingClassDllexported"; case CodeSynthesisContext::BuildingBuiltinDumpStructCall: return "BuildingBuiltinDumpStructCall"; + case CodeSynthesisContext::BuildingDeductionGuides: + return "BuildingDeductionGuides"; } return ""; } @@ -460,6 +460,8 @@ private: return; } + assert(NamedCtx && "NamedCtx cannot be null"); + if (const auto *Decl = dyn_cast<ParmVarDecl>(NamedTemplate)) { OS << "unnamed function parameter " << Decl->getFunctionScopeIndex() << " "; @@ -763,14 +765,18 @@ static StringRef ModuleKindName(Module::ModuleKind MK) { return "Module Map Module"; case Module::ModuleInterfaceUnit: return "Interface Unit"; + case Module::ModuleImplementationUnit: + return "Implementation Unit"; case Module::ModulePartitionInterface: return "Partition Interface"; case Module::ModulePartitionImplementation: return "Partition Implementation"; case Module::ModuleHeaderUnit: return "Header Unit"; - case Module::GlobalModuleFragment: + case Module::ExplicitGlobalModuleFragment: return "Global Module Fragment"; + case Module::ImplicitGlobalModuleFragment: + return "Implicit Module Fragment"; case Module::PrivateModuleFragment: return "Private Module Fragment"; } @@ -780,14 +786,12 @@ static StringRef ModuleKindName(Module::ModuleKind MK) { void DumpModuleInfoAction::ExecuteAction() { assert(isCurrentFileAST() && "dumping non-AST?"); // Set up the output file. - std::unique_ptr<llvm::raw_fd_ostream> OutFile; CompilerInstance &CI = getCompilerInstance(); StringRef OutputFileName = CI.getFrontendOpts().OutputFile; if (!OutputFileName.empty() && OutputFileName != "-") { std::error_code EC; - OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC, - llvm::sys::fs::OF_TextWithCRLF)); - OutputStream = OutFile.get(); + OutputStream.reset(new llvm::raw_fd_ostream( + OutputFileName.str(), EC, llvm::sys::fs::OF_TextWithCRLF)); } llvm::raw_ostream &Out = OutputStream ? *OutputStream : llvm::outs(); @@ -884,7 +888,7 @@ void DumpModuleInfoAction::ExecuteAction() { } // Now let's print out any modules we did not see as part of the Primary. - for (auto SM : SubModMap) { + for (const auto &SM : SubModMap) { if (!SM.second.Seen && SM.second.Mod) { Out << " " << ModuleKindName(SM.second.Kind) << " '" << SM.first << "' at index #" << SM.second.Idx diff --git a/clang/lib/Frontend/HeaderIncludeGen.cpp b/clang/lib/Frontend/HeaderIncludeGen.cpp index 2ab480940264..9c1bf490fcd6 100644 --- a/clang/lib/Frontend/HeaderIncludeGen.cpp +++ b/clang/lib/Frontend/HeaderIncludeGen.cpp @@ -43,12 +43,27 @@ public: delete OutputFile; } + HeaderIncludesCallback(const HeaderIncludesCallback &) = delete; + HeaderIncludesCallback &operator=(const HeaderIncludesCallback &) = delete; + void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID) override; void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok, SrcMgr::CharacteristicKind FileType) override; + +private: + bool ShouldShowHeader(SrcMgr::CharacteristicKind HeaderType) { + if (!DepOpts.IncludeSystemHeaders && isSystem(HeaderType)) + return false; + + // Show the current header if we are (a) past the predefines, or (b) showing + // all headers and in the predefines at a depth past the initial file and + // command line buffers. + return (HasProcessedPredefines || + (ShowAllHeaders && CurrentIncludeDepth > 2)); + } }; /// A callback for emitting header usage information to a file in JSON. Each @@ -78,6 +93,10 @@ public: delete OutputFile; } + HeaderIncludesJSONCallback(const HeaderIncludesJSONCallback &) = delete; + HeaderIncludesJSONCallback & + operator=(const HeaderIncludesJSONCallback &) = delete; + void EndOfMainFile() override; void FileChanged(SourceLocation Loc, FileChangeReason Reason, @@ -202,38 +221,24 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc, // We track when we are done with the predefines by watching for the first // place where we drop back to a nesting depth of 1. - if (CurrentIncludeDepth == 1 && !HasProcessedPredefines) { - if (!DepOpts.ShowIncludesPretendHeader.empty()) { - PrintHeaderInfo(OutputFile, DepOpts.ShowIncludesPretendHeader, - ShowDepth, 2, MSStyle); - } + if (CurrentIncludeDepth == 1 && !HasProcessedPredefines) HasProcessedPredefines = true; - } return; - } else + } else { + return; + } + + if (!ShouldShowHeader(NewFileType)) return; - // Show the header if we are (a) past the predefines, or (b) showing all - // headers and in the predefines at a depth past the initial file and command - // line buffers. - bool ShowHeader = (HasProcessedPredefines || - (ShowAllHeaders && CurrentIncludeDepth > 2)); unsigned IncludeDepth = CurrentIncludeDepth; if (!HasProcessedPredefines) --IncludeDepth; // Ignore indent from <built-in>. - else if (!DepOpts.ShowIncludesPretendHeader.empty()) - ++IncludeDepth; // Pretend inclusion by ShowIncludesPretendHeader. - - if (!DepOpts.IncludeSystemHeaders && isSystem(NewFileType)) - ShowHeader = false; - // Dump the header include information we are past the predefines buffer or - // are showing all headers and this isn't the magic implicit <command line> - // header. // FIXME: Identify headers in a more robust way than comparing their name to // "<command line>" and "<built-in>" in a bunch of places. - if (ShowHeader && Reason == PPCallbacks::EnterFile && + if (Reason == PPCallbacks::EnterFile && UserLoc.getFilename() != StringRef("<command line>")) { PrintHeaderInfo(OutputFile, UserLoc.getFilename(), ShowDepth, IncludeDepth, MSStyle); @@ -246,7 +251,7 @@ void HeaderIncludesCallback::FileSkipped(const FileEntryRef &SkippedFile, const if (!DepOpts.ShowSkippedHeaderIncludes) return; - if (!DepOpts.IncludeSystemHeaders && isSystem(FileType)) + if (!ShouldShowHeader(FileType)) return; PrintHeaderInfo(OutputFile, SkippedFile.getName(), ShowDepth, diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 208c6a8db159..f8fae82fba12 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -451,9 +451,11 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { // -- __cplusplus - // FIXME: Use correct value for C++23. - if (LangOpts.CPlusPlus2b) - Builder.defineMacro("__cplusplus", "202101L"); + if (LangOpts.CPlusPlus26) + // FIXME: Use correct value for C++26. + Builder.defineMacro("__cplusplus", "202400L"); + else if (LangOpts.CPlusPlus23) + Builder.defineMacro("__cplusplus", "202302L"); // [C++20] The integer literal 202002L. else if (LangOpts.CPlusPlus20) Builder.defineMacro("__cplusplus", "202002L"); @@ -572,6 +574,9 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__CLANG_RDC__"); if (!LangOpts.HIP) Builder.defineMacro("__CUDA__"); + if (LangOpts.GPUDefaultStream == + LangOptions::GPUDefaultStreamKind::PerThread) + Builder.defineMacro("CUDA_API_PER_THREAD_DEFAULT_STREAM"); } if (LangOpts.HIP) { Builder.defineMacro("__HIP__"); @@ -581,11 +586,20 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__HIP_MEMORY_SCOPE_WORKGROUP", "3"); Builder.defineMacro("__HIP_MEMORY_SCOPE_AGENT", "4"); Builder.defineMacro("__HIP_MEMORY_SCOPE_SYSTEM", "5"); - if (LangOpts.CUDAIsDevice) + if (LangOpts.CUDAIsDevice) { Builder.defineMacro("__HIP_DEVICE_COMPILE__"); + if (!TI.hasHIPImageSupport()) { + Builder.defineMacro("__HIP_NO_IMAGE_SUPPORT__", "1"); + // Deprecated. + Builder.defineMacro("__HIP_NO_IMAGE_SUPPORT", "1"); + } + } if (LangOpts.GPUDefaultStream == - LangOptions::GPUDefaultStreamKind::PerThread) + LangOptions::GPUDefaultStreamKind::PerThread) { + Builder.defineMacro("__HIP_API_PER_THREAD_DEFAULT_STREAM__"); + // Deprecated. Builder.defineMacro("HIP_API_PER_THREAD_DEFAULT_STREAM"); + } } } @@ -606,7 +620,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_unicode_literals", "200710L"); Builder.defineMacro("__cpp_user_defined_literals", "200809L"); Builder.defineMacro("__cpp_lambdas", "200907L"); - Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus2b ? "202211L" + Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus26 ? "202306L" + : LangOpts.CPlusPlus23 ? "202211L" : LangOpts.CPlusPlus20 ? "201907L" : LangOpts.CPlusPlus17 ? "201603L" : LangOpts.CPlusPlus14 ? "201304L" @@ -614,8 +629,10 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_constexpr_in_decltype", "201711L"); Builder.defineMacro("__cpp_range_based_for", LangOpts.CPlusPlus17 ? "201603L" : "200907"); - Builder.defineMacro("__cpp_static_assert", - LangOpts.CPlusPlus17 ? "201411L" : "200410"); + Builder.defineMacro("__cpp_static_assert", LangOpts.CPlusPlus26 ? "202306L" + : LangOpts.CPlusPlus17 + ? "201411L" + : "200410"); Builder.defineMacro("__cpp_decltype", "200707L"); Builder.defineMacro("__cpp_attributes", "200809L"); Builder.defineMacro("__cpp_rvalue_references", "200610L"); @@ -681,7 +698,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, // Refer to the discussion of this at https://reviews.llvm.org/D128619. Builder.defineMacro("__cpp_concepts", "201907L"); Builder.defineMacro("__cpp_conditional_explicit", "201806L"); - //Builder.defineMacro("__cpp_consteval", "201811L"); + Builder.defineMacro("__cpp_consteval", "202211L"); Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); Builder.defineMacro("__cpp_constinit", "201907L"); Builder.defineMacro("__cpp_impl_coroutine", "201902L"); @@ -690,15 +707,15 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, //Builder.defineMacro("__cpp_modules", "201907L"); Builder.defineMacro("__cpp_using_enum", "201907L"); } - // C++2b features. - if (LangOpts.CPlusPlus2b) { + // C++23 features. + if (LangOpts.CPlusPlus23) { Builder.defineMacro("__cpp_implicit_move", "202011L"); Builder.defineMacro("__cpp_size_t_suffix", "202011L"); Builder.defineMacro("__cpp_if_consteval", "202106L"); Builder.defineMacro("__cpp_multidimensional_subscript", "202211L"); } - // We provide those C++2b features as extensions in earlier language modes, so + // We provide those C++23 features as extensions in earlier language modes, so // we also define their feature test macros. if (LangOpts.CPlusPlus11) Builder.defineMacro("__cpp_static_call_operator", "202207L"); @@ -707,10 +724,6 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, if (LangOpts.Char8) Builder.defineMacro("__cpp_char8_t", "202207L"); Builder.defineMacro("__cpp_impl_destroying_delete", "201806L"); - - // TS features. - if (LangOpts.Coroutines) - Builder.defineMacro("__cpp_coroutines", "201703L"); } /// InitializeOpenCLFeatureTestMacros - Define OpenCL macros based on target @@ -794,6 +807,18 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES", "3"); Builder.defineMacro("__OPENCL_MEMORY_SCOPE_SUB_GROUP", "4"); + // Define macros for floating-point data classes, used in __builtin_isfpclass. + Builder.defineMacro("__FPCLASS_SNAN", "0x0001"); + Builder.defineMacro("__FPCLASS_QNAN", "0x0002"); + Builder.defineMacro("__FPCLASS_NEGINF", "0x0004"); + Builder.defineMacro("__FPCLASS_NEGNORMAL", "0x0008"); + Builder.defineMacro("__FPCLASS_NEGSUBNORMAL", "0x0010"); + Builder.defineMacro("__FPCLASS_NEGZERO", "0x0020"); + Builder.defineMacro("__FPCLASS_POSZERO", "0x0040"); + Builder.defineMacro("__FPCLASS_POSSUBNORMAL", "0x0080"); + Builder.defineMacro("__FPCLASS_POSNORMAL", "0x0100"); + Builder.defineMacro("__FPCLASS_POSINF", "0x0200"); + // Support for #pragma redefine_extname (Sun compatibility) Builder.defineMacro("__PRAGMA_REDEFINE_EXTNAME", "1"); @@ -1252,16 +1277,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI, case 45: Builder.defineMacro("_OPENMP", "201511"); break; - case 51: - Builder.defineMacro("_OPENMP", "202011"); + case 50: + Builder.defineMacro("_OPENMP", "201811"); break; case 52: Builder.defineMacro("_OPENMP", "202111"); break; - case 50: - default: - // Default version is OpenMP 5.0 - Builder.defineMacro("_OPENMP", "201811"); + default: // case 51: + // Default version is OpenMP 5.1 + Builder.defineMacro("_OPENMP", "202011"); break; } } @@ -1301,6 +1325,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__GLIBCXX_BITSIZE_INT_N_0", "128"); } + // ELF targets define __ELF__ + if (TI.getTriple().isOSBinFormatELF()) + Builder.defineMacro("__ELF__"); + // Get other target #defines. TI.getTargetDefines(LangOpts, Builder); } @@ -1317,17 +1345,17 @@ void clang::InitializePreprocessor( llvm::raw_string_ostream Predefines(PredefineBuffer); MacroBuilder Builder(Predefines); - // Emit line markers for various builtin sections of the file. We don't do - // this in asm preprocessor mode, because "# 4" is not a line marker directive - // in this mode. - if (!PP.getLangOpts().AsmPreprocessor) - Builder.append("# 1 \"<built-in>\" 3"); + // Emit line markers for various builtin sections of the file. The 3 here + // marks <built-in> as being a system header, which suppresses warnings when + // the same macro is defined multiple times. + Builder.append("# 1 \"<built-in>\" 3"); // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) { // FIXME: This will create multiple definitions for most of the predefined // macros. This is not the right way to handle this. - if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice || LangOpts.SYCLIsDevice) && + if ((LangOpts.CUDA || LangOpts.OpenMPIsTargetDevice || + LangOpts.SYCLIsDevice) && PP.getAuxTargetInfo()) InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts, PP.getPreprocessorOpts(), Builder); @@ -1359,8 +1387,7 @@ void clang::InitializePreprocessor( // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. - if (!PP.getLangOpts().AsmPreprocessor) - Builder.append("# 1 \"<command line>\" 1"); + Builder.append("# 1 \"<command line>\" 1"); // Process #define's and #undef's in the order they are given. for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { @@ -1372,8 +1399,7 @@ void clang::InitializePreprocessor( } // Exit the command line and go back to <built-in> (2 is LC_LEAVE). - if (!PP.getLangOpts().AsmPreprocessor) - Builder.append("# 1 \"<built-in>\" 2"); + Builder.append("# 1 \"<built-in>\" 2"); // If -imacros are specified, include them now. These are processed before // any -include directives. diff --git a/clang/lib/Frontend/LayoutOverrideSource.cpp b/clang/lib/Frontend/LayoutOverrideSource.cpp index 0d288db0632f..f474d4fe8fdc 100644 --- a/clang/lib/Frontend/LayoutOverrideSource.cpp +++ b/clang/lib/Frontend/LayoutOverrideSource.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/LayoutOverrideSource.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/Basic/CharInfo.h" #include "llvm/Support/raw_ostream.h" #include <fstream> @@ -26,6 +27,18 @@ static std::string parseName(StringRef S) { return S.substr(0, Offset).str(); } +/// Parse an unsigned integer and move S to the next non-digit character. +static bool parseUnsigned(StringRef &S, unsigned long long &ULL) { + if (S.empty() || !isDigit(S[0])) + return false; + unsigned Idx = 1; + while (Idx < S.size() && isDigit(S[Idx])) + ++Idx; + (void)S.substr(0, Idx).getAsInteger(10, ULL); + S = S.substr(Idx); + return true; +} + LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { std::ifstream Input(Filename.str().c_str()); if (!Input.is_open()) @@ -80,8 +93,8 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { LineStr = LineStr.substr(Pos + strlen(" Size:")); unsigned long long Size = 0; - (void)LineStr.getAsInteger(10, Size); - CurrentLayout.Size = Size; + if (parseUnsigned(LineStr, Size)) + CurrentLayout.Size = Size; continue; } @@ -92,12 +105,13 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { LineStr = LineStr.substr(Pos + strlen("Alignment:")); unsigned long long Alignment = 0; - (void)LineStr.getAsInteger(10, Alignment); - CurrentLayout.Align = Alignment; + if (parseUnsigned(LineStr, Alignment)) + CurrentLayout.Align = Alignment; continue; } - // Check for the size/alignment of the type. + // Check for the size/alignment of the type. The number follows "size=" or + // "align=" indicates number of bytes. Pos = LineStr.find("sizeof="); if (Pos != StringRef::npos) { /* Skip past the sizeof= prefix. */ @@ -105,8 +119,8 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { // Parse size. unsigned long long Size = 0; - (void)LineStr.getAsInteger(10, Size); - CurrentLayout.Size = Size; + if (parseUnsigned(LineStr, Size)) + CurrentLayout.Size = Size * 8; Pos = LineStr.find("align="); if (Pos != StringRef::npos) { @@ -115,8 +129,8 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { // Parse alignment. unsigned long long Alignment = 0; - (void)LineStr.getAsInteger(10, Alignment); - CurrentLayout.Align = Alignment; + if (parseUnsigned(LineStr, Alignment)) + CurrentLayout.Align = Alignment * 8; } continue; @@ -124,25 +138,51 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { // Check for the field offsets of the type. Pos = LineStr.find("FieldOffsets: ["); - if (Pos == StringRef::npos) - continue; + if (Pos != StringRef::npos) { + LineStr = LineStr.substr(Pos + strlen("FieldOffsets: [")); + while (!LineStr.empty() && isDigit(LineStr[0])) { + unsigned long long Offset = 0; + if (parseUnsigned(LineStr, Offset)) + CurrentLayout.FieldOffsets.push_back(Offset); - LineStr = LineStr.substr(Pos + strlen("FieldOffsets: [")); - while (!LineStr.empty() && isDigit(LineStr[0])) { - // Parse this offset. - unsigned Idx = 1; - while (Idx < LineStr.size() && isDigit(LineStr[Idx])) - ++Idx; + // Skip over this offset, the following comma, and any spaces. + LineStr = LineStr.substr(1); + while (!LineStr.empty() && isWhitespace(LineStr[0])) + LineStr = LineStr.substr(1); + } + } - unsigned long long Offset = 0; - (void)LineStr.substr(0, Idx).getAsInteger(10, Offset); + // Check for the virtual base offsets. + Pos = LineStr.find("VBaseOffsets: ["); + if (Pos != StringRef::npos) { + LineStr = LineStr.substr(Pos + strlen("VBaseOffsets: [")); + while (!LineStr.empty() && isDigit(LineStr[0])) { + unsigned long long Offset = 0; + if (parseUnsigned(LineStr, Offset)) + CurrentLayout.VBaseOffsets.push_back(CharUnits::fromQuantity(Offset)); - CurrentLayout.FieldOffsets.push_back(Offset); + // Skip over this offset, the following comma, and any spaces. + LineStr = LineStr.substr(1); + while (!LineStr.empty() && isWhitespace(LineStr[0])) + LineStr = LineStr.substr(1); + } + continue; + } - // Skip over this offset, the following comma, and any spaces. - LineStr = LineStr.substr(Idx + 1); - while (!LineStr.empty() && isWhitespace(LineStr[0])) + // Check for the base offsets. + Pos = LineStr.find("BaseOffsets: ["); + if (Pos != StringRef::npos) { + LineStr = LineStr.substr(Pos + strlen("BaseOffsets: [")); + while (!LineStr.empty() && isDigit(LineStr[0])) { + unsigned long long Offset = 0; + if (parseUnsigned(LineStr, Offset)) + CurrentLayout.BaseOffsets.push_back(CharUnits::fromQuantity(Offset)); + + // Skip over this offset, the following comma, and any spaces. LineStr = LineStr.substr(1); + while (!LineStr.empty() && isWhitespace(LineStr[0])) + LineStr = LineStr.substr(1); + } } } @@ -182,6 +222,24 @@ LayoutOverrideSource::layoutRecordType(const RecordDecl *Record, if (NumFields != Known->second.FieldOffsets.size()) return false; + // Provide base offsets. + if (const auto *RD = dyn_cast<CXXRecordDecl>(Record)) { + unsigned NumNB = 0; + unsigned NumVB = 0; + for (const auto &I : RD->vbases()) { + if (NumVB >= Known->second.VBaseOffsets.size()) + continue; + const CXXRecordDecl *VBase = I.getType()->getAsCXXRecordDecl(); + VirtualBaseOffsets[VBase] = Known->second.VBaseOffsets[NumVB++]; + } + for (const auto &I : RD->bases()) { + if (I.isVirtual() || NumNB >= Known->second.BaseOffsets.size()) + continue; + const CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl(); + BaseOffsets[Base] = Known->second.BaseOffsets[NumNB++]; + } + } + Size = Known->second.Size; Alignment = Known->second.Align; return true; diff --git a/clang/lib/Frontend/ModuleDependencyCollector.cpp b/clang/lib/Frontend/ModuleDependencyCollector.cpp index b4b312bc93b9..939e611e5489 100644 --- a/clang/lib/Frontend/ModuleDependencyCollector.cpp +++ b/clang/lib/Frontend/ModuleDependencyCollector.cpp @@ -72,37 +72,12 @@ struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks { if (llvm::sys::path::is_absolute(HeaderPath)) Collector.addFile(HeaderPath); } - void moduleMapAddUmbrellaHeader(FileManager *FileMgr, - const FileEntry *Header) override { - StringRef HeaderFilename = Header->getName(); - moduleMapAddHeader(HeaderFilename); - // The FileManager can find and cache the symbolic link for a framework - // header before its real path, this means a module can have some of its - // headers to use other paths. Although this is usually not a problem, it's - // inconsistent, and not collecting the original path header leads to - // umbrella clashes while rebuilding modules in the crash reproducer. For - // example: - // ApplicationServices.framework/Frameworks/ImageIO.framework/ImageIO.h - // instead of: - // ImageIO.framework/ImageIO.h - // - // FIXME: this shouldn't be necessary once we have FileName instances - // around instead of FileEntry ones. For now, make sure we collect all - // that we need for the reproducer to work correctly. - StringRef UmbreallDirFromHeader = - llvm::sys::path::parent_path(HeaderFilename); - StringRef UmbrellaDir = Header->getDir()->getName(); - if (!UmbrellaDir.equals(UmbreallDirFromHeader)) { - SmallString<128> AltHeaderFilename; - llvm::sys::path::append(AltHeaderFilename, UmbrellaDir, - llvm::sys::path::filename(HeaderFilename)); - if (FileMgr->getFile(AltHeaderFilename)) - moduleMapAddHeader(AltHeaderFilename); - } + void moduleMapAddUmbrellaHeader(FileEntryRef Header) override { + moduleMapAddHeader(Header.getNameAsRequested()); } }; -} +} // namespace void ModuleDependencyCollector::attachToASTReader(ASTReader &R) { R.addListener( diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp index 579a0b8b614d..5ffb54e2fdf6 100644 --- a/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -113,16 +113,16 @@ public: // Reconstruct the filenames that would satisfy this directive... llvm::SmallString<256> Buf; - auto NotFoundRelativeTo = [&](const DirectoryEntry *DE) { - Buf = DE->getName(); + auto NotFoundRelativeTo = [&](DirectoryEntryRef DE) { + Buf = DE.getName(); llvm::sys::path::append(Buf, FileName); llvm::sys::path::remove_dots(Buf, /*remove_dot_dot=*/true); Out.insert(Buf); }; // ...relative to the including file. if (!IsAngled) { - if (const FileEntry *IncludingFile = - SM.getFileEntryForID(SM.getFileID(IncludeTok.getLocation()))) + if (OptionalFileEntryRef IncludingFile = + SM.getFileEntryRefForID(SM.getFileID(IncludeTok.getLocation()))) if (IncludingFile->getDir()) NotFoundRelativeTo(IncludingFile->getDir()); } @@ -132,7 +132,7 @@ public: Search.search_dir_end())) { // No support for frameworks or header maps yet. if (Dir.isNormalDir()) - NotFoundRelativeTo(Dir.getDir()); + NotFoundRelativeTo(*Dir.getDirRef()); } } }; @@ -197,20 +197,32 @@ void TemporaryFiles::removeFile(StringRef File) { class TempPCHFile { public: // A main method used to construct TempPCHFile. - static std::unique_ptr<TempPCHFile> create() { + static std::unique_ptr<TempPCHFile> create(StringRef StoragePath) { // FIXME: This is a hack so that we can override the preamble file during // crash-recovery testing, which is the only case where the preamble files // are not necessarily cleaned up. if (const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE")) return std::unique_ptr<TempPCHFile>(new TempPCHFile(TmpFile)); - llvm::SmallString<64> File; - // Using a version of createTemporaryFile with a file descriptor guarantees + llvm::SmallString<128> File; + // Using the versions of createTemporaryFile() and + // createUniqueFile() with a file descriptor guarantees // that we would never get a race condition in a multi-threaded setting // (i.e., multiple threads getting the same temporary path). int FD; - if (auto EC = - llvm::sys::fs::createTemporaryFile("preamble", "pch", FD, File)) + std::error_code EC; + if (StoragePath.empty()) + EC = llvm::sys::fs::createTemporaryFile("preamble", "pch", FD, File); + else { + llvm::SmallString<128> TempPath = StoragePath; + // Use the same filename model as fs::createTemporaryFile(). + llvm::sys::path::append(TempPath, "preamble-%%%%%%.pch"); + namespace fs = llvm::sys::fs; + // Use the same owner-only file permissions as fs::createTemporaryFile(). + EC = fs::createUniqueFile(TempPath, FD, File, fs::OF_None, + fs::owner_read | fs::owner_write); + } + if (EC) return nullptr; // We only needed to make sure the file exists, close the file right away. llvm::sys::Process::SafelyCloseFileDescriptor(FD); @@ -403,7 +415,7 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory, - PreambleCallbacks &Callbacks) { + StringRef StoragePath, PreambleCallbacks &Callbacks) { assert(VFS && "VFS is null"); auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation); @@ -418,7 +430,8 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( } else { // Create a temporary file for the precompiled preamble. In rare // circumstances, this can fail. - std::unique_ptr<TempPCHFile> PreamblePCHFile = TempPCHFile::create(); + std::unique_ptr<TempPCHFile> PreamblePCHFile = + TempPCHFile::create(StoragePath); if (!PreamblePCHFile) return BuildPreambleError::CouldntCreateTempFile; Storage = PCHStorage::file(std::move(PreamblePCHFile)); diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index ffa85e523c03..1b262d9e6f7c 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -663,7 +663,8 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, // them. if (Tok.is(tok::eof) || (Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) && - !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end))) + !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end) && + !Tok.is(tok::annot_repl_input_end))) return; // EmittedDirectiveOnThisLine takes priority over RequireSameLine. @@ -819,6 +820,9 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // -traditional-cpp the lexer keeps /all/ whitespace, including comments. PP.Lex(Tok); continue; + } else if (Tok.is(tok::annot_repl_input_end)) { + PP.Lex(Tok); + continue; } else if (Tok.is(tok::eod)) { // Don't print end of directive tokens, since they are typically newlines // that mess up our line tracking. These come from unknown pre-processor diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 6685109f8d33..14569013b92c 100644 --- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -165,10 +165,11 @@ RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { if (std::unique_ptr<raw_ostream> OS = CI.createDefaultOutputFile(false, InFile, "cpp")) { if (CI.getLangOpts().ObjCRuntime.isNonFragile()) - return CreateModernObjCRewriter( - std::string(InFile), std::move(OS), CI.getDiagnostics(), - CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros, - (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo)); + return CreateModernObjCRewriter(std::string(InFile), std::move(OS), + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros, + (CI.getCodeGenOpts().getDebugInfo() != + llvm::codegenoptions::NoDebugInfo)); return CreateObjCRewriter(std::string(InFile), std::move(OS), CI.getDiagnostics(), CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros); diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp index fc8fce4b42b8..b76728acb907 100644 --- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -37,14 +37,12 @@ public: AbbreviationMap() {} void set(unsigned recordID, unsigned abbrevID) { - assert(Abbrevs.find(recordID) == Abbrevs.end() - && "Abbreviation already set."); + assert(!Abbrevs.contains(recordID) && "Abbreviation already set."); Abbrevs[recordID] = abbrevID; } unsigned get(unsigned recordID) { - assert(Abbrevs.find(recordID) != Abbrevs.end() && - "Abbreviation not set."); + assert(Abbrevs.contains(recordID) && "Abbreviation not set."); return Abbrevs[recordID]; } }; diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp index 809d5309d1af..3a3cc246d3af 100644 --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -91,89 +91,108 @@ static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) { /// printableTextForNextCharacter. /// /// \param SourceLine The line of source -/// \param i Pointer to byte index, +/// \param I Pointer to byte index, /// \param TabStop used to expand tabs /// \return pair(printable text, 'true' iff original text was printable) /// static std::pair<SmallString<16>, bool> -printableTextForNextCharacter(StringRef SourceLine, size_t *i, +printableTextForNextCharacter(StringRef SourceLine, size_t *I, unsigned TabStop) { - assert(i && "i must not be null"); - assert(*i<SourceLine.size() && "must point to a valid index"); + assert(I && "I must not be null"); + assert(*I < SourceLine.size() && "must point to a valid index"); - if (SourceLine[*i]=='\t') { + if (SourceLine[*I] == '\t') { assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && "Invalid -ftabstop value"); - unsigned col = bytesSincePreviousTabOrLineBegin(SourceLine, *i); - unsigned NumSpaces = TabStop - col%TabStop; + unsigned Col = bytesSincePreviousTabOrLineBegin(SourceLine, *I); + unsigned NumSpaces = TabStop - (Col % TabStop); assert(0 < NumSpaces && NumSpaces <= TabStop && "Invalid computation of space amt"); - ++(*i); + ++(*I); - SmallString<16> expandedTab; - expandedTab.assign(NumSpaces, ' '); - return std::make_pair(expandedTab, true); + SmallString<16> ExpandedTab; + ExpandedTab.assign(NumSpaces, ' '); + return std::make_pair(ExpandedTab, true); } - unsigned char const *begin, *end; - begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i)); - end = begin + (SourceLine.size() - *i); - - if (llvm::isLegalUTF8Sequence(begin, end)) { - llvm::UTF32 c; - llvm::UTF32 *cptr = &c; - unsigned char const *original_begin = begin; - unsigned char const *cp_end = - begin + llvm::getNumBytesForUTF8(SourceLine[*i]); - - llvm::ConversionResult res = llvm::ConvertUTF8toUTF32( - &begin, cp_end, &cptr, cptr + 1, llvm::strictConversion); - (void)res; - assert(llvm::conversionOK == res); - assert(0 < begin-original_begin - && "we must be further along in the string now"); - *i += begin-original_begin; - - if (!llvm::sys::locale::isPrint(c)) { - // If next character is valid UTF-8, but not printable - SmallString<16> expandedCP("<U+>"); - while (c) { - expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(c%16)); - c/=16; - } - while (expandedCP.size() < 8) - expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(0)); - return std::make_pair(expandedCP, false); - } - - // If next character is valid UTF-8, and printable - return std::make_pair(SmallString<16>(original_begin, cp_end), true); + const unsigned char *Begin = SourceLine.bytes_begin() + *I; + // Fast path for the common ASCII case. + if (*Begin < 0x80 && llvm::sys::locale::isPrint(*Begin)) { + ++(*I); + return std::make_pair(SmallString<16>(Begin, Begin + 1), true); + } + unsigned CharSize = llvm::getNumBytesForUTF8(*Begin); + const unsigned char *End = Begin + CharSize; + + // Convert it to UTF32 and check if it's printable. + if (End <= SourceLine.bytes_end() && llvm::isLegalUTF8Sequence(Begin, End)) { + llvm::UTF32 C; + llvm::UTF32 *CPtr = &C; + + // Begin and end before conversion. + unsigned char const *OriginalBegin = Begin; + llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32( + &Begin, End, &CPtr, CPtr + 1, llvm::strictConversion); + (void)Res; + assert(Res == llvm::conversionOK); + assert(OriginalBegin < Begin); + assert((Begin - OriginalBegin) == CharSize); + + (*I) += (Begin - OriginalBegin); + + // Valid, multi-byte, printable UTF8 character. + if (llvm::sys::locale::isPrint(C)) + return std::make_pair(SmallString<16>(OriginalBegin, End), true); + + // Valid but not printable. + SmallString<16> Str("<U+>"); + while (C) { + Str.insert(Str.begin() + 3, llvm::hexdigit(C % 16)); + C /= 16; + } + while (Str.size() < 8) + Str.insert(Str.begin() + 3, llvm::hexdigit(0)); + return std::make_pair(Str, false); } - // If next byte is not valid UTF-8 (and therefore not printable) - SmallString<16> expandedByte("<XX>"); - unsigned char byte = SourceLine[*i]; - expandedByte[1] = llvm::hexdigit(byte / 16); - expandedByte[2] = llvm::hexdigit(byte % 16); - ++(*i); - return std::make_pair(expandedByte, false); + // Otherwise, not printable since it's not valid UTF8. + SmallString<16> ExpandedByte("<XX>"); + unsigned char Byte = SourceLine[*I]; + ExpandedByte[1] = llvm::hexdigit(Byte / 16); + ExpandedByte[2] = llvm::hexdigit(Byte % 16); + ++(*I); + return std::make_pair(ExpandedByte, false); } static void expandTabs(std::string &SourceLine, unsigned TabStop) { - size_t i = SourceLine.size(); - while (i>0) { - i--; - if (SourceLine[i]!='\t') + size_t I = SourceLine.size(); + while (I > 0) { + I--; + if (SourceLine[I] != '\t') continue; - size_t tmp_i = i; - std::pair<SmallString<16>,bool> res - = printableTextForNextCharacter(SourceLine, &tmp_i, TabStop); - SourceLine.replace(i, 1, res.first.c_str()); + size_t TmpI = I; + auto [Str, Printable] = + printableTextForNextCharacter(SourceLine, &TmpI, TabStop); + SourceLine.replace(I, 1, Str.c_str()); } } -/// This function takes a raw source line and produces a mapping from the bytes +/// \p BytesOut: +/// A mapping from columns to the byte of the source line that produced the +/// character displaying at that column. This is the inverse of \p ColumnsOut. +/// +/// The last element in the array is the number of bytes in the source string. +/// +/// example: (given a tabstop of 8) +/// +/// "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7} +/// +/// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to +/// display) +/// +/// \p ColumnsOut: +/// A mapping from the bytes /// of the printable representation of the line to the columns those printable /// characters will appear at (numbering the first column as 0). /// @@ -195,60 +214,34 @@ static void expandTabs(std::string &SourceLine, unsigned TabStop) { /// /// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to /// display) -static void byteToColumn(StringRef SourceLine, unsigned TabStop, - SmallVectorImpl<int> &out) { - out.clear(); +static void genColumnByteMapping(StringRef SourceLine, unsigned TabStop, + SmallVectorImpl<int> &BytesOut, + SmallVectorImpl<int> &ColumnsOut) { + assert(BytesOut.empty()); + assert(ColumnsOut.empty()); if (SourceLine.empty()) { - out.resize(1u,0); + BytesOut.resize(1u, 0); + ColumnsOut.resize(1u, 0); return; } - out.resize(SourceLine.size()+1, -1); - - int columns = 0; - size_t i = 0; - while (i<SourceLine.size()) { - out[i] = columns; - std::pair<SmallString<16>,bool> res - = printableTextForNextCharacter(SourceLine, &i, TabStop); - columns += llvm::sys::locale::columnWidth(res.first); - } - out.back() = columns; -} - -/// This function takes a raw source line and produces a mapping from columns -/// to the byte of the source line that produced the character displaying at -/// that column. This is the inverse of the mapping produced by byteToColumn() -/// -/// The last element in the array is the number of bytes in the source string -/// -/// example: (given a tabstop of 8) -/// -/// "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7} -/// -/// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to -/// display) -static void columnToByte(StringRef SourceLine, unsigned TabStop, - SmallVectorImpl<int> &out) { - out.clear(); - - if (SourceLine.empty()) { - out.resize(1u, 0); - return; + ColumnsOut.resize(SourceLine.size() + 1, -1); + + int Columns = 0; + size_t I = 0; + while (I < SourceLine.size()) { + ColumnsOut[I] = Columns; + BytesOut.resize(Columns + 1, -1); + BytesOut.back() = I; + auto [Str, Printable] = + printableTextForNextCharacter(SourceLine, &I, TabStop); + Columns += llvm::sys::locale::columnWidth(Str); } - int columns = 0; - size_t i = 0; - while (i<SourceLine.size()) { - out.resize(columns+1, -1); - out.back() = i; - std::pair<SmallString<16>,bool> res - = printableTextForNextCharacter(SourceLine, &i, TabStop); - columns += llvm::sys::locale::columnWidth(res.first); - } - out.resize(columns+1, -1); - out.back() = i; + ColumnsOut.back() = Columns; + BytesOut.resize(Columns + 1, -1); + BytesOut.back() = I; } namespace { @@ -256,8 +249,7 @@ struct SourceColumnMap { SourceColumnMap(StringRef SourceLine, unsigned TabStop) : m_SourceLine(SourceLine) { - ::byteToColumn(SourceLine, TabStop, m_byteToColumn); - ::columnToByte(SourceLine, TabStop, m_columnToByte); + genColumnByteMapping(SourceLine, TabStop, m_columnToByte, m_byteToColumn); assert(m_byteToColumn.size()==SourceLine.size()+1); assert(0 < m_byteToColumn.size() && 0 < m_columnToByte.size()); @@ -471,9 +463,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine, CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource; // [CaretStart, CaretEnd) is the slice we want. Update the various - // output lines to show only this slice, with two-space padding - // before the lines so that it looks nicer. - + // output lines to show only this slice. assert(CaretStart!=(unsigned)-1 && CaretEnd!=(unsigned)-1 && SourceStart!=(unsigned)-1 && SourceEnd!=(unsigned)-1); assert(SourceStart <= SourceEnd); @@ -605,21 +595,13 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str, /// Str will be printed. This will be non-zero when part of the first /// line has already been printed. /// \param Bold if the current text should be bold -/// \param Indentation the number of spaces to indent any lines beyond -/// the first line. /// \returns true if word-wrapping was required, or false if the /// string fit on the first line. -static bool printWordWrapped(raw_ostream &OS, StringRef Str, - unsigned Columns, - unsigned Column = 0, - bool Bold = false, - unsigned Indentation = WordWrapIndentation) { +static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns, + unsigned Column, bool Bold) { const unsigned Length = std::min(Str.find('\n'), Str.size()); bool TextNormal = true; - // The string used to indent each line. - SmallString<16> IndentStr; - IndentStr.assign(Indentation, ' '); bool Wrapped = false; for (unsigned WordStart = 0, WordEnd; WordStart < Length; WordStart = WordEnd) { @@ -648,10 +630,10 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, // This word does not fit on the current line, so wrap to the next // line. OS << '\n'; - OS.write(&IndentStr[0], Indentation); + OS.indent(WordWrapIndentation); applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength), TextNormal, Bold); - Column = Indentation + WordLength; + Column = WordWrapIndentation + WordLength; Wrapped = true; } @@ -787,7 +769,7 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) { /// Print out the file/line/column information and include trace. /// -/// This method handlen the emission of the diagnostic location information. +/// This method handles the emission of the diagnostic location information. /// This includes extracting as much location information as is present for /// the diagnostic and printing it, as well as any include stack or source /// ranges necessary. @@ -796,8 +778,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, ArrayRef<CharSourceRange> Ranges) { if (PLoc.isInvalid()) { // At least print the file name if available: - FileID FID = Loc.getFileID(); - if (FID.isValid()) { + if (FileID FID = Loc.getFileID(); FID.isValid()) { if (const FileEntry *FE = Loc.getFileEntry()) { emitFilename(FE->getName(), Loc.getManager()); OS << ": "; @@ -855,31 +836,26 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { FileID CaretFileID = Loc.getExpansionLoc().getFileID(); bool PrintedRange = false; + const SourceManager &SM = Loc.getManager(); - for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(), - RE = Ranges.end(); - RI != RE; ++RI) { + for (const auto &R : Ranges) { // Ignore invalid ranges. - if (!RI->isValid()) continue; + if (!R.isValid()) + continue; - auto &SM = Loc.getManager(); - SourceLocation B = SM.getExpansionLoc(RI->getBegin()); - CharSourceRange ERange = SM.getExpansionRange(RI->getEnd()); + SourceLocation B = SM.getExpansionLoc(R.getBegin()); + CharSourceRange ERange = SM.getExpansionRange(R.getEnd()); SourceLocation E = ERange.getEnd(); - bool IsTokenRange = ERange.isTokenRange(); - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); - - // If the start or end of the range is in another file, just discard - // it. - if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) + // If the start or end of the range is in another file, just + // discard it. + if (SM.getFileID(B) != CaretFileID || SM.getFileID(E) != CaretFileID) continue; // Add in the length of the token, so that we cover multi-char // tokens. unsigned TokSize = 0; - if (IsTokenRange) + if (ERange.isTokenRange()) TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts); FullSourceLoc BF(B, SM), EF(E, SM); @@ -897,10 +873,11 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, } void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) { - if (DiagOpts->ShowLocation && PLoc.isValid()) - OS << "In file included from " << PLoc.getFilename() << ':' - << PLoc.getLine() << ":\n"; - else + if (DiagOpts->ShowLocation && PLoc.isValid()) { + OS << "In file included from "; + emitFilename(PLoc.getFilename(), Loc.getManager()); + OS << ':' << PLoc.getLine() << ":\n"; + } else OS << "In included file:\n"; } @@ -974,87 +951,43 @@ maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B, return A; } -/// Highlight a SourceRange (with ~'s) for any characters on LineNo. -static void highlightRange(const CharSourceRange &R, - unsigned LineNo, FileID FID, - const SourceColumnMap &map, - std::string &CaretLine, - const SourceManager &SM, - const LangOptions &LangOpts) { - if (!R.isValid()) return; - - SourceLocation Begin = R.getBegin(); - SourceLocation End = R.getEnd(); - - unsigned StartLineNo = SM.getExpansionLineNumber(Begin); - if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) - return; // No intersection. - - unsigned EndLineNo = SM.getExpansionLineNumber(End); - if (EndLineNo < LineNo || SM.getFileID(End) != FID) - return; // No intersection. - - // Compute the column number of the start. - unsigned StartColNo = 0; - if (StartLineNo == LineNo) { - StartColNo = SM.getExpansionColumnNumber(Begin); - if (StartColNo) --StartColNo; // Zero base the col #. - } - - // Compute the column number of the end. - unsigned EndColNo = map.getSourceLine().size(); - if (EndLineNo == LineNo) { - EndColNo = SM.getExpansionColumnNumber(End); - if (EndColNo) { - --EndColNo; // Zero base the col #. - - // Add in the length of the token, so that we cover multi-char tokens if - // this is a token range. - if (R.isTokenRange()) - EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); - } else { - EndColNo = CaretLine.size(); - } - } - - assert(StartColNo <= EndColNo && "Invalid range!"); - - // Check that a token range does not highlight only whitespace. - if (R.isTokenRange()) { - // Pick the first non-whitespace column. - while (StartColNo < map.getSourceLine().size() && - (map.getSourceLine()[StartColNo] == ' ' || - map.getSourceLine()[StartColNo] == '\t')) - StartColNo = map.startOfNextColumn(StartColNo); - - // Pick the last non-whitespace column. - if (EndColNo > map.getSourceLine().size()) - EndColNo = map.getSourceLine().size(); - while (EndColNo && - (map.getSourceLine()[EndColNo-1] == ' ' || - map.getSourceLine()[EndColNo-1] == '\t')) - EndColNo = map.startOfPreviousColumn(EndColNo); - - // If the start/end passed each other, then we are trying to highlight a - // range that just exists in whitespace. That most likely means we have - // a multi-line highlighting range that covers a blank line. - if (StartColNo > EndColNo) { - assert(StartLineNo != EndLineNo && "trying to highlight whitespace"); - StartColNo = EndColNo; - } - } +struct LineRange { + unsigned LineNo; + unsigned StartCol; + unsigned EndCol; +}; - assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); - assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); +/// Highlight \p R (with ~'s) on the current source line. +static void highlightRange(const LineRange &R, const SourceColumnMap &Map, + std::string &CaretLine) { + // Pick the first non-whitespace column. + unsigned StartColNo = R.StartCol; + while (StartColNo < Map.getSourceLine().size() && + (Map.getSourceLine()[StartColNo] == ' ' || + Map.getSourceLine()[StartColNo] == '\t')) + StartColNo = Map.startOfNextColumn(StartColNo); + + // Pick the last non-whitespace column. + unsigned EndColNo = + std::min(static_cast<size_t>(R.EndCol), Map.getSourceLine().size()); + while (EndColNo && (Map.getSourceLine()[EndColNo - 1] == ' ' || + Map.getSourceLine()[EndColNo - 1] == '\t')) + EndColNo = Map.startOfPreviousColumn(EndColNo); + + // If the start/end passed each other, then we are trying to highlight a + // range that just exists in whitespace. That most likely means we have + // a multi-line highlighting range that covers a blank line. + if (StartColNo > EndColNo) + return; // Fill the range with ~'s. - StartColNo = map.byteToContainingColumn(StartColNo); - EndColNo = map.byteToContainingColumn(EndColNo); + StartColNo = Map.byteToContainingColumn(StartColNo); + EndColNo = Map.byteToContainingColumn(EndColNo); assert(StartColNo <= EndColNo && "Invalid range!"); if (CaretLine.size() < EndColNo) - CaretLine.resize(EndColNo,' '); - std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); + CaretLine.resize(EndColNo, ' '); + std::fill(CaretLine.begin() + StartColNo, CaretLine.begin() + EndColNo, '~'); } static std::string buildFixItInsertionLine(FileID FID, @@ -1068,51 +1001,51 @@ static std::string buildFixItInsertionLine(FileID FID, return FixItInsertionLine; unsigned PrevHintEndCol = 0; - for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); - I != E; ++I) { - if (!I->CodeToInsert.empty()) { - // We have an insertion hint. Determine whether the inserted - // code contains no newlines and is on the same line as the caret. - std::pair<FileID, unsigned> HintLocInfo - = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); - if (FID == HintLocInfo.first && - LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && - StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { - // Insert the new code into the line just below the code - // that the user wrote. - // Note: When modifying this function, be very careful about what is a - // "column" (printed width, platform-dependent) and what is a - // "byte offset" (SourceManager "column"). - unsigned HintByteOffset - = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; - - // The hint must start inside the source or right at the end - assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1); - unsigned HintCol = map.byteToContainingColumn(HintByteOffset); - - // If we inserted a long previous hint, push this one forwards, and add - // an extra space to show that this is not part of the previous - // completion. This is sort of the best we can do when two hints appear - // to overlap. - // - // Note that if this hint is located immediately after the previous - // hint, no space will be added, since the location is more important. - if (HintCol < PrevHintEndCol) - HintCol = PrevHintEndCol + 1; - - // This should NOT use HintByteOffset, because the source might have - // Unicode characters in earlier columns. - unsigned NewFixItLineSize = FixItInsertionLine.size() + - (HintCol - PrevHintEndCol) + I->CodeToInsert.size(); - if (NewFixItLineSize > FixItInsertionLine.size()) - FixItInsertionLine.resize(NewFixItLineSize, ' '); - - std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), - FixItInsertionLine.end() - I->CodeToInsert.size()); - - PrevHintEndCol = - HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert); - } + for (const auto &H : Hints) { + if (H.CodeToInsert.empty()) + continue; + + // We have an insertion hint. Determine whether the inserted + // code contains no newlines and is on the same line as the caret. + std::pair<FileID, unsigned> HintLocInfo = + SM.getDecomposedExpansionLoc(H.RemoveRange.getBegin()); + if (FID == HintLocInfo.first && + LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && + StringRef(H.CodeToInsert).find_first_of("\n\r") == StringRef::npos) { + // Insert the new code into the line just below the code + // that the user wrote. + // Note: When modifying this function, be very careful about what is a + // "column" (printed width, platform-dependent) and what is a + // "byte offset" (SourceManager "column"). + unsigned HintByteOffset = + SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; + + // The hint must start inside the source or right at the end + assert(HintByteOffset < static_cast<unsigned>(map.bytes()) + 1); + unsigned HintCol = map.byteToContainingColumn(HintByteOffset); + + // If we inserted a long previous hint, push this one forwards, and add + // an extra space to show that this is not part of the previous + // completion. This is sort of the best we can do when two hints appear + // to overlap. + // + // Note that if this hint is located immediately after the previous + // hint, no space will be added, since the location is more important. + if (HintCol < PrevHintEndCol) + HintCol = PrevHintEndCol + 1; + + // This should NOT use HintByteOffset, because the source might have + // Unicode characters in earlier columns. + unsigned NewFixItLineSize = FixItInsertionLine.size() + + (HintCol - PrevHintEndCol) + + H.CodeToInsert.size(); + if (NewFixItLineSize > FixItInsertionLine.size()) + FixItInsertionLine.resize(NewFixItLineSize, ' '); + + std::copy(H.CodeToInsert.begin(), H.CodeToInsert.end(), + FixItInsertionLine.end() - H.CodeToInsert.size()); + + PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(H.CodeToInsert); } } @@ -1121,6 +1054,65 @@ static std::string buildFixItInsertionLine(FileID FID, return FixItInsertionLine; } +static unsigned getNumDisplayWidth(unsigned N) { + unsigned L = 1u, M = 10u; + while (M <= N && ++L != std::numeric_limits<unsigned>::digits10 + 1) + M *= 10u; + + return L; +} + +/// Filter out invalid ranges, ranges that don't fit into the window of +/// source lines we will print, and ranges from other files. +/// +/// For the remaining ranges, convert them to simple LineRange structs, +/// which only cover one line at a time. +static SmallVector<LineRange> +prepareAndFilterRanges(const SmallVectorImpl<CharSourceRange> &Ranges, + const SourceManager &SM, + const std::pair<unsigned, unsigned> &Lines, FileID FID, + const LangOptions &LangOpts) { + SmallVector<LineRange> LineRanges; + + for (const CharSourceRange &R : Ranges) { + if (R.isInvalid()) + continue; + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); + + unsigned StartLineNo = SM.getExpansionLineNumber(Begin); + if (StartLineNo > Lines.second || SM.getFileID(Begin) != FID) + continue; + + unsigned EndLineNo = SM.getExpansionLineNumber(End); + if (EndLineNo < Lines.first || SM.getFileID(End) != FID) + continue; + + unsigned StartColumn = SM.getExpansionColumnNumber(Begin); + unsigned EndColumn = SM.getExpansionColumnNumber(End); + if (R.isTokenRange()) + EndColumn += Lexer::MeasureTokenLength(End, SM, LangOpts); + + // Only a single line. + if (StartLineNo == EndLineNo) { + LineRanges.push_back({StartLineNo, StartColumn - 1, EndColumn - 1}); + continue; + } + + // Start line. + LineRanges.push_back({StartLineNo, StartColumn - 1, ~0u}); + + // Middle lines. + for (unsigned S = StartLineNo + 1; S != EndLineNo; ++S) + LineRanges.push_back({S, 0, ~0u}); + + // End line. + LineRanges.push_back({EndLineNo, 0, EndColumn - 1}); + } + + return LineRanges; +} + /// Emit a code snippet and caret line. /// /// This routine emits a single line's code snippet and caret line.. @@ -1146,9 +1138,7 @@ void TextDiagnostic::emitSnippetAndCaret( (LastLevel != DiagnosticsEngine::Note || Level == LastLevel)) return; - // Decompose the location into a FID/Offset pair. - std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc(); - FileID FID = LocInfo.first; + FileID FID = Loc.getFileID(); const SourceManager &SM = Loc.getManager(); // Get information about the buffer it points into. @@ -1156,6 +1146,8 @@ void TextDiagnostic::emitSnippetAndCaret( StringRef BufData = Loc.getBufferData(&Invalid); if (Invalid) return; + const char *BufStart = BufData.data(); + const char *BufEnd = BufStart + BufData.size(); unsigned CaretLineNo = Loc.getLineNumber(); unsigned CaretColNo = Loc.getColumnNumber(); @@ -1168,16 +1160,34 @@ void TextDiagnostic::emitSnippetAndCaret( // Find the set of lines to include. const unsigned MaxLines = DiagOpts->SnippetLineLimit; std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo}; - for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) - if (auto OptionalRange = findLinesForRange(*I, FID, SM)) + unsigned DisplayLineNo = + Ranges.empty() ? Loc.getPresumedLoc().getLine() : ~0u; + for (const auto &I : Ranges) { + if (auto OptionalRange = findLinesForRange(I, FID, SM)) Lines = maybeAddRange(Lines, *OptionalRange, MaxLines); - for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) { - const char *BufStart = BufData.data(); - const char *BufEnd = BufStart + BufData.size(); + DisplayLineNo = + std::min(DisplayLineNo, SM.getPresumedLineNumber(I.getBegin())); + } + // Our line numbers look like: + // " [number] | " + // Where [number] is MaxLineNoDisplayWidth columns + // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns. + unsigned MaxLineNoDisplayWidth = + DiagOpts->ShowLineNumbers + ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines)) + : 0; + auto indentForLineNumbers = [&] { + if (MaxLineNoDisplayWidth > 0) + OS.indent(MaxLineNoDisplayWidth + 2) << "| "; + }; + + SmallVector<LineRange> LineRanges = + prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts); + + for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; + ++LineNo, ++DisplayLineNo) { // Rewind from the current position to the start of the line. const char *LineStart = BufStart + @@ -1195,34 +1205,28 @@ void TextDiagnostic::emitSnippetAndCaret( if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) return; - // Trim trailing null-bytes. - StringRef Line(LineStart, LineEnd - LineStart); - while (!Line.empty() && Line.back() == '\0' && - (LineNo != CaretLineNo || Line.size() > CaretColNo)) - Line = Line.drop_back(); - // Copy the line of code into an std::string for ease of manipulation. - std::string SourceLine(Line.begin(), Line.end()); + std::string SourceLine(LineStart, LineEnd); + // Remove trailing null bytes. + while (!SourceLine.empty() && SourceLine.back() == '\0' && + (LineNo != CaretLineNo || SourceLine.size() > CaretColNo)) + SourceLine.pop_back(); // Build the byte to column map. const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); - // Create a line for the caret that is filled with spaces that is the same - // number of columns as the line of source code. - std::string CaretLine(sourceColMap.columns(), ' '); - + std::string CaretLine; // Highlight all of the characters covered by Ranges with ~ characters. - for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) - highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts); + for (const auto &LR : LineRanges) { + if (LR.LineNo == LineNo) + highlightRange(LR, sourceColMap, CaretLine); + } // Next, insert the caret itself. if (CaretLineNo == LineNo) { - CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1); - if (CaretLine.size() < CaretColNo + 1) - CaretLine.resize(CaretColNo + 1, ' '); - CaretLine[CaretColNo] = '^'; + size_t Col = sourceColMap.byteToContainingColumn(CaretColNo - 1); + CaretLine.resize(std::max(Col + 1, CaretLine.size()), ' '); + CaretLine[Col] = '^'; } std::string FixItInsertionLine = buildFixItInsertionLine( @@ -1239,19 +1243,16 @@ void TextDiagnostic::emitSnippetAndCaret( // to produce easily machine parsable output. Add a space before the // source line and the caret to make it trivial to tell the main diagnostic // line from what the user is intended to see. - if (DiagOpts->ShowSourceRanges) { + if (DiagOpts->ShowSourceRanges && !SourceLine.empty()) { SourceLine = ' ' + SourceLine; CaretLine = ' ' + CaretLine; } - // Finally, remove any blank spaces from the end of CaretLine. - while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ') - CaretLine.erase(CaretLine.end() - 1); - // Emit what we have computed. - emitSnippet(SourceLine); + emitSnippet(SourceLine, MaxLineNoDisplayWidth, DisplayLineNo); if (!CaretLine.empty()) { + indentForLineNumbers(); if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; @@ -1260,6 +1261,7 @@ void TextDiagnostic::emitSnippetAndCaret( } if (!FixItInsertionLine.empty()) { + indentForLineNumbers(); if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); @@ -1275,37 +1277,37 @@ void TextDiagnostic::emitSnippetAndCaret( emitParseableFixits(Hints, SM); } -void TextDiagnostic::emitSnippet(StringRef line) { - if (line.empty()) - return; - - size_t i = 0; - - std::string to_print; - bool print_reversed = false; - - while (i<line.size()) { - std::pair<SmallString<16>,bool> res - = printableTextForNextCharacter(line, &i, DiagOpts->TabStop); - bool was_printable = res.second; +void TextDiagnostic::emitSnippet(StringRef SourceLine, + unsigned MaxLineNoDisplayWidth, + unsigned LineNo) { + // Emit line number. + if (MaxLineNoDisplayWidth > 0) { + unsigned LineNoDisplayWidth = getNumDisplayWidth(LineNo); + OS.indent(MaxLineNoDisplayWidth - LineNoDisplayWidth + 1) + << LineNo << " | "; + } - if (DiagOpts->ShowColors && was_printable == print_reversed) { - if (print_reversed) - OS.reverseColor(); - OS << to_print; - to_print.clear(); - if (DiagOpts->ShowColors) - OS.resetColor(); + // Print the source line one character at a time. + bool PrintReversed = false; + size_t I = 0; + while (I < SourceLine.size()) { + auto [Str, WasPrintable] = + printableTextForNextCharacter(SourceLine, &I, DiagOpts->TabStop); + + // Toggle inverted colors on or off for this character. + if (DiagOpts->ShowColors) { + if (WasPrintable == PrintReversed) { + PrintReversed = !PrintReversed; + if (PrintReversed) + OS.reverseColor(); + else + OS.resetColor(); + } } - - print_reversed = !was_printable; - to_print += res.first.str(); + OS << Str; } - if (print_reversed && DiagOpts->ShowColors) - OS.reverseColor(); - OS << to_print; - if (print_reversed && DiagOpts->ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); OS << '\n'; @@ -1318,24 +1320,21 @@ void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints, // We follow FixItRewriter's example in not (yet) handling // fix-its in macros. - for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); - I != E; ++I) { - if (I->RemoveRange.isInvalid() || - I->RemoveRange.getBegin().isMacroID() || - I->RemoveRange.getEnd().isMacroID()) + for (const auto &H : Hints) { + if (H.RemoveRange.isInvalid() || H.RemoveRange.getBegin().isMacroID() || + H.RemoveRange.getEnd().isMacroID()) return; } - for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); - I != E; ++I) { - SourceLocation BLoc = I->RemoveRange.getBegin(); - SourceLocation ELoc = I->RemoveRange.getEnd(); + for (const auto &H : Hints) { + SourceLocation BLoc = H.RemoveRange.getBegin(); + SourceLocation ELoc = H.RemoveRange.getEnd(); std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc); std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc); // Adjust for token ranges. - if (I->RemoveRange.isTokenRange()) + if (H.RemoveRange.isTokenRange()) EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts); // We specifically do not do word-wrapping or tab-expansion here, @@ -1351,7 +1350,7 @@ void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints, << '-' << SM.getLineNumber(EInfo.first, EInfo.second) << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) << "}:\""; - OS.write_escaped(I->CodeToInsert); + OS.write_escaped(H.CodeToInsert); OS << "\"\n"; } } diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index 378f7ddd0159..d57b27e9e36f 100644 --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -737,12 +737,12 @@ void VerifyDiagnosticConsumer::HandleDiagnostic( Loc = SrcManager->getExpansionLoc(Loc); FileID FID = SrcManager->getFileID(Loc); - const FileEntry *FE = SrcManager->getFileEntryForID(FID); + auto FE = SrcManager->getFileEntryRefForID(FID); if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) { // If the file is a modules header file it shall not be parsed // for expected-* directives. HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo(); - if (HS.findModuleForHeader(FE)) + if (HS.findModuleForHeader(*FE)) PS = IsUnparsedNoDirectives; } |
