aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Frontend
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Frontend')
-rw-r--r--clang/lib/Frontend/ASTConsumers.cpp25
-rw-r--r--clang/lib/Frontend/ASTMerge.cpp2
-rw-r--r--clang/lib/Frontend/ASTUnit.cpp54
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp45
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp551
-rw-r--r--clang/lib/Frontend/CreateInvocationFromCommandLine.cpp2
-rw-r--r--clang/lib/Frontend/DependencyFile.cpp50
-rw-r--r--clang/lib/Frontend/DiagnosticRenderer.cpp14
-rw-r--r--clang/lib/Frontend/FrontendAction.cpp57
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp28
-rw-r--r--clang/lib/Frontend/HeaderIncludeGen.cpp49
-rw-r--r--clang/lib/Frontend/InitPreprocessor.cpp90
-rw-r--r--clang/lib/Frontend/LayoutOverrideSource.cpp104
-rw-r--r--clang/lib/Frontend/ModuleDependencyCollector.cpp31
-rw-r--r--clang/lib/Frontend/PrecompiledPreamble.cpp37
-rw-r--r--clang/lib/Frontend/PrintPreprocessedOutput.cpp6
-rw-r--r--clang/lib/Frontend/Rewrite/FrontendActions.cpp9
-rw-r--r--clang/lib/Frontend/SerializedDiagnosticPrinter.cpp6
-rw-r--r--clang/lib/Frontend/TextDiagnostic.cpp677
-rw-r--r--clang/lib/Frontend/VerifyDiagnosticConsumer.cpp4
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;
}