Skip to content

Commit a874406

Browse files
authored
[clang-repl] Include consistency using the default clang actions. (#116610)
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 ee4fb3a commit a874406

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
@@ -338,19 +341,8 @@ class IncrementalAction : public WrapperFrontendAction {
338341
}
339342

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

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

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

391381
if (ErrOut)
392382
return;
393383

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

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

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

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

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

@@ -614,6 +619,14 @@ void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
614619

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

0 commit comments

Comments
 (0)