Skip to content

Commit 2b89c6b

Browse files
committed
[clang-repl] Include consistency using the default clang actions.
This patch improves the code reuse of the actions system and adds several improvements for easier debugging via clang-repl --debug-only=clang-repl. The change inimproves the consistency of the TUKind when actions are handled within a WrapperFrontendAction. In this case instead of falling back to default TU_Complete, we forward to the TUKind of the ASTContext which presumably was created by the intended action. This enables the incremental infrastructure to reuse code. This patch also clones the first llvm::Module because the first PTU now can come from -include A.h and the presumption of llvm::Module being empty does not hold. The changes are a first step to fix the issues with `clang-repl --cuda`.
1 parent b5dc7b8 commit 2b89c6b

File tree

5 files changed

+57
-31
lines changed

5 files changed

+57
-31
lines changed

clang/include/clang/Frontend/FrontendAction.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/Basic/LLVM.h"
2222
#include "clang/Basic/LangOptions.h"
2323
#include "clang/Frontend/ASTUnit.h"
24+
#include "clang/Frontend/CompilerInstance.h"
2425
#include "clang/Frontend/FrontendOptions.h"
2526
#include "llvm/ADT/StringRef.h"
2627
#include "llvm/Support/Error.h"
@@ -185,7 +186,12 @@ class FrontendAction {
185186
virtual bool usesPreprocessorOnly() const = 0;
186187

187188
/// For AST-based actions, the kind of translation unit we're handling.
188-
virtual TranslationUnitKind getTranslationUnitKind() { return TU_Complete; }
189+
virtual TranslationUnitKind getTranslationUnitKind() {
190+
// The ASTContext, if exists, knows the exact TUKind of the frondend.
191+
if (Instance && Instance->hasASTContext())
192+
return Instance->getASTContext().TUKind;
193+
return TU_Complete;
194+
}
189195

190196
/// Does this action support use with PCH?
191197
virtual bool hasPCHSupport() const { return true; }

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ class Interpreter {
177177

178178
CodeGenerator *getCodeGen() const;
179179
std::unique_ptr<llvm::Module> GenModule();
180-
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU);
180+
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
181+
std::unique_ptr<llvm::Module> M = {});
181182

182183
// A cache for the compiled destructors used to for de-allocation of managed
183184
// clang::Values.

clang/include/clang/Interpreter/PartialTranslationUnit.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ struct PartialTranslationUnit {
3131

3232
/// The llvm IR produced for the input.
3333
std::unique_ptr<llvm::Module> TheModule;
34+
bool operator==(const PartialTranslationUnit &other) {
35+
return other.TUPart == TUPart && other.TheModule == TheModule;
36+
}
3437
};
3538
} // namespace clang
3639

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ set(LLVM_LINK_COMPONENTS
1010
Support
1111
Target
1212
TargetParser
13-
)
13+
TransformUtils
14+
)
1415

1516
if (EMSCRIPTEN AND "lld" IN_LIST LLVM_ENABLE_PROJECTS)
1617
set(WASM_SRC Wasm.cpp)

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
#include "llvm/Support/ErrorHandling.h"
5151
#include "llvm/Support/raw_ostream.h"
5252
#include "llvm/TargetParser/Host.h"
53+
#include "llvm/Transforms/Utils/Cloning.h" // for CloneModule
54+
55+
#define DEBUG_TYPE "clang-repl"
5356

5457
using namespace clang;
5558
// FIXME: Figure out how to unify with namespace init_convenience from
@@ -339,19 +342,8 @@ class IncrementalAction : public WrapperFrontendAction {
339342
}
340343

341344
void ExecuteAction() override {
342-
CompilerInstance &CI = getCompilerInstance();
343-
assert(CI.hasPreprocessor() && "No PP!");
344-
345-
// Use a code completion consumer?
346-
CodeCompleteConsumer *CompletionConsumer = nullptr;
347-
if (CI.hasCodeCompletionConsumer())
348-
CompletionConsumer = &CI.getCodeCompletionConsumer();
349-
350-
Preprocessor &PP = CI.getPreprocessor();
351-
PP.EnterMainSourceFile();
352-
353-
if (!CI.hasSema())
354-
CI.createSema(getTranslationUnitKind(), CompletionConsumer);
345+
WrapperFrontendAction::ExecuteAction();
346+
getCompilerInstance().getSema().CurContext = nullptr;
355347
}
356348

357349
// Do not terminate after processing the input. This allows us to keep various
@@ -385,27 +377,29 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
385377
return;
386378
CI->ExecuteAction(*Act);
387379

388-
ASTContext &C = CI->getASTContext();
389-
390380
IncrParser = std::make_unique<IncrementalParser>(*CI, ErrOut);
391381

392382
if (ErrOut)
393383
return;
394384

395385
if (getCodeGen()) {
396386
CachedInCodeGenModule = GenModule();
387+
// The initial PTU is filled by `-include` or by CUDA includes
388+
// automatically.
389+
if (!CI->getPreprocessorOpts().Includes.empty()) {
390+
// We can't really directly pass the CachedInCodeGenModule to the Jit
391+
// because it will steal it, causing dangling references as explained in
392+
// Interpreter::Execute
393+
auto M = llvm::CloneModule(*CachedInCodeGenModule);
394+
ASTContext &C = CI->getASTContext();
395+
RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
396+
}
397397
if (llvm::Error Err = CreateExecutor()) {
398398
ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
399399
return;
400400
}
401401
}
402402

403-
// The initial PTU is filled by `-include` or by CUDA includes automatically.
404-
RegisterPTU(C.getTranslationUnitDecl());
405-
406-
// Prepare the IncrParser for input.
407-
llvm::cantFail(Parse(""));
408-
409403
// Not all frontends support code-generation, e.g. ast-dump actions don't
410404
if (getCodeGen()) {
411405
// Process the PTUs that came from initialization. For example -include will
@@ -535,14 +529,25 @@ size_t Interpreter::getEffectivePTUSize() const {
535529
return PTUs.size() - InitPTUSize;
536530
}
537531

538-
PartialTranslationUnit &Interpreter::RegisterPTU(TranslationUnitDecl *TU) {
532+
PartialTranslationUnit &
533+
Interpreter::RegisterPTU(TranslationUnitDecl *TU,
534+
std::unique_ptr<llvm::Module> M /*={}*/) {
539535
PTUs.emplace_back(PartialTranslationUnit());
540536
PartialTranslationUnit &LastPTU = PTUs.back();
541537
LastPTU.TUPart = TU;
542538

543-
if (std::unique_ptr<llvm::Module> M = GenModule())
544-
LastPTU.TheModule = std::move(M);
539+
if (!M)
540+
M = GenModule();
541+
542+
assert((!getCodeGen() || M) && "Must have a llvm::Module at this point");
545543

544+
LastPTU.TheModule = std::move(M);
545+
LLVM_DEBUG(llvm::dbgs() << "compile-ptu " << PTUs.size() - 1
546+
<< ": [TU=" << LastPTU.TUPart);
547+
if (LastPTU.TheModule)
548+
LLVM_DEBUG(llvm::dbgs() << ", M=" << LastPTU.TheModule.get() << " ("
549+
<< LastPTU.TheModule->getName() << ")");
550+
LLVM_DEBUG(llvm::dbgs() << "]\n");
546551
return LastPTU;
547552
}
548553

@@ -615,6 +620,14 @@ void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
615620

616621
llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
617622
assert(T.TheModule);
623+
LLVM_DEBUG(llvm::dbgs()
624+
<< "execute-ptu "
625+
<< ((std::find(PTUs.begin(), PTUs.end(), T) != PTUs.end())
626+
? std::distance(PTUs.begin(),
627+
std::find(PTUs.begin(), PTUs.end(), T))
628+
: -1)
629+
<< ": [TU=" << T.TUPart << ", M=" << T.TheModule.get() << " ("
630+
<< T.TheModule->getName() << ")]\n");
618631
if (!IncrExecutor) {
619632
auto Err = CreateExecutor();
620633
if (Err)
@@ -723,10 +736,12 @@ std::unique_ptr<llvm::Module> Interpreter::GenModule() {
723736
// of the module which does not map well to CodeGen's design. To work this
724737
// around we created an empty module to make CodeGen happy. We should make
725738
// sure it always stays empty.
726-
assert((!CachedInCodeGenModule || (CachedInCodeGenModule->empty() &&
727-
CachedInCodeGenModule->global_empty() &&
728-
CachedInCodeGenModule->alias_empty() &&
729-
CachedInCodeGenModule->ifunc_empty())) &&
739+
assert(((!CachedInCodeGenModule ||
740+
!getCompilerInstance()->getPreprocessorOpts().Includes.empty()) ||
741+
(CachedInCodeGenModule->empty() &&
742+
CachedInCodeGenModule->global_empty() &&
743+
CachedInCodeGenModule->alias_empty() &&
744+
CachedInCodeGenModule->ifunc_empty())) &&
730745
"CodeGen wrote to a readonly module");
731746
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
732747
CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());

0 commit comments

Comments
 (0)