diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3940,6 +3940,12 @@ } } + // Clang stores the sret pointer provided by the caller in a static alloca. + // Use DW_OP_deref to tell the debugger to load the pointer and treat it as + // the address of the variable. + if (VD->isNRVOVariable()) + Expr.push_back(llvm::dwarf::DW_OP_deref); + // Create the descriptor for the variable. auto *D = ArgNo ? DBuilder.createParameterVariable( Scope, Name, *ArgNo, Unit, Line, Ty, diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1403,12 +1403,11 @@ getLangOpts().OpenMP ? CGM.getOpenMPRuntime().getAddressOfLocalVariable(*this, &D) : Address::invalid(); + bool NRVO = getLangOpts().ElideConstructors && D.isNRVOVariable(); + if (getLangOpts().OpenMP && OpenMPLocalAddr.isValid()) { address = OpenMPLocalAddr; } else if (Ty->isConstantSizeType()) { - bool NRVO = getLangOpts().ElideConstructors && - D.isNRVOVariable(); - // If this value is an array or struct with a statically determinable // constant initializer, there are optimizations we can do. // @@ -1561,8 +1560,14 @@ // Emit debug info for local var declaration. if (EmitDebugInfo && HaveInsertPoint()) { + Address DebugAddr = address; DI->setLocation(D.getLocation()); - (void)DI->EmitDeclareOfAutoVariable(&D, address.getPointer(), Builder); + + // If NRVO, use a pointer to the return address. + if (NRVO && ReturnValuePointer.isValid()) + DebugAddr = ReturnValuePointer; + + (void)DI->EmitDeclareOfAutoVariable(&D, DebugAddr.getPointer(), Builder); } if (D.hasAttr() && HaveInsertPoint()) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -327,6 +327,10 @@ /// value. This is invalid iff the function has no return value. Address ReturnValue = Address::invalid(); + /// ReturnValuePointer - The temporary alloca to hold a pointer to sret. + /// This is invalid if sret is not in use. + Address ReturnValuePointer = Address::invalid(); + /// Return true if a label was seen in the current scope. bool hasLabelBeenSeenInCurrentScope() const { if (CurLexicalScope) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -895,6 +895,10 @@ if (CurFnInfo->getReturnInfo().isSRetAfterThis()) ++AI; ReturnValue = Address(&*AI, CurFnInfo->getReturnInfo().getIndirectAlign()); + ReturnValuePointer = CreateDefaultAlignTempAlloca(Int8PtrTy, "result.ptr"); + Builder.CreateStore(Builder.CreatePointerBitCastOrAddrSpaceCast( + ReturnValue.getPointer(), Int8PtrTy), + ReturnValuePointer); } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca && !hasScalarEvaluationKind(CurFnInfo->getReturnType())) { // Load the sret pointer from the argument struct and return into that. @@ -904,6 +908,10 @@ llvm::Value *Addr = Builder.CreateStructGEP(nullptr, &*EI, Idx); Addr = Builder.CreateAlignedLoad(Addr, getPointerAlign(), "agg.result"); ReturnValue = Address(Addr, getNaturalTypeAlignment(RetTy)); + ReturnValuePointer = CreateDefaultAlignTempAlloca(Int8PtrTy, "result.ptr"); + Builder.CreateStore(Builder.CreatePointerBitCastOrAddrSpaceCast( + ReturnValue.getPointer(), Int8PtrTy), + ReturnValuePointer); } else { ReturnValue = CreateIRTemp(RetTy, "retval"); diff --git a/debuginfo-tests/nrvo-string.cpp b/debuginfo-tests/nrvo-string.cpp --- a/debuginfo-tests/nrvo-string.cpp +++ b/debuginfo-tests/nrvo-string.cpp @@ -17,11 +17,31 @@ string get_string() { string unused; string result = 3; -// DEBUGGER: break 21 + // DEBUGGER: break 21 return result; } -int main() { get_string(); } +void some_function(int) {} +struct string2 { + string2() = default; + string2(string2 &&other) { i = other.i; } + int i; +} string2 get_string2() { + string2 result; + result.i = 5; + some_function(result.i); + // Test that the debugger can get the value of result after another + // function is called. + // DEBUGGER: break 35 + return result; +} +int main() { + get_string(); + get_string2(); +} // DEBUGGER: r // DEBUGGER: print result.i // CHECK: = 3 +// DEBUGGER: c +// DEBUGGER: print result.i +// CHECK: = 5 diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1142,9 +1142,15 @@ // If the variable has an attached offset expression, extract it. // FIXME: Try to handle DW_OP_deref as well. int64_t ExprOffset = 0; - if (VI.Expr) - if (!VI.Expr->extractIfOffset(ExprOffset)) + bool Deref = false; + if (VI.Expr) { + // If there is one DW_OP_deref element, use offset of 0 and keep going. + if (VI.Expr->getNumElements() == 1 && + VI.Expr->getElement(0) == llvm::dwarf::DW_OP_deref) + Deref = true; + else if (!VI.Expr->extractIfOffset(ExprOffset)) continue; + } // Get the frame register used and the offset. unsigned FrameReg = 0; @@ -1154,6 +1160,7 @@ // Calculate the label ranges. LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset + ExprOffset); + for (const InsnRange &Range : Scope->getRanges()) { const MCSymbol *Begin = getLabelBeforeInsn(Range.first); const MCSymbol *End = getLabelAfterInsn(Range.second); @@ -1164,6 +1171,9 @@ LocalVariable Var; Var.DIVar = VI.Var; Var.DefRanges.emplace_back(std::move(DefRange)); + if (Deref) + Var.UseReferenceType = true; + recordLocalVariable(std::move(Var), Scope); } }