[MS] Fix crash involving gnu stmt exprs and inalloca

Use a WeakTrackingVH to cope with the stmt emission logic that cleans up
unreachable blocks. This invalidates the reference to the deferred
replacement placeholder. Cope with it.

Fixes PR25102 (from 2015!)
This commit is contained in:
Reid Kleckner 2021-03-04 13:52:30 -08:00
parent 9899427174
commit 1c2e7d200d
4 changed files with 61 additions and 9 deletions

View File

@ -4436,7 +4436,8 @@ llvm::CallBase *CodeGenFunction::EmitCallOrInvoke(llvm::FunctionCallee Callee,
void CodeGenFunction::deferPlaceholderReplacement(llvm::Instruction *Old,
llvm::Value *New) {
DeferredReplacements.push_back(std::make_pair(Old, New));
DeferredReplacements.push_back(
std::make_pair(llvm::WeakTrackingVH(Old), New));
}
namespace {

View File

@ -452,13 +452,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
if (CGM.getCodeGenOpts().EmitDeclMetadata)
EmitDeclMetadata();
for (SmallVectorImpl<std::pair<llvm::Instruction *, llvm::Value *> >::iterator
I = DeferredReplacements.begin(),
E = DeferredReplacements.end();
I != E; ++I) {
I->first->replaceAllUsesWith(I->second);
I->first->eraseFromParent();
for (const auto &R : DeferredReplacements) {
if (llvm::Value *Old = R.first) {
Old->replaceAllUsesWith(R.second);
cast<llvm::Instruction>(Old)->eraseFromParent();
}
}
DeferredReplacements.clear();
// Eliminate CleanupDestSlot alloca by replacing it with SSA values and
// PHIs if the current function is a coroutine. We don't do it for all

View File

@ -4539,8 +4539,8 @@ private:
void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New);
llvm::SmallVector<std::pair<llvm::Instruction *, llvm::Value *>, 4>
DeferredReplacements;
llvm::SmallVector<std::pair<llvm::WeakTrackingVH, llvm::Value *>, 4>
DeferredReplacements;
/// Set the address of a local variable.
void setAddrOfLocalVar(const VarDecl *VD, Address Addr) {

View File

@ -0,0 +1,51 @@
// RUN: %clang_cc1 %s -emit-llvm -triple i686-windows-msvc -o - | FileCheck %s
// Statement allow the user to exit the evaluation scope of a CallExpr without
// executing the call. Check that clang generates reasonable IR for that case.
// Not trivially copyable, subject to inalloca.
struct Foo {
int x;
Foo();
~Foo();
};
void inalloca(Foo x, Foo y);
// PR25102: In this case, clang attempts to clean up unreachable blocks *during*
// IR generation. inalloca defers some RAUW operations to the end of codegen,
// and those references would become stale when the unreachable call to
// 'inalloca' got deleted.
extern "C" void pr25102() {
inalloca(Foo(), ({
goto out;
Foo();
}));
out:;
}
// CHECK-LABEL: define dso_local void @pr25102()
// CHECK: br label %out
// CHECK: out:
// CHECK: ret void
bool cond();
extern "C" void seqAbort() {
inalloca(Foo(), ({
if (cond())
goto out;
Foo();
}));
out:;
}
// FIXME: This can cause a stack leak. We should really have a "normal" cleanup
// that goto branches through.
// CHECK-LABEL: define dso_local void @seqAbort()
// CHECK: alloca inalloca <{ %struct.Foo, %struct.Foo }>
// CHECK: call zeroext i1 @"?cond@@YA_NXZ"()
// CHECK: br i1
// CHECK: br label %out
// CHECK: call void @"?inalloca@@YAXUFoo@@0@Z"(<{ %struct.Foo, %struct.Foo }>* inalloca %{{.*}})
// CHECK: call void @llvm.stackrestore(i8* %inalloca.save)
// CHECK: out: