[clang] Hide the TargetOptions pointer from CompilerInvocation (#106271)

This PR hides the reference-counted pointer that holds `TargetOptions`
from the public API of `CompilerInvocation`. This gives
`CompilerInvocation` an exclusive control over the lifetime of this
member, which will eventually be leveraged to implement a copy-on-write
behavior.

There are two clients that currently share ownership of that pointer:

* `TargetInfo` - This was refactored to hold a non-owning reference to
`TargetOptions`. The options object is typically owned by the
`CompilerInvocation` or by the new `CompilerInstance::AuxTargetOpts` for
the auxiliary target. This needed a bit of care in `ASTUnit::Parse()` to
keep the `CompilerInvocation` alive.
* `clangd::PreambleData` - This was refactored to exclusively own the
`TargetOptions` that get moved out of the `CompilerInvocation`.
This commit is contained in:
Jan Svoboda
2025-04-28 07:43:26 -07:00
committed by GitHub
parent ba420d8122
commit 985410f87f
30 changed files with 50 additions and 39 deletions

View File

@@ -711,7 +711,10 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
Result->Marks = CapturedInfo.takeMarks();
Result->StatCache = StatCache;
Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
Result->TargetOpts = CI.TargetOpts;
// Move the options instead of copying them. The invocation doesn't need
// them anymore.
Result->TargetOpts =
std::make_unique<TargetOptions>(std::move(CI.getTargetOpts()));
if (PreambleCallback) {
trace::Span Tracer("Running PreambleCallback");
auto Ctx = CapturedInfo.takeLife();
@@ -932,7 +935,7 @@ void PreamblePatch::apply(CompilerInvocation &CI) const {
// ParsedASTTest.PreambleWithDifferentTarget.
// Make sure this is a deep copy, as the same Baseline might be used
// concurrently.
*CI.TargetOpts = *Baseline->TargetOpts;
CI.getTargetOpts() = *Baseline->TargetOpts;
// No need to map an empty file.
if (PatchContents.empty())

View File

@@ -103,7 +103,7 @@ struct PreambleData {
// Target options used when building the preamble. Changes in target can cause
// crashes when deserializing preamble, this enables consumers to use the
// same target (without reparsing CompileCommand).
std::shared_ptr<TargetOptions> TargetOpts = nullptr;
std::unique_ptr<TargetOptions> TargetOpts = nullptr;
PrecompiledPreamble Preamble;
std::vector<Diag> Diags;
// Processes like code completions and go-to-definitions will need #include

View File

@@ -256,7 +256,7 @@ bool isValidTarget(llvm::StringRef Triple) {
DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions,
new IgnoringDiagConsumer);
llvm::IntrusiveRefCntPtr<TargetInfo> Target =
TargetInfo::CreateTargetInfo(Diags, TargetOpts);
TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
return bool(Target);
}

View File

@@ -53,7 +53,7 @@ ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
Diagnostics(
new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
TargetOpts(new ModuleMapTargetOptions()),
Target(TargetInfo::CreateTargetInfo(*Diagnostics, TargetOpts)),
Target(TargetInfo::CreateTargetInfo(*Diagnostics, *TargetOpts)),
FileMgr(new FileManager(FileSystemOpts)),
SourceMgr(new SourceManager(*Diagnostics, *FileMgr, false)), HSOpts(),
HeaderInfo(new HeaderSearch(HSOpts, *SourceMgr, *Diagnostics, *LangOpts,

View File

@@ -224,7 +224,7 @@ enum OpenCLTypeKind : uint8_t {
///
class TargetInfo : public TransferrableTargetInfo,
public RefCountedBase<TargetInfo> {
std::shared_ptr<TargetOptions> TargetOpts;
TargetOptions *TargetOpts;
llvm::Triple Triple;
protected:
// Target values set by the ctor of the actual target implementation. Default
@@ -310,10 +310,9 @@ public:
///
/// \param Opts - The options to use to initialize the target. The target may
/// modify the options to canonicalize the target feature information to match
/// what the backend expects.
static TargetInfo *
CreateTargetInfo(DiagnosticsEngine &Diags,
const std::shared_ptr<TargetOptions> &Opts);
/// what the backend expects. These must outlive the returned TargetInfo.
static TargetInfo *CreateTargetInfo(DiagnosticsEngine &Diags,
TargetOptions &Opts);
virtual ~TargetInfo();

View File

@@ -143,6 +143,10 @@ private:
/// Parse available.
std::shared_ptr<CompilerInvocation> CCInvocation;
/// Optional owned invocation, just used to keep the invocation alive for the
/// members initialized in transferASTDataFromCompilerInstance.
std::shared_ptr<CompilerInvocation> ModifiedInvocation;
/// Fake module loader: the AST unit doesn't need to load any modules.
TrivialModuleLoader ModuleLoader;

View File

@@ -88,6 +88,9 @@ class CompilerInstance : public ModuleLoader {
/// The target being compiled for.
IntrusiveRefCntPtr<TargetInfo> Target;
/// Options for the auxiliary target.
std::unique_ptr<TargetOptions> AuxTargetOpts;
/// Auxiliary Target info.
IntrusiveRefCntPtr<TargetInfo> AuxTarget;

View File

@@ -268,7 +268,6 @@ public:
/// Base class internals.
/// @{
using CompilerInvocationBase::LangOpts;
using CompilerInvocationBase::TargetOpts;
std::shared_ptr<LangOptions> getLangOptsPtr() { return LangOpts; }
/// @}

View File

@@ -774,9 +774,10 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
using namespace clang::targets;
/// CreateTargetInfo - Return the target info object for the specified target
/// options.
TargetInfo *
TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
const std::shared_ptr<TargetOptions> &Opts) {
TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
TargetOptions &OptsRef) {
TargetOptions *Opts = &OptsRef;
llvm::Triple Triple(llvm::Triple::normalize(Opts->Triple));
// Construct the target

View File

@@ -615,7 +615,7 @@ public:
this->TargetOpts = std::make_shared<TargetOptions>(TargetOpts);
Target =
TargetInfo::CreateTargetInfo(PP.getDiagnostics(), this->TargetOpts);
TargetInfo::CreateTargetInfo(PP.getDiagnostics(), *this->TargetOpts);
updated();
return false;
@@ -1499,6 +1499,10 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
Target = &CI.getTarget();
Reader = CI.getASTReader();
HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
if (Invocation != CI.getInvocationPtr()) {
// This happens when Parse creates a copy of \c Invocation to modify.
ModifiedInvocation = CI.getInvocationPtr();
}
}
StringRef ASTUnit::getMainFileName() const {

View File

@@ -127,7 +127,7 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
Clang->setInvocation(std::move(CInvok));
Clang->setDiagnostics(Diags.get());
Clang->setTarget(TargetInfo::CreateTargetInfo(
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
Clang->createFileManager();
Clang->createSourceManager(Clang->getFileManager());
Clang->createPreprocessor(TU_Prefix);

View File

@@ -110,7 +110,7 @@ void CompilerInstance::setAuxTarget(TargetInfo *Value) { AuxTarget = Value; }
bool CompilerInstance::createTarget() {
// Create the target instance.
setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(),
getInvocation().TargetOpts));
getInvocation().getTargetOpts()));
if (!hasTarget())
return false;
@@ -119,14 +119,14 @@ bool CompilerInstance::createTarget() {
if (!getAuxTarget() &&
(getLangOpts().CUDA || getLangOpts().isTargetDevice()) &&
!getFrontendOpts().AuxTriple.empty()) {
auto TO = std::make_shared<TargetOptions>();
auto &TO = AuxTargetOpts = std::make_unique<TargetOptions>();
TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple);
if (getFrontendOpts().AuxTargetCPU)
TO->CPU = *getFrontendOpts().AuxTargetCPU;
if (getFrontendOpts().AuxTargetFeatures)
TO->FeaturesAsWritten = *getFrontendOpts().AuxTargetFeatures;
TO->HostTriple = getTarget().getTriple().str();
setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), TO));
setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), *TO));
}
if (!getTarget().hasStrictFP() && !getLangOpts().ExpStrictFP) {

View File

@@ -125,7 +125,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) {
Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
Clang->setTarget(TargetInfo::CreateTargetInfo(
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
if (!Clang->hasTarget())
return llvm::createStringError(llvm::errc::not_supported,
"Initialization failed. "

View File

@@ -208,7 +208,7 @@ std::unique_ptr<CompilerInstance> BuildCompilerInstance() {
Ins->setInvocation(std::move(Inv));
TargetInfo *TI = TargetInfo::CreateTargetInfo(
Ins->getDiagnostics(), Ins->getInvocation().TargetOpts);
Ins->getDiagnostics(), Ins->getInvocation().getTargetOpts());
Ins->setTarget(TI);
Ins->getTarget().adjust(Ins->getDiagnostics(), Ins->getLangOpts());
Ins->createFileManager();

View File

@@ -39,7 +39,7 @@ protected:
Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
TargetOpts->Triple = "x86_64-pc-linux-unknown";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
LangOpts.CPlusPlus20 = 1; // For __VA_OPT__
}

View File

@@ -46,7 +46,7 @@ protected:
SourceMgr(Diags, FileMgr),
TargetOpts(new TargetOptions) {
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;

View File

@@ -45,8 +45,7 @@ struct TestCompiler {
Tr.setEnvironment(Triple::EnvironmentType::UnknownEnvironment);
compiler.getTargetOpts().Triple = Tr.getTriple();
compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
compiler.getDiagnostics(),
std::make_shared<clang::TargetOptions>(compiler.getTargetOpts())));
compiler.getDiagnostics(), compiler.getTargetOpts()));
const clang::TargetInfo &TInfo = compiler.getTarget();
PtrSize = TInfo.getPointerWidth(clang::LangAS::Default) / 8;

View File

@@ -589,8 +589,7 @@ TEST(ToolChainTest, UEFICallingConventionTest) {
compiler.getTargetOpts().Triple = Tr.getTriple();
compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
compiler.getDiagnostics(),
std::make_shared<clang::TargetOptions>(compiler.getTargetOpts())));
compiler.getDiagnostics(), compiler.getTargetOpts()));
EXPECT_EQ(compiler.getTarget().getCallingConvKind(true),
TargetInfo::CallingConvKind::CCK_MicrosoftWin64);

