Skip to content

Commit

Permalink
[cling] TransactionUnloader: ensure function instantiations are proce…
Browse files Browse the repository at this point in the history
…ssed only once

Implicit instantiation of a function template calls
`DeclCollector::HandleCXXImplicitFunctionInstantiation()`, which appends the
FunctionDecl to the transaction.  According to clang documentation, the body of
the function has not yet been instantiated. `HandleTopLevelDecl()` will be
called again for this decl at the end of the TU, which will append it
again to the transaction - same `Decl *`, different ConsumerCallInfo.

This is by design. However, unloading of decls in the transaction should
not process the same `Decl *` twice. In particular, entries with ConsumerCallInfo
== `kCCIHandleCXXImplicitFunctionInstantiation` will omitted.

Fixes issue #9850.
  • Loading branch information
jalopezg-git committed Mar 3, 2022
1 parent 4b22703 commit cd9d087
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 5 deletions.
20 changes: 15 additions & 5 deletions interpreter/cling/lib/Interpreter/TransactionUnloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,23 @@ namespace cling {

if (Call == Transaction::kCCIHandleVTable)
continue;

// The documentation for `ASTConsumer::HandleCXXImplicitFunctionInstantiation()`
// states that implicit function instantiations come through both
// `HandleCXXImplicitFunctionInstantiation` (before the body is intantiated)
// and `HandleTopLevelDecl` (after).
// Therefore, the same decl is duplicated in the transaction differing in the ConsumerCallInfo. `UnloadDecl()` should be called only once.
if (Call == Transaction::kCCIHandleCXXImplicitFunctionInstantiation)
continue;

// The non templated classes come through HandleTopLevelDecl and
// HandleTagDeclDefinition, this is why we need to filter.
if (Call == Transaction::kCCIHandleTagDeclDefinition)
if (const CXXRecordDecl* D
= dyn_cast<CXXRecordDecl>(DGR.getSingleDecl()))
if (D->getTemplateSpecializationKind() == TSK_Undeclared)
continue;
if (Call == Transaction::kCCIHandleTagDeclDefinition) {
if (const CXXRecordDecl* D
= dyn_cast<CXXRecordDecl>(DGR.getSingleDecl()))
if (D->getTemplateSpecializationKind() == TSK_Undeclared)
continue;
}

if (Call == Transaction::kCCINone)
m_Interp->unload(*(*T->rnested_begin()));
Expand Down
5 changes: 5 additions & 0 deletions interpreter/cling/test/CodeUnloading/RereadFile.C
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ macro() // CHECK: 2.version 2
//CHECK: 13
.x unnamedns.h
//CHECK-NEXT: 13

.x templatedfunc.h
//CHECK: 4
.x templatedfunc.h
//CHECK-NEXT: 4
10 changes: 10 additions & 0 deletions interpreter/cling/test/CodeUnloading/templatedfunc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
template <typename T> T square(T x) {
// This unused lambda caused a crash if the file is unloaded; see
// https://github.com/root-project/root/issues/9850
auto lambda = [](double x) { return x; };
return x * x;
}

void templatedfunc() {
printf("%d\n", square(2));
}

0 comments on commit cd9d087

Please sign in to comment.