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 <Hahnfeld@itc.rwth-aachen.de>
Co-authored-by: Jonas Hahnfeld <hahnjo@hahnjo.de>
This commit is contained in:
Jonas Hahnfeld 2021-03-12 10:01:12 +01:00 committed by jenkins
parent e13eff3119
commit fd2212c84e
6 changed files with 73 additions and 34 deletions

View File

@ -25,9 +25,9 @@ namespace cling {
public: public:
AutoFixer(Sema* S) : m_Sema(S), m_FoundDRE(0) {} AutoFixer(Sema* S) : m_Sema(S), m_FoundDRE(0) {}
void Fix(CompoundStmt* CS) { CompoundStmt* Fix(CompoundStmt* CS) {
if (!CS->size()) if (!CS->size())
return; return nullptr;
typedef llvm::SmallVector<Stmt*, 32> Statements; typedef llvm::SmallVector<Stmt*, 32> Statements;
Statements Stmts; Statements Stmts;
Stmts.append(CS->body_begin(), CS->body_end()); Stmts.append(CS->body_begin(), CS->body_end());
@ -44,18 +44,30 @@ namespace cling {
} }
} }
if (CS->size() != Stmts.size()) 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) { CXXTryStmt* Fix(CXXTryStmt* TS) {
Fix(TS->getTryBlock()); CompoundStmt *TryBlock = TS->getTryBlock();
for(unsigned int h = 0; h < TS->getNumHandlers(); ++h) { if (CompoundStmt *NewTryBlock = Fix(TryBlock))
Stmt *s = TS->getHandler(h)->getHandlerBlock(); TryBlock = NewTryBlock;
if (CompoundStmt* CS = dyn_cast_or_null<CompoundStmt>(s))
Fix(CS); llvm::SmallVector<Stmt*, 4> Handlers(TS->getNumHandlers());
else if (CXXTryStmt *HandlerTS = dyn_cast_or_null<CXXTryStmt>(s)) for (unsigned int h = 0; h < TS->getNumHandlers(); ++h) {
Fix(HandlerTS); Stmt *HandlerBlock = TS->getHandler(h)->getHandlerBlock();
if (CompoundStmt *HandlerCS = dyn_cast_or_null<CompoundStmt>(HandlerBlock)) {
if (CompoundStmt *NewHandlerCS = Fix(HandlerCS))
HandlerBlock = NewHandlerCS;
} else if (CXXTryStmt *HandlerTS = dyn_cast_or_null<CXXTryStmt>(HandlerBlock)) {
if (CXXTryStmt *NewHandlerTS = Fix(HandlerTS))
HandlerBlock = NewHandlerTS;
}
} }
return CXXTryStmt::Create(m_Sema->getASTContext(), TS->getTryLoc(),
TryBlock, Handlers);
} }
bool VisitDeclRefExpr(DeclRefExpr* DRE) { bool VisitDeclRefExpr(DeclRefExpr* DRE) {
@ -92,9 +104,12 @@ namespace cling {
// those. // those.
Stmt *Body = FD->getBody(); Stmt *Body = FD->getBody();
if (CompoundStmt* CS = dyn_cast_or_null<CompoundStmt>(Body)) if (CompoundStmt* CS = dyn_cast_or_null<CompoundStmt>(Body))
m_AutoFixer->Fix(CS); Body = m_AutoFixer->Fix(CS);
else if (CXXTryStmt *TS = dyn_cast_or_null<CXXTryStmt>(Body)) else if (CXXTryStmt *TS = dyn_cast_or_null<CXXTryStmt>(Body))
m_AutoFixer->Fix(TS); Body = m_AutoFixer->Fix(TS);
if (Body != nullptr)
FD->setBody(Body);
} }
return Result(D, true); return Result(D, true);
} }

View File