View File

@@ -33,7 +33,7 @@ TEST(BuildCompilerInvocationTest, RecoverMultipleJobs) {
*Opts.VFS, new DiagnosticOptions, &D, false);
std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, Opts);
ASSERT_TRUE(CI);
EXPECT_THAT(CI->TargetOpts->Triple, testing::StartsWith("i386-"));
EXPECT_THAT(CI->getTargetOpts().Triple, testing::StartsWith("i386-"));
}
// buildInvocationFromCommandLine should not translate -include to -include-pch,

View File

@@ -34,7 +34,7 @@ protected:
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions),
Search(HSOpts, SourceMgr, Diags, LangOpts, Target.get()) {
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
void addSearchDir(llvm::StringRef Dir) {

View File

@@ -48,7 +48,7 @@ protected:
TargetOpts(new TargetOptions)
{
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
std::unique_ptr<Preprocessor> CreatePP(StringRef Source,

View File

@@ -58,7 +58,7 @@ protected:
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
TargetOpts->Triple = "x86_64-unknown-linux-gnu";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
std::unique_ptr<Preprocessor>

View File

@@ -139,7 +139,7 @@ protected:
Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;

View File

@@ -36,7 +36,7 @@ protected:
TargetOpts(new TargetOptions)
{
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;

View File

@@ -35,7 +35,7 @@ protected:
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
TargetOpts->Triple = "x86_64-apple-macos12";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;

View File

@@ -31,7 +31,7 @@ protected:
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;

View File

@@ -72,7 +72,7 @@ protected:
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
// This is an arbitrarily chosen target triple to create the target info.
TargetOpts->Triple = "dxil";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
std::unique_ptr<Preprocessor> createPP(StringRef Source,

View File

@@ -789,7 +789,7 @@ ClangExpressionParser::ClangExpressionParser(
if (auto *target_info = TargetInfo::CreateTargetInfo(
m_compiler->getDiagnostics(),
m_compiler->getInvocation().TargetOpts)) {
m_compiler->getInvocation().getTargetOpts())) {
if (log) {
LLDB_LOGF(log, "Target datalayout string: '%s'",
target_info->getDataLayoutString());

View File

@@ -742,7 +742,7 @@ ClangModulesDeclVendor::Create(Target &target) {
std::unique_ptr<clang::FrontendAction> action(new clang::SyntaxOnlyAction);
instance->setTarget(clang::TargetInfo::CreateTargetInfo(
*diagnostics_engine, instance->getInvocation().TargetOpts));
*diagnostics_engine, instance->getInvocation().getTargetOpts()));
if (!instance->hasTarget())
return nullptr;

View File

@@ -744,7 +744,7 @@ TargetInfo *TypeSystemClang::getTargetInfo() {
// target_triple should be something like "x86_64-apple-macosx"
if (m_target_info_up == nullptr && !m_target_triple.empty())
m_target_info_up.reset(TargetInfo::CreateTargetInfo(
getASTContext().getDiagnostics(), getTargetOptions()));
getASTContext().getDiagnostics(), *getTargetOptions()));
return m_target_info_up.get();
}