Skip to content

[clang] Make the entire CompilerInvocation ref-counted #65647

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 63 additions & 87 deletions clang/include/clang/Frontend/CompilerInvocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,12 @@ bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args,
DiagnosticsEngine *Diags = nullptr,
bool DefaultDiagColor = true);

/// The base class of CompilerInvocation with reference semantics.
///
/// This class stores option objects behind reference-counted pointers. This is
/// useful for clients that want to keep some option object around even after
/// CompilerInvocation gets destroyed, without making a copy.
///
/// This is a separate class so that we can implement the copy constructor and
/// assignment here and leave them defaulted in the rest of CompilerInvocation.
class CompilerInvocationRefBase {
public:
/// The base class of CompilerInvocation. It keeps individual option objects
/// behind reference-counted pointers, which is useful for clients that want to
/// keep select option objects alive (even after CompilerInvocation gets
/// destroyed) without making a copy.
class CompilerInvocationBase {
protected:
/// Options controlling the language variant.
std::shared_ptr<LangOptions> LangOpts;

Expand All @@ -86,103 +82,71 @@ class CompilerInvocationRefBase {
IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts;

/// Options controlling the \#include directive.
std::shared_ptr<HeaderSearchOptions> HeaderSearchOpts;
std::shared_ptr<HeaderSearchOptions> HSOpts;

/// Options controlling the preprocessor (aside from \#include handling).
std::shared_ptr<PreprocessorOptions> PreprocessorOpts;
std::shared_ptr<PreprocessorOptions> PPOpts;

/// Options controlling the static analyzer.
AnalyzerOptionsRef AnalyzerOpts;

CompilerInvocationRefBase();
CompilerInvocationRefBase(const CompilerInvocationRefBase &X);
CompilerInvocationRefBase(CompilerInvocationRefBase &&X);
CompilerInvocationRefBase &operator=(CompilerInvocationRefBase X);
CompilerInvocationRefBase &operator=(CompilerInvocationRefBase &&X);
~CompilerInvocationRefBase();

LangOptions &getLangOpts() { return *LangOpts; }
const LangOptions &getLangOpts() const { return *LangOpts; }

TargetOptions &getTargetOpts() { return *TargetOpts.get(); }
const TargetOptions &getTargetOpts() const { return *TargetOpts.get(); }

DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }

HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }

const HeaderSearchOptions &getHeaderSearchOpts() const {
return *HeaderSearchOpts;
}

std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const {
return HeaderSearchOpts;
}

std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() {
return PreprocessorOpts;
}

PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; }

const PreprocessorOptions &getPreprocessorOpts() const {
return *PreprocessorOpts;
}

AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
};

/// The base class of CompilerInvocation with value semantics.
class CompilerInvocationValueBase {
protected:
MigratorOptions MigratorOpts;
std::shared_ptr<MigratorOptions> MigratorOpts;

/// Options controlling IRgen and the backend.
CodeGenOptions CodeGenOpts;

/// Options controlling dependency output.
DependencyOutputOptions DependencyOutputOpts;
std::shared_ptr<CodeGenOptions> CodeGenOpts;

/// Options controlling file system operations.
FileSystemOptions FileSystemOpts;
std::shared_ptr<FileSystemOptions> FSOpts;

/// Options controlling the frontend itself.
FrontendOptions FrontendOpts;
std::shared_ptr<FrontendOptions> FrontendOpts;

/// Options controlling dependency output.
std::shared_ptr<DependencyOutputOptions> DependencyOutputOpts;

/// Options controlling preprocessed output.
PreprocessorOutputOptions PreprocessorOutputOpts;
std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;

public:
MigratorOptions &getMigratorOpts() { return MigratorOpts; }
const MigratorOptions &getMigratorOpts() const { return MigratorOpts; }

CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }

DependencyOutputOptions &getDependencyOutputOpts() {
return DependencyOutputOpts;
}
CompilerInvocationBase();
CompilerInvocationBase(const CompilerInvocationBase &X) { operator=(X); }
CompilerInvocationBase(CompilerInvocationBase &&X) = default;
CompilerInvocationBase &operator=(const CompilerInvocationBase &X);
CompilerInvocationBase &operator=(CompilerInvocationBase &&X) = default;
~CompilerInvocationBase() = default;

const LangOptions &getLangOpts() const { return *LangOpts; }
const TargetOptions &getTargetOpts() const { return *TargetOpts; }
const DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
const HeaderSearchOptions &getHeaderSearchOpts() const { return *HSOpts; }
const PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; }
const AnalyzerOptions &getAnalyzerOpts() const { return *AnalyzerOpts; }
const MigratorOptions &getMigratorOpts() const { return *MigratorOpts; }
const CodeGenOptions &getCodeGenOpts() const { return *CodeGenOpts; }
const FileSystemOptions &getFileSystemOpts() const { return *FSOpts; }
const FrontendOptions &getFrontendOpts() const { return *FrontendOpts; }
const DependencyOutputOptions &getDependencyOutputOpts() const {
return DependencyOutputOpts;
return *DependencyOutputOpts;
}

FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }

const FileSystemOptions &getFileSystemOpts() const {
return FileSystemOpts;
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
return *PreprocessorOutputOpts;
}

FrontendOptions &getFrontendOpts() { return FrontendOpts; }
const FrontendOptions &getFrontendOpts() const { return FrontendOpts; }

PreprocessorOutputOptions &getPreprocessorOutputOpts() {
return PreprocessorOutputOpts;
LangOptions &getLangOpts() { return *LangOpts; }
TargetOptions &getTargetOpts() { return *TargetOpts; }
DiagnosticOptions &getDiagnosticOpts() { return *DiagnosticOpts; }
HeaderSearchOptions &getHeaderSearchOpts() { return *HSOpts; }
PreprocessorOptions &getPreprocessorOpts() { return *PPOpts; }
AnalyzerOptions &getAnalyzerOpts() { return *AnalyzerOpts; }
MigratorOptions &getMigratorOpts() { return *MigratorOpts; }
CodeGenOptions &getCodeGenOpts() { return *CodeGenOpts; }
FileSystemOptions &getFileSystemOpts() { return *FSOpts; }
FrontendOptions &getFrontendOpts() { return *FrontendOpts; }
DependencyOutputOptions &getDependencyOutputOpts() {
return *DependencyOutputOpts;
}

const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
return PreprocessorOutputOpts;
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
return *PreprocessorOutputOpts;
}
};

Expand All @@ -191,9 +155,21 @@ class CompilerInvocationValueBase {
/// This class is designed to represent an abstract "invocation" of the
/// compiler, including data such as the include paths, the code generation
/// options, the warning flags, and so on.
class CompilerInvocation : public CompilerInvocationRefBase,
public CompilerInvocationValueBase {
class CompilerInvocation : public CompilerInvocationBase {
public:
/// Base class internals.
/// @{
using CompilerInvocationBase::LangOpts;
using CompilerInvocationBase::TargetOpts;
using CompilerInvocationBase::DiagnosticOpts;
std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() {
return HSOpts;
}
std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() {
return PPOpts;
}
/// @}

/// Create a compiler invocation from a list of input options.
/// \returns true on success.
///
Expand Down
130 changes: 70 additions & 60 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,40 +126,49 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
// Initialization.
//===----------------------------------------------------------------------===//

CompilerInvocationRefBase::CompilerInvocationRefBase()
: LangOpts(new LangOptions()), TargetOpts(new TargetOptions()),
DiagnosticOpts(new DiagnosticOptions()),
HeaderSearchOpts(new HeaderSearchOptions()),
PreprocessorOpts(new PreprocessorOptions()),
AnalyzerOpts(new AnalyzerOptions()) {}

CompilerInvocationRefBase::CompilerInvocationRefBase(
const CompilerInvocationRefBase &X)
: LangOpts(new LangOptions(X.getLangOpts())),
TargetOpts(new TargetOptions(X.getTargetOpts())),
DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())),
HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())),
PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())),
AnalyzerOpts(new AnalyzerOptions(X.getAnalyzerOpts())) {}

CompilerInvocationRefBase::CompilerInvocationRefBase(
CompilerInvocationRefBase &&X) = default;

CompilerInvocationRefBase &
CompilerInvocationRefBase::operator=(CompilerInvocationRefBase X) {
LangOpts.swap(X.LangOpts);
TargetOpts.swap(X.TargetOpts);
DiagnosticOpts.swap(X.DiagnosticOpts);
HeaderSearchOpts.swap(X.HeaderSearchOpts);
PreprocessorOpts.swap(X.PreprocessorOpts);
AnalyzerOpts.swap(X.AnalyzerOpts);
return *this;
namespace {
template <class T> std::shared_ptr<T> make_shared_copy(const T &X) {
return std::make_shared<T>(X);
}

CompilerInvocationRefBase &
CompilerInvocationRefBase::operator=(CompilerInvocationRefBase &&X) = default;

CompilerInvocationRefBase::~CompilerInvocationRefBase() = default;
template <class T>
llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCntCopy(const T &X) {
return llvm::makeIntrusiveRefCnt<T>(X);
}
} // namespace

CompilerInvocationBase::CompilerInvocationBase()
: LangOpts(std::make_shared<LangOptions>()),
TargetOpts(std::make_shared<TargetOptions>()),
DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
HSOpts(std::make_shared<HeaderSearchOptions>()),
PPOpts(std::make_shared<PreprocessorOptions>()),
AnalyzerOpts(llvm::makeIntrusiveRefCnt<AnalyzerOptions>()),
MigratorOpts(std::make_shared<MigratorOptions>()),
CodeGenOpts(std::make_shared<CodeGenOptions>()),
FSOpts(std::make_shared<FileSystemOptions>()),
FrontendOpts(std::make_shared<FrontendOptions>()),
DependencyOutputOpts(std::make_shared<DependencyOutputOptions>()),
PreprocessorOutputOpts(std::make_shared<PreprocessorOutputOptions>()) {}

CompilerInvocationBase &
CompilerInvocationBase::operator=(const CompilerInvocationBase &X) {
if (this != &X) {
LangOpts = make_shared_copy(X.getLangOpts());
TargetOpts = make_shared_copy(X.getTargetOpts());
DiagnosticOpts = makeIntrusiveRefCntCopy(X.getDiagnosticOpts());
HSOpts = make_shared_copy(X.getHeaderSearchOpts());
PPOpts = make_shared_copy(X.getPreprocessorOpts());
AnalyzerOpts = makeIntrusiveRefCntCopy(X.getAnalyzerOpts());
MigratorOpts = make_shared_copy(X.getMigratorOpts());
CodeGenOpts = make_shared_copy(X.getCodeGenOpts());
FSOpts = make_shared_copy(X.getFileSystemOpts());
FrontendOpts = make_shared_copy(X.getFrontendOpts());
DependencyOutputOpts = make_shared_copy(X.getDependencyOutputOpts());
PreprocessorOutputOpts = make_shared_copy(X.getPreprocessorOutputOpts());
}
return *this;
}

//===----------------------------------------------------------------------===//
// Normalizers
Expand Down Expand Up @@ -838,7 +847,7 @@ static void getAllNoBuiltinFuncValues(ArgList &Args,
Funcs.insert(Funcs.end(), Values.begin(), BuiltinEnd);
}

static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
static void GenerateAnalyzerArgs(const AnalyzerOptions &Opts,
ArgumentConsumer Consumer) {
const AnalyzerOptions *AnalyzerOpts = &Opts;

Expand Down Expand Up @@ -2917,7 +2926,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
}

static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
ArgumentConsumer Consumer) {
const HeaderSearchOptions *HeaderSearchOpts = &Opts;
#define HEADER_SEARCH_OPTION_WITH_MARSHALLING(...) \
Expand Down Expand Up @@ -4103,12 +4112,12 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
llvm_unreachable("invalid frontend action");
}

static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
static void GeneratePreprocessorArgs(const PreprocessorOptions &Opts,
ArgumentConsumer Consumer,
const LangOptions &LangOpts,
const FrontendOptions &FrontendOpts,
const CodeGenOptions &CodeGenOpts) {
PreprocessorOptions *PreprocessorOpts = &Opts;
const PreprocessorOptions *PreprocessorOpts = &Opts;

#define PREPROCESSOR_OPTION_WITH_MARSHALLING(...) \
GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
Expand Down Expand Up @@ -4514,15 +4523,15 @@ std::string CompilerInvocation::getModuleHash() const {
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"

HBuilder.addRange(LangOpts->ModuleFeatures);
HBuilder.addRange(getLangOpts().ModuleFeatures);

HBuilder.add(LangOpts->ObjCRuntime);
HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames);
HBuilder.add(getLangOpts().ObjCRuntime);
HBuilder.addRange(getLangOpts().CommentOpts.BlockCommandNames);

// Extend the signature with the target options.
HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU,
TargetOpts->ABI);
HBuilder.addRange(TargetOpts->FeaturesAsWritten);
HBuilder.add(getTargetOpts().Triple, getTargetOpts().CPU,
getTargetOpts().TuneCPU, getTargetOpts().ABI);
HBuilder.addRange(getTargetOpts().FeaturesAsWritten);

// Extend the signature with preprocessor options.
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
Expand Down Expand Up @@ -4577,7 +4586,7 @@ std::string CompilerInvocation::getModuleHash() const {

// Extend the signature with the enabled sanitizers, if at least one is
// enabled. Sanitizers which cannot affect AST generation aren't hashed.
SanitizerSet SanHash = LangOpts->Sanitize;
SanitizerSet SanHash = getLangOpts().Sanitize;
SanHash.clear(getPPTransparentSanitizers());
if (!SanHash.empty())
HBuilder.add(SanHash.Mask);
Expand All @@ -4590,23 +4599,24 @@ std::string CompilerInvocation::getModuleHash() const {

void CompilerInvocation::generateCC1CommandLine(
ArgumentConsumer Consumer) const {
llvm::Triple T(TargetOpts->Triple);

GenerateFileSystemArgs(FileSystemOpts, Consumer);
GenerateMigratorArgs(MigratorOpts, Consumer);
GenerateAnalyzerArgs(*AnalyzerOpts, Consumer);
GenerateDiagnosticArgs(*DiagnosticOpts, Consumer, false);
GenerateFrontendArgs(FrontendOpts, Consumer, LangOpts->IsHeaderFile);
GenerateTargetArgs(*TargetOpts, Consumer);
GenerateHeaderSearchArgs(*HeaderSearchOpts, Consumer);
GenerateLangArgs(*LangOpts, Consumer, T, FrontendOpts.DashX);
GenerateCodeGenArgs(CodeGenOpts, Consumer, T, FrontendOpts.OutputFile,
&*LangOpts);
GeneratePreprocessorArgs(*PreprocessorOpts, Consumer, *LangOpts, FrontendOpts,
CodeGenOpts);
GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Consumer,
FrontendOpts.ProgramAction);
GenerateDependencyOutputArgs(DependencyOutputOpts, Consumer);
llvm::Triple T(getTargetOpts().Triple);

GenerateFileSystemArgs(getFileSystemOpts(), Consumer);
GenerateMigratorArgs(getMigratorOpts(), Consumer);
GenerateAnalyzerArgs(getAnalyzerOpts(), Consumer);
GenerateDiagnosticArgs(getDiagnosticOpts(), Consumer,
/*DefaultDiagColor=*/false);
GenerateFrontendArgs(getFrontendOpts(), Consumer, getLangOpts().IsHeaderFile);
GenerateTargetArgs(getTargetOpts(), Consumer);
GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer);
GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX);
GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T,
getFrontendOpts().OutputFile, &getLangOpts());
GeneratePreprocessorArgs(getPreprocessorOpts(), Consumer, getLangOpts(),
getFrontendOpts(), getCodeGenOpts());
GeneratePreprocessorOutputArgs(getPreprocessorOutputOpts(), Consumer,
getFrontendOpts().ProgramAction);
GenerateDependencyOutputArgs(getDependencyOutputOpts(), Consumer);
}

std::vector<std::string> CompilerInvocation::getCC1CommandLine() const {
Expand Down