@ -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()) { if (hasNoErrors && !TouchedDecls.empty()) {
// Put the wrapper after its declarations. (Nice when AST dumping) // Put the wrapper after its declarations. (Nice when AST dumping)

View File

@ -289,12 +289,12 @@ namespace cling {
"Cannot have more than one stmt at that point"); "Cannot have more than one stmt at that point");
if (NewNode.isForReplacement()) { if (NewNode.isForReplacement()) {
if (Expr* E = NewNode.getAs<Expr>()) if (Expr* E = NewNode.getAs<Expr>()) {
// Assume void if still not escaped // Assume void if still not escaped
*I = SubstituteUnknownSymbol(m_Context->VoidTy, E); *I = SubstituteUnknownSymbol(m_Context->VoidTy, E);
} } else {
else { *I = NewNode.getAsSingleNode();
*I = NewNode.getAsSingleNode(); }
} }
} }
} }
@ -328,14 +328,21 @@ namespace cling {
// where we know what to do. For Stmt, though, we need to substitute here, // where we know what to do. For Stmt, though, we need to substitute here,
// knowing the "target" type. // knowing the "target" type.
ASTNodeInfo thenInfo = Visit(Node->getThen()); ASTNodeInfo thenInfo = Visit(Node->getThen());
if (thenInfo.isForReplacement()) if (thenInfo.isForReplacement()) {
Node->setThen(SubstituteUnknownSymbol(m_Context->VoidTy, Stmt* thenReplacement = thenInfo.getAsSingleNode();
thenInfo.getAs<Expr>())); if (Expr* thenExpr = dyn_cast<Expr>(thenReplacement))
thenReplacement = SubstituteUnknownSymbol(m_Context->VoidTy, thenExpr);
Node->setThen(thenReplacement);
}
if (Stmt* ElseExpr = Node->getElse()) { if (Stmt* ElseExpr = Node->getElse()) {
ASTNodeInfo elseInfo = Visit(ElseExpr); ASTNodeInfo elseInfo = Visit(ElseExpr);
if (elseInfo.isForReplacement()) if (elseInfo.isForReplacement()) {
Node->setElse(SubstituteUnknownSymbol(m_Context->VoidTy, Stmt* elseReplacement = elseInfo.getAsSingleNode();
elseInfo.getAs<Expr>())); if (Expr* elseExpr = dyn_cast<Expr>(elseReplacement))
elseReplacement =
SubstituteUnknownSymbol(m_Context->VoidTy, elseExpr);
Node->setElse(elseReplacement);
}
} }
return ASTNodeInfo(Node, false); 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; --m_NestedCompoundStmts;
return ASTNodeInfo(Node, 0); return ASTNodeInfo(NewCS, true);
} }
ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) { ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) {

View File

@ -105,7 +105,7 @@ namespace cling {
*(CS->body_begin()+indexOfLastExpr) = Result; *(CS->body_begin()+indexOfLastExpr) = Result;
} }
// Clear the artificial NullStmt-s // Clear the artificial NullStmt-s
if (!ClearNullStmts(CS)) { if (!ClearNullStmts(FD)) {
// FIXME: Why it is here? Shouldn't it be in DeclExtractor? // FIXME: Why it is here? Shouldn't it be in DeclExtractor?
// if no body remove the wrapper // if no body remove the wrapper
DeclContext* DC = FD->getDeclContext(); DeclContext* DC = FD->getDeclContext();
@ -166,14 +166,24 @@ namespace cling {
} }
unsigned ValuePrinterSynthesizer::ClearNullStmts(CompoundStmt* CS) { unsigned ValuePrinterSynthesizer::ClearNullStmts(FunctionDecl* FD) {
CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
assert(CS && "Missing body?");
llvm::SmallVector<Stmt*, 8> FBody; llvm::SmallVector<Stmt*, 8> FBody;
for (auto&& child: CS->children()) for (auto&& child: CS->children())
if (!isa<NullStmt>(child)) if (!isa<NullStmt>(child))
FBody.push_back(child); FBody.push_back(child);
if (CS->size() != FBody.size()) // If body would be empty, return early - the function will be removed.
CS->replaceStmts(*m_Context, FBody); 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(); return FBody.size();
} }

View File

@ -16,7 +16,6 @@
namespace clang { namespace clang {
class ASTContext; class ASTContext;
class CompoundStmt;
class Decl; class Decl;
class FunctionDecl; class FunctionDecl;
class Expr; class Expr;
@ -63,7 +62,7 @@ public:
/// critical error. /// critical error.
bool tryAttachVP(clang::FunctionDecl* FD); bool tryAttachVP(clang::FunctionDecl* FD);
clang::Expr* SynthesizeVP(clang::Expr* E); clang::Expr* SynthesizeVP(clang::Expr* E);
unsigned ClearNullStmts(clang::CompoundStmt* CS); unsigned ClearNullStmts(clang::FunctionDecl* FD);
// Find and cache cling::runtime on first request. // Find and cache cling::runtime on first request.
void FindAndCacheRuntimeLookupResult(clang::SourceLocation SourceLoc); void FindAndCacheRuntimeLookupResult(clang::SourceLocation SourceLoc);

View File

@ -169,8 +169,11 @@ namespace utils {
indexOfLastExpr++; indexOfLastExpr++;
newBody.insert(newBody.begin() + indexOfLastExpr, DRE); newBody.insert(newBody.begin() + indexOfLastExpr, DRE);
// Attach the new body (note: it does dealloc/alloc of all nodes) // Attach a new body.
CS->replaceStmts(S->getASTContext(), newBody); auto newCS = CompoundStmt::Create(S->getASTContext(), newBody,
CS->getLBracLoc(),
CS->getRBracLoc());
FD->setBody(newCS);
if (FoundAt) if (FoundAt)
*FoundAt = indexOfLastExpr; *FoundAt = indexOfLastExpr;
return DRE; return DRE;