forked from OSchip/llvm-project
[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:
parent
9899427174
commit
1c2e7d200d
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
Loading…
Reference in New Issue