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 @@ -3937,6 +3937,11 @@ } } + // Add DW_OP_deref to NRVO variables because we set their debug values to be + // references. + 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,20 @@ // Emit debug info for local var declaration. if (EmitDebugInfo && HaveInsertPoint()) { + Address DebugAddr = address; DI->setLocation(D.getLocation()); - (void)DI->EmitDeclareOfAutoVariable(&D, address.getPointer(), Builder); + + // NRVO variables are stored in the return register and are not always + // readable by the debugger. Get around this by storing a reference to + // the variable. + if (NRVO) { + llvm::Type *RefTy = + ConvertTypeForMem(getContext().getLValueReferenceType(Ty)); + DebugAddr = CreateTempAlloca(RefTy, getPointerAlign(), "nrvo_ref"); + Builder.CreateStore(ReturnValue.getPointer(), DebugAddr); + } + + (void)DI->EmitDeclareOfAutoVariable(&D, DebugAddr.getPointer(), Builder); } if (D.hasAttr() && HaveInsertPoint()) 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 @@ -14,10 +14,13 @@ ~string() {} int i = 0; }; +int some_function_call(int i) { return i; } string get_string() { string unused; string result = 3; -// DEBUGGER: break 21 + // DEBUGGER: break 21 + result = some_function_call(47); + // DEBUGGER: break 23 return result; } int main() { get_string(); } @@ -25,3 +28,6 @@ // DEBUGGER: r // DEBUGGER: print result.i // CHECK: = 3 +// DEBUGGER: c +// DEBUGGER: print result.i +// CHECK: = 47 diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2468,8 +2468,9 @@ static void appendOffset(SmallVectorImpl &Ops, int64_t Offset); /// If this is a constant offset, extract it. If there is no expression, - /// return true with an offset of zero. - bool extractIfOffset(int64_t &Offset) const; + /// or if there is one expression of DW_OP_deref, return true with an offset + /// of zero. Also set Deref. + bool extractIfOffset(int64_t &Offset, bool &Deref) const; /// Checks if the last 4 elements of the expression are DW_OP_constu DW_OP_swap DW_OP_xderef and extracts the extractIfOffset(ExprOffset)) + bool Deref = false; + if (VI.Expr) { + if (!VI.Expr->extractIfOffset(ExprOffset, Deref)) continue; + } // Get the frame register used and the offset. unsigned FrameReg = 0; @@ -1154,6 +1156,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 +1167,9 @@ LocalVariable Var; Var.DIVar = VI.Var; Var.DefRanges.emplace_back(std::move(DefRange)); + if (Deref) + Var.UseReferenceType = true; + recordLocalVariable(std::move(Var), Scope); } } diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -936,12 +936,20 @@ } } -bool DIExpression::extractIfOffset(int64_t &Offset) const { +bool DIExpression::extractIfOffset(int64_t &Offset, bool &Deref) const { + Deref = false; + if (getNumElements() == 0) { Offset = 0; return true; } + if (getNumElements() == 1 && Elements[0] == dwarf::DW_OP_deref) { + Offset = 0; + Deref = true; + return true; + } + if (getNumElements() == 2 && Elements[0] == dwarf::DW_OP_plus_uconst) { Offset = Elements[1]; return true;