Skip to content

Commit 9e2579d

Browse files
committed
Fix infinite recursion during IR emission if a constant-initialized lifetime-extended temporary object's initializer refers back to the same object.
`GetAddrOfGlobalTemporary` previously tried to emit the initializer of a global temporary before updating the global temporary map. Emitting the initializer could recurse back into `GetAddrOfGlobalTemporary` for the same temporary, resulting in an infinite recursion. Reviewed By: rjmccall Differential Revision: https://reviews.llvm.org/D97733
1 parent 6d2fd3d commit 9e2579d

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5325,8 +5325,21 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
53255325

53265326
CharUnits Align = getContext().getTypeAlignInChars(MaterializedType);
53275327

5328-
if (llvm::Constant *Slot = MaterializedGlobalTemporaryMap[E])
5329-
return ConstantAddress(Slot, Align);
5328+
auto InsertResult = MaterializedGlobalTemporaryMap.insert({E, nullptr});
5329+
if (!InsertResult.second) {
5330+
// We've seen this before: either we already created it or we're in the
5331+
// process of doing so.
5332+
if (!InsertResult.first->second) {
5333+
// We recursively re-entered this function, probably during emission of
5334+
// the initializer. Create a placeholder. We'll clean this up in the
5335+
// outer call, at the end of this function.
5336+
llvm::Type *Type = getTypes().ConvertTypeForMem(MaterializedType);
5337+
InsertResult.first->second = new llvm::GlobalVariable(
5338+
getModule(), Type, false, llvm::GlobalVariable::InternalLinkage,
5339+
nullptr);
5340+
}
5341+
return ConstantAddress(InsertResult.first->second, Align);
5342+
}
53305343

53315344
// FIXME: If an externally-visible declaration extends multiple temporaries,
53325345
// we need to give each temporary the same name in every translation unit (and
@@ -5405,7 +5418,17 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
54055418
*this, GV, AddrSpace, LangAS::Default,
54065419
Type->getPointerTo(
54075420
getContext().getTargetAddressSpace(LangAS::Default)));
5408-
MaterializedGlobalTemporaryMap[E] = CV;
5421+
5422+
// Update the map with the new temporary. If we created a placeholder above,
5423+
// replace it with the new global now.
5424+
llvm::Constant *&Entry = MaterializedGlobalTemporaryMap[E];
5425+
if (Entry) {
5426+
Entry->replaceAllUsesWith(
5427+
llvm::ConstantExpr::getBitCast(CV, Entry->getType()));
5428+
llvm::cast<llvm::GlobalVariable>(Entry)->eraseFromParent();
5429+
}
5430+
Entry = CV;
5431+
54095432
return ConstantAddress(CV, Align);
54105433
}
54115434

clang/test/CodeGenCXX/temporaries.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ namespace BraceInit {
5353
// CHECK: @_ZN9BraceInit1xE ={{.*}} constant i32* @_ZGRN9BraceInit1xE_
5454
}
5555

56+
namespace RefTempSubobject {
57+
struct SelfReferential {
58+
int *p = ints;
59+
int ints[3] = {1, 2, 3};
60+
};
61+
62+
// CHECK: @_ZGRN16RefTempSubobject2srE_ = internal global { i32*, [3 x i32] } { {{.*}} getelementptr {{.*}} @_ZGRN16RefTempSubobject2srE_ {{.*}}, [3 x i32] [i32 1, i32 2, i32 3] }
63+
// CHECK: @_ZN16RefTempSubobject2srE = {{.*}} constant {{.*}} @_ZGRN16RefTempSubobject2srE_
64+
constexpr const SelfReferential &sr = SelfReferential();
65+
}
66+
5667
struct A {
5768
A();
5869
~A();

0 commit comments

Comments
 (0)