From fd2212c84e8b2b91d6c7028170e30354a226d1e4 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 12 Mar 2021 10:01:12 +0100 Subject: [PATCH] Create new CompoundStmt instead of replacing children For the update of LLVM 9, Cling required another patch to Clang for replacing the children of a CompoundStmt. Instead solve this by creating a new CompoundStmt with the right Stmts attached. Co-authored-by: Jonas Hahnfeld Co-authored-by: Jonas Hahnfeld --- lib/Interpreter/AutoSynthesizer.cpp | 41 ++++++++++++++------- lib/Interpreter/DeclExtractor.cpp | 5 ++- lib/Interpreter/DynamicLookup.cpp | 33 +++++++++++------ lib/Interpreter/ValuePrinterSynthesizer.cpp | 18 +++++++-- lib/Interpreter/ValuePrinterSynthesizer.h | 3 +- lib/Utils/AST.cpp | 7 +++- 6 files changed, 73 insertions(+), 34 deletions(-) diff --git a/lib/Interpreter/AutoSynthesizer.cpp b/lib/Interpreter/AutoSynthesizer.cpp index 576edd9d..2dab7d3c 100644 --- a/lib/Interpreter/AutoSynthesizer.cpp +++ b/lib/Interpreter/AutoSynthesizer.cpp @@ -25,9 +25,9 @@ namespace cling { public: AutoFixer(Sema* S) : m_Sema(S), m_FoundDRE(0) {} - void Fix(CompoundStmt* CS) { + CompoundStmt* Fix(CompoundStmt* CS) { if (!CS->size()) - return; + return nullptr; typedef llvm::SmallVector Statements; Statements Stmts; Stmts.append(CS->body_begin(), CS->body_end()); @@ -44,18 +44,30 @@ namespace cling { } } if (CS->size() != Stmts.size()) - CS->replaceStmts(m_Sema->getASTContext(), Stmts); + return CompoundStmt::Create(m_Sema->getASTContext(), Stmts, + CS->getLBracLoc(), CS->getRBracLoc()); + return nullptr; } - void Fix(CXXTryStmt* TS) { - Fix(TS->getTryBlock()); - for(unsigned int h = 0; h < TS->getNumHandlers(); ++h) { - Stmt *s = TS->getHandler(h)->getHandlerBlock(); - if (CompoundStmt* CS = dyn_cast_or_null(s)) - Fix(CS); - else if (CXXTryStmt *HandlerTS = dyn_cast_or_null(s)) - Fix(HandlerTS); + CXXTryStmt* Fix(CXXTryStmt* TS) { + CompoundStmt *TryBlock = TS->getTryBlock(); + if (CompoundStmt *NewTryBlock = Fix(TryBlock)) + TryBlock = NewTryBlock; + + llvm::SmallVector Handlers(TS->getNumHandlers()); + for (unsigned int h = 0; h < TS->getNumHandlers(); ++h) { + Stmt *HandlerBlock = TS->getHandler(h)->getHandlerBlock(); + if (CompoundStmt *HandlerCS = dyn_cast_or_null(HandlerBlock)) { + if (CompoundStmt *NewHandlerCS = Fix(HandlerCS)) + HandlerBlock = NewHandlerCS; + } else if (CXXTryStmt *HandlerTS = dyn_cast_or_null(HandlerBlock)) { + if (CXXTryStmt *NewHandlerTS = Fix(HandlerTS)) + HandlerBlock = NewHandlerTS; + } } + + return CXXTryStmt::Create(m_Sema->getASTContext(), TS->getTryLoc(), + TryBlock, Handlers); } bool VisitDeclRefExpr(DeclRefExpr* DRE) { @@ -92,9 +104,12 @@ namespace cling { // those. Stmt *Body = FD->getBody(); if (CompoundStmt* CS = dyn_cast_or_null(Body)) - m_AutoFixer->Fix(CS); + Body = m_AutoFixer->Fix(CS); else if (CXXTryStmt *TS = dyn_cast_or_null(Body)) - m_AutoFixer->Fix(TS); + Body = m_AutoFixer->Fix(TS); + + if (Body != nullptr) + FD->setBody(Body); } return Result(D, true); } diff --git a/lib/Interpreter/DeclExtractor.cpp b/lib/Interpreter/DeclExtractor.cpp index c00ea33a..b0d3f293 100644 --- a/lib/Interpreter/DeclExtractor.cpp +++ b/lib/Interpreter/DeclExtractor.cpp @@ -211,7 +211,10 @@ namespace cling { } } - CS->replaceStmts(*m_Context, Stmts); + // Create a new body. + auto newCS = CompoundStmt::Create(*m_Context, Stmts, CS->getLBracLoc(), + CS->getRBracLoc()); + FD->setBody(newCS); if (hasNoErrors && !TouchedDecls.empty()) { // Put the wrapper after its declarations. (Nice when AST dumping) diff --git a/lib/Interpreter/DynamicLookup.cpp b/lib/Interpreter/DynamicLookup.cpp index 78eef3e5..c0e14731 100644 --- a/lib/Interpreter/DynamicLookup.cpp +++ b/lib/Interpreter/DynamicLookup.cpp @@ -289,12 +289,12 @@ namespace cling { "Cannot have more than one stmt at that point"); if (NewNode.isForReplacement()) { - if (Expr* E = NewNode.getAs()) + if (Expr* E = NewNode.getAs()) { // Assume void if still not escaped *I = SubstituteUnknownSymbol(m_Context->VoidTy, E); - } - else { - *I = NewNode.getAsSingleNode(); + } else { + *I = NewNode.getAsSingleNode(); + } } } } @@ -328,14 +328,21 @@ namespace cling { // where we know what to do. For Stmt, though, we need to substitute here, // knowing the "target" type. ASTNodeInfo thenInfo = Visit(Node->getThen()); - if (thenInfo.isForReplacement()) - Node->setThen(SubstituteUnknownSymbol(m_Context->VoidTy, - thenInfo.getAs())); + if (thenInfo.isForReplacement()) { + Stmt* thenReplacement = thenInfo.getAsSingleNode(); + if (Expr* thenExpr = dyn_cast(thenReplacement)) + thenReplacement = SubstituteUnknownSymbol(m_Context->VoidTy, thenExpr); + Node->setThen(thenReplacement); + } if (Stmt* ElseExpr = Node->getElse()) { ASTNodeInfo elseInfo = Visit(ElseExpr); - if (elseInfo.isForReplacement()) - Node->setElse(SubstituteUnknownSymbol(m_Context->VoidTy, - elseInfo.getAs())); + if (elseInfo.isForReplacement()) { + Stmt* elseReplacement = elseInfo.getAsSingleNode(); + if (Expr* elseExpr = dyn_cast(elseReplacement)) + elseReplacement = + SubstituteUnknownSymbol(m_Context->VoidTy, elseExpr); + Node->setElse(elseReplacement); + } } return ASTNodeInfo(Node, false); @@ -382,10 +389,12 @@ namespace cling { } } - Node->replaceStmts(*m_Context, NewChildren); + auto* NewCS = CompoundStmt::Create(*m_Context, NewChildren, + Node->getLBracLoc(), + Node->getRBracLoc()); --m_NestedCompoundStmts; - return ASTNodeInfo(Node, 0); + return ASTNodeInfo(NewCS, true); } ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) { diff --git a/lib/Interpreter/ValuePrinterSynthesizer.cpp b/lib/Interpreter/ValuePrinterSynthesizer.cpp index 98f51d07..fa03e651 100644 --- a/lib/Interpreter/ValuePrinterSynthesizer.cpp +++ b/lib/Interpreter/ValuePrinterSynthesizer.cpp @@ -105,7 +105,7 @@ namespace cling { *(CS->body_begin()+indexOfLastExpr) = Result; } // Clear the artificial NullStmt-s - if (!ClearNullStmts(CS)) { + if (!ClearNullStmts(FD)) { // FIXME: Why it is here? Shouldn't it be in DeclExtractor? // if no body remove the wrapper DeclContext* DC = FD->getDeclContext(); @@ -166,14 +166,24 @@ namespace cling { } - unsigned ValuePrinterSynthesizer::ClearNullStmts(CompoundStmt* CS) { + unsigned ValuePrinterSynthesizer::ClearNullStmts(FunctionDecl* FD) { + CompoundStmt* CS = cast(FD->getBody()); + assert(CS && "Missing body?"); + llvm::SmallVector FBody; for (auto&& child: CS->children()) if (!isa(child)) FBody.push_back(child); - if (CS->size() != FBody.size()) - CS->replaceStmts(*m_Context, FBody); + // If body would be empty, return early - the function will be removed. + if (FBody.empty()) + return 0; + + if (CS->size() != FBody.size()) { + auto BodyCS = CompoundStmt::Create(*m_Context, FBody, CS->getLBracLoc(), + CS->getRBracLoc()); + FD->setBody(BodyCS); + } return FBody.size(); } diff --git a/lib/Interpreter/ValuePrinterSynthesizer.h b/lib/Interpreter/ValuePrinterSynthesizer.h index 1a2ac501..adf513af 100644 --- a/lib/Interpreter/ValuePrinterSynthesizer.h +++ b/lib/Interpreter/ValuePrinterSynthesizer.h @@ -16,7 +16,6 @@ namespace clang { class ASTContext; - class CompoundStmt; class Decl; class FunctionDecl; class Expr; @@ -63,7 +62,7 @@ public: /// critical error. bool tryAttachVP(clang::FunctionDecl* FD); clang::Expr* SynthesizeVP(clang::Expr* E); - unsigned ClearNullStmts(clang::CompoundStmt* CS); + unsigned ClearNullStmts(clang::FunctionDecl* FD); // Find and cache cling::runtime on first request. void FindAndCacheRuntimeLookupResult(clang::SourceLocation SourceLoc); diff --git a/lib/Utils/AST.cpp b/lib/Utils/AST.cpp index e5d3eb00..f5ae42ad 100644 --- a/lib/Utils/AST.cpp +++ b/lib/Utils/AST.cpp @@ -169,8 +169,11 @@ namespace utils { indexOfLastExpr++; newBody.insert(newBody.begin() + indexOfLastExpr, DRE); - // Attach the new body (note: it does dealloc/alloc of all nodes) - CS->replaceStmts(S->getASTContext(), newBody); + // Attach a new body. + auto newCS = CompoundStmt::Create(S->getASTContext(), newBody, + CS->getLBracLoc(), + CS->getRBracLoc()); + FD->setBody(newCS); if (FoundAt) *FoundAt = indexOfLastExpr; return DRE;