Reapply "DebugInfo: Generalize debug info location handling"

Originally committed in r224385 and reverted in r224441 due to concerns
this change might've introduced a crash. Turns out this change fixes the
crash introduced by one of my earlier more specific location handling
changes (those specific fixes are reverted by this patch, in favor of
the more general solution).

Recommitted in r224941 and reverted in r224970 after it caused a crash
when building compiler-rt. Looks to be due to this change zeroing out
the debug location when emitting default arguments (which were meant to
inherit their outer expression's location) thus creating call
instructions without locations - these create problems for inlining and
must not be created. That is fixed and tested in this version of the
change.

Original commit message:

This is a more scalable (fixed in mostly one place, rather than many
places that will need constant improvement/maintenance) solution to
several commits I've made recently to increase source fidelity for
subexpressions.

This resetting had to be done at the DebugLoc level (not the
SourceLocation level) to preserve scoping information (if the resetting
was done with CGDebugInfo::EmitLocation, it would've caused the tail end
of an expression's codegen to end up in a potentially different scope
than the start, even though it was at the same source location). The
drawback to this is that it might leave CGDebugInfo out of sync. Ideally
CGDebugInfo shouldn't have a duplicate sense of the current
SourceLocation, but for now it seems it does... - I don't think I'm
going to tackle removing that just now.

I expect this'll probably cause some more buildbot fallout & I'll
investigate that as it comes up.

Also these sort of improvements might be starting to show a weakness/bug
in LLVM's line table handling: we don't correctly emit is_stmt for
statements, we just put it on every line table entry. This means one
statement split over multiple lines appears as multiple 'statements' and
two statements on one line (without column info) are treated as one
statement.

I don't think we have any IR representation of statements that would
help us distinguish these cases and identify the beginning of each
statement - so that might be something we need to add (possibly to the
lexical scope chain - a scope for each statement). This does cause some
problems for GDB and possibly other DWARF consumers.

llvm-svn: 225000
This commit is contained in:
David Blaikie 2014-12-30 19:39:33 +00:00
parent aa185bfc4b
commit 84fe79cfc3
18 changed files with 124 additions and 195 deletions

View File

@ -874,7 +874,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// locations of subexpressions in the initialization. // locations of subexpressions in the initialization.
EmitExprAsInit(&l2r, &blockFieldPseudoVar, EmitExprAsInit(&l2r, &blockFieldPseudoVar,
MakeAddrLValue(blockField, type, align), MakeAddrLValue(blockField, type, align),
/*captured by init*/ false, SourceLocation()); /*captured by init*/ false);
} }
// Activate the cleanup if layout pushed one. // Activate the cleanup if layout pushed one.
@ -1175,7 +1175,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
Alloca->setAlignment(Align); Alloca->setAlignment(Align);
// Set the DebugLocation to empty, so the store is recognized as a // Set the DebugLocation to empty, so the store is recognized as a
// frame setup instruction by llvm::DwarfDebug::beginFunction(). // frame setup instruction by llvm::DwarfDebug::beginFunction().
NoLocation NL(*this, Builder); ApplyDebugLocation NL(*this);
Builder.CreateAlignedStore(BlockPointer, Alloca, Align); Builder.CreateAlignedStore(BlockPointer, Alloca, Align);
BlockPointerDbgLoc = Alloca; BlockPointerDbgLoc = Alloca;
} }
@ -1326,9 +1326,9 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
false, false,
false); false);
// Create a scope with an artificial location for the body of this function. // Create a scope with an artificial location for the body of this function.
ArtificialLocation AL(*this, Builder); ApplyDebugLocation NL(*this);
StartFunction(FD, C.VoidTy, Fn, FI, args); StartFunction(FD, C.VoidTy, Fn, FI, args);
AL.Emit(); ArtificialLocation AL(*this);
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@ -1497,9 +1497,9 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
nullptr, SC_Static, nullptr, SC_Static,
false, false); false, false);
// Create a scope with an artificial location for the body of this function. // Create a scope with an artificial location for the body of this function.
ArtificialLocation AL(*this, Builder); ApplyDebugLocation NL(*this);
StartFunction(FD, C.VoidTy, Fn, FI, args); StartFunction(FD, C.VoidTy, Fn, FI, args);
AL.Emit(); ArtificialLocation AL(*this);
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();

View File

@ -544,6 +544,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
CXXCtorInitializer *MemberInit, CXXCtorInitializer *MemberInit,
const CXXConstructorDecl *Constructor, const CXXConstructorDecl *Constructor,
FunctionArgList &Args) { FunctionArgList &Args) {
ApplyDebugLocation Loc(CGF, MemberInit->getMemberLocation());
assert(MemberInit->isAnyMemberInitializer() && assert(MemberInit->isAnyMemberInitializer() &&
"Must have member initializer!"); "Must have member initializer!");
assert(MemberInit->getInit() && "Must have initializer!"); assert(MemberInit->getInit() && "Must have initializer!");
@ -597,26 +598,25 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
ArrayRef<VarDecl *> ArrayIndexes; ArrayRef<VarDecl *> ArrayIndexes;
if (MemberInit->getNumArrayIndices()) if (MemberInit->getNumArrayIndices())
ArrayIndexes = MemberInit->getArrayIndexes(); ArrayIndexes = MemberInit->getArrayIndexes();
CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes, ApplyDebugLocation DL(CGF, MemberInit->getMemberLocation());
MemberInit->getMemberLocation()); CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes);
} }
void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS, void CodeGenFunction::EmitInitializerForField(
Expr *Init, FieldDecl *Field, LValue LHS, Expr *Init,
ArrayRef<VarDecl *> ArrayIndexes, ArrayRef<VarDecl *> ArrayIndexes) {
SourceLocation DbgLoc) {
QualType FieldType = Field->getType(); QualType FieldType = Field->getType();
switch (getEvaluationKind(FieldType)) { switch (getEvaluationKind(FieldType)) {
case TEK_Scalar: case TEK_Scalar:
if (LHS.isSimple()) { if (LHS.isSimple()) {
EmitExprAsInit(Init, Field, LHS, false, DbgLoc); EmitExprAsInit(Init, Field, LHS, false);
} else { } else {
RValue RHS = RValue::get(EmitScalarExpr(Init)); RValue RHS = RValue::get(EmitScalarExpr(Init));
EmitStoreThroughLValue(RHS, LHS); EmitStoreThroughLValue(RHS, LHS);
} }
break; break;
case TEK_Complex: case TEK_Complex:
EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true, DbgLoc); EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
break; break;
case TEK_Aggregate: { case TEK_Aggregate: {
llvm::Value *ArrayIndexVar = nullptr; llvm::Value *ArrayIndexVar = nullptr;
@ -783,8 +783,6 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// delegation optimization. // delegation optimization.
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) && if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
CGM.getTarget().getCXXABI().hasConstructorVariants()) { CGM.getTarget().getCXXABI().hasConstructorVariants()) {
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, Ctor->getLocEnd());
EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args, Ctor->getLocEnd()); EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args, Ctor->getLocEnd());
return; return;
} }

View File

@ -861,10 +861,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// Emit the EH cleanup if required. // Emit the EH cleanup if required.
if (RequiresEHCleanup) { if (RequiresEHCleanup) {
CGDebugInfo *DI = getDebugInfo(); ApplyDebugLocation AutoRestoreLocation(*this, CurEHLocation);
SaveAndRestoreLocation AutoRestoreLocation(*this, Builder);
if (DI)
DI->EmitLocation(Builder, CurEHLocation);
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();

View File

@ -52,54 +52,38 @@ CGDebugInfo::~CGDebugInfo() {
"Region stack mismatch, stack not empty!"); "Region stack mismatch, stack not empty!");
} }
SaveAndRestoreLocation::SaveAndRestoreLocation(CodeGenFunction &CGF, ArtificialLocation::ArtificialLocation(CodeGenFunction &CGF)
CGBuilderTy &B) : ApplyDebugLocation(CGF) {
: DI(CGF.getDebugInfo()), Builder(B) { if (auto *DI = CGF.getDebugInfo()) {
if (DI) {
SavedLoc = DI->getLocation();
DI->CurLoc = SourceLocation();
}
}
SaveAndRestoreLocation::~SaveAndRestoreLocation() {
if (DI)
DI->EmitLocation(Builder, SavedLoc);
}
NoLocation::NoLocation(CodeGenFunction &CGF, CGBuilderTy &B)
: SaveAndRestoreLocation(CGF, B) {
if (DI)
Builder.SetCurrentDebugLocation(llvm::DebugLoc());
}
NoLocation::~NoLocation() {
if (DI)
assert(Builder.getCurrentDebugLocation().isUnknown());
}
ArtificialLocation::ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B)
: SaveAndRestoreLocation(CGF, B) {
if (DI)
Builder.SetCurrentDebugLocation(llvm::DebugLoc());
}
void ArtificialLocation::Emit() {
if (DI) {
// Sync the Builder.
DI->EmitLocation(Builder, SavedLoc);
DI->CurLoc = SourceLocation();
// Construct a location that has a valid scope, but no line info. // Construct a location that has a valid scope, but no line info.
assert(!DI->LexicalBlockStack.empty()); assert(!DI->LexicalBlockStack.empty());
llvm::DIDescriptor Scope(DI->LexicalBlockStack.back()); llvm::DIDescriptor Scope(DI->LexicalBlockStack.back());
Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, Scope)); CGF.Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, Scope));
} }
} }
ArtificialLocation::~ArtificialLocation() { ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
if (DI) SourceLocation TemporaryLocation,
assert(Builder.getCurrentDebugLocation().getLine() == 0); bool ForceColumnInfo)
: CGF(CGF) {
if (auto *DI = CGF.getDebugInfo()) {
OriginalLocation = CGF.Builder.getCurrentDebugLocation();
if (TemporaryLocation.isInvalid())
CGF.Builder.SetCurrentDebugLocation(llvm::DebugLoc());
else
DI->EmitLocation(CGF.Builder, TemporaryLocation, ForceColumnInfo);
}
} }
ApplyDebugLocation::~ApplyDebugLocation() {
// Query CGF so the location isn't overwritten when location updates are
// temporarily disabled (for C++ default function arguments)
if (CGF.getDebugInfo())
CGF.Builder.SetCurrentDebugLocation(OriginalLocation);
}
/// ArtificialLocation - An RAII object that temporarily switches to
/// an artificial debug location that has a valid scope, but no line
void CGDebugInfo::setLocation(SourceLocation Loc) { void CGDebugInfo::setLocation(SourceLocation Loc) {
// If the new location isn't valid return. // If the new location isn't valid return.
if (Loc.isInvalid()) if (Loc.isInvalid())

View File

@ -448,27 +448,16 @@ private:
} }
}; };
/// SaveAndRestoreLocation - An RAII object saves the current location class ApplyDebugLocation {
/// and automatically restores it to the original value.
class SaveAndRestoreLocation {
protected: protected:
SourceLocation SavedLoc; llvm::DebugLoc OriginalLocation;
CGDebugInfo *DI; CodeGenFunction &CGF;
CGBuilderTy &Builder;
public:
SaveAndRestoreLocation(CodeGenFunction &CGF, CGBuilderTy &B);
/// Autorestore everything back to normal.
~SaveAndRestoreLocation();
};
/// NoLocation - An RAII object that temporarily disables debug
/// locations. This is useful for emitting instructions that should be
/// counted towards the function prologue.
class NoLocation : public SaveAndRestoreLocation {
public: public:
NoLocation(CodeGenFunction &CGF, CGBuilderTy &B); ApplyDebugLocation(CodeGenFunction &CGF,
/// Autorestore everything back to normal. SourceLocation TemporaryLocation = SourceLocation(),
~NoLocation(); bool ForceColumnInfo = false);
~ApplyDebugLocation();
}; };
/// ArtificialLocation - An RAII object that temporarily switches to /// ArtificialLocation - An RAII object that temporarily switches to
@ -482,16 +471,9 @@ public:
/// This is necessary because passing an empty SourceLocation to /// This is necessary because passing an empty SourceLocation to
/// CGDebugInfo::setLocation() will result in the last valid location /// CGDebugInfo::setLocation() will result in the last valid location
/// being reused. /// being reused.
class ArtificialLocation : public SaveAndRestoreLocation { class ArtificialLocation : public ApplyDebugLocation {
public: public:
ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B); ArtificialLocation(CodeGenFunction &CGF);
/// Set the current location to line 0, but within the current scope
/// (= the top of the LexicalBlockStack).
void Emit();
/// Autorestore everything back to normal.
~ArtificialLocation();
}; };

View File

@ -597,14 +597,13 @@ static void drillIntoBlockVariable(CodeGenFunction &CGF,
} }
void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit, LValue lvalue, bool capturedByInit) {
SourceLocation DbgLoc) {
Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime(); Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
if (!lifetime) { if (!lifetime) {
llvm::Value *value = EmitScalarExpr(init); llvm::Value *value = EmitScalarExpr(init);
if (capturedByInit) if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(RValue::get(value), lvalue, true, DbgLoc); EmitStoreThroughLValue(RValue::get(value), lvalue, true);
return; return;
} }
@ -1088,6 +1087,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
if (emission.wasEmittedAsGlobal()) return; if (emission.wasEmittedAsGlobal()) return;
const VarDecl &D = *emission.Variable; const VarDecl &D = *emission.Variable;
ApplyDebugLocation DL(*this, D.getLocation());
QualType type = D.getType(); QualType type = D.getType();
// If this local has an initializer, emit it now. // If this local has an initializer, emit it now.
@ -1126,7 +1126,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
if (!constant) { if (!constant) {
LValue lv = MakeAddrLValue(Loc, type, alignment); LValue lv = MakeAddrLValue(Loc, type, alignment);
lv.setNonGC(true); lv.setNonGC(true);
return EmitExprAsInit(Init, &D, lv, capturedByInit, D.getLocation()); return EmitExprAsInit(Init, &D, lv, capturedByInit);
} }
if (!emission.IsConstantAggregate) { if (!emission.IsConstantAggregate) {
@ -1192,26 +1192,25 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
/// \param capturedByInit true if the variable is a __block variable /// \param capturedByInit true if the variable is a __block variable
/// whose address is potentially changed by the initializer /// whose address is potentially changed by the initializer
void CodeGenFunction::EmitExprAsInit(const Expr *init, const ValueDecl *D, void CodeGenFunction::EmitExprAsInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit, LValue lvalue, bool capturedByInit) {
SourceLocation DbgLoc) {
QualType type = D->getType(); QualType type = D->getType();
if (type->isReferenceType()) { if (type->isReferenceType()) {
RValue rvalue = EmitReferenceBindingToExpr(init); RValue rvalue = EmitReferenceBindingToExpr(init);
if (capturedByInit) if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(rvalue, lvalue, true, DbgLoc); EmitStoreThroughLValue(rvalue, lvalue, true);
return; return;
} }
switch (getEvaluationKind(type)) { switch (getEvaluationKind(type)) {
case TEK_Scalar: case TEK_Scalar:
EmitScalarInit(init, D, lvalue, capturedByInit, DbgLoc); EmitScalarInit(init, D, lvalue, capturedByInit);
return; return;
case TEK_Complex: { case TEK_Complex: {
ComplexPairTy complex = EmitComplexExpr(init); ComplexPairTy complex = EmitComplexExpr(init);
if (capturedByInit) if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreOfComplex(complex, lvalue, /*init*/ true, DbgLoc); EmitStoreOfComplex(complex, lvalue, /*init*/ true);
return; return;
} }
case TEK_Aggregate: case TEK_Aggregate:

View File

@ -474,11 +474,11 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
ArrayRef<llvm::Function *> Decls, ArrayRef<llvm::Function *> Decls,
llvm::GlobalVariable *Guard) { llvm::GlobalVariable *Guard) {
{ {
ArtificialLocation AL(*this, Builder); ApplyDebugLocation NL(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(), FunctionArgList()); getTypes().arrangeNullaryFunction(), FunctionArgList());
// Emit an artificial location for this function. // Emit an artificial location for this function.
AL.Emit(); ArtificialLocation AL(*this);
llvm::BasicBlock *ExitBlock = nullptr; llvm::BasicBlock *ExitBlock = nullptr;
if (Guard) { if (Guard) {
@ -525,11 +525,11 @@ void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> > const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) { &DtorsAndObjects) {
{ {
ArtificialLocation AL(*this, Builder); ApplyDebugLocation NL(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(), FunctionArgList()); getTypes().arrangeNullaryFunction(), FunctionArgList());
// Emit an artificial location for this function. // Emit an artificial location for this function.
AL.Emit(); ArtificialLocation AL(*this);
// Emit the dtors, in reverse order from construction. // Emit the dtors, in reverse order from construction.
for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) { for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {

View File

@ -734,9 +734,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Save the current IR generation state. // Save the current IR generation state.
CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP(); CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
SaveAndRestoreLocation AutoRestoreLocation(*this, Builder); ApplyDebugLocation AutoRestoreLocation(*this, CurEHLocation);
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, CurEHLocation);
const EHPersonality &personality = EHPersonality::get(CGM); const EHPersonality &personality = EHPersonality::get(CGM);

View File

@ -1438,11 +1438,7 @@ RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) {
/// lvalue, where both are guaranteed to the have the same type, and that type /// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'. /// is 'Ty'.
void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
bool isInit, bool isInit) {
SourceLocation DbgLoc) {
if (auto *DI = getDebugInfo())
DI->EmitLocation(Builder, DbgLoc);
if (!Dst.isSimple()) { if (!Dst.isSimple()) {
if (Dst.isVectorElt()) { if (Dst.isVectorElt()) {
// Read/modify/write the vector, inserting the new element. // Read/modify/write the vector, inserting the new element.
@ -2408,9 +2404,6 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// The element count here is the total number of non-VLA elements. // The element count here is the total number of non-VLA elements.
llvm::Value *numElements = getVLASize(vla).first; llvm::Value *numElements = getVLASize(vla).first;
if (auto *DI = getDebugInfo())
DI->EmitLocation(Builder, E->getLocStart());
// Effectively, the multiply by the VLA size is part of the GEP. // Effectively, the multiply by the VLA size is part of the GEP.
// GEP indexes are signed, and scaling an index isn't permitted to // GEP indexes are signed, and scaling an index isn't permitted to
// signed-overflow, so we use the same semantics for our explicit // signed-overflow, so we use the same semantics for our explicit
@ -2456,9 +2449,6 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// Propagate the alignment from the array itself to the result. // Propagate the alignment from the array itself to the result.
ArrayAlignment = ArrayLV.getAlignment(); ArrayAlignment = ArrayLV.getAlignment();
if (auto *DI = getDebugInfo())
DI->EmitLocation(Builder, E->getLocStart());
if (getLangOpts().isSignedOverflowDefined()) if (getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx"); Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx");
else else
@ -2466,8 +2456,6 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
} else { } else {
// The base must be a pointer, which is not an aggregate. Emit it. // The base must be a pointer, which is not an aggregate. Emit it.
llvm::Value *Base = EmitScalarExpr(E->getBase()); llvm::Value *Base = EmitScalarExpr(E->getBase());
if (auto *DI = getDebugInfo())
DI->EmitLocation(Builder, E->getLocStart());
if (getLangOpts().isSignedOverflowDefined()) if (getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(Base, Idx, "arrayidx"); Address = Builder.CreateGEP(Base, Idx, "arrayidx");
else else
@ -3024,18 +3012,15 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) { ReturnValueSlot ReturnValue) {
if (CGDebugInfo *DI = getDebugInfo()) { // Force column info to be generated so we can differentiate
SourceLocation Loc = E->getLocStart(); // multiple call sites on the same line in the debug info.
// Force column info to be generated so we can differentiate // FIXME: This is insufficient. Two calls coming from the same macro
// multiple call sites on the same line in the debug info. // expansion will still get the same line/column and break debug info. It's
// FIXME: This is insufficient. Two calls coming from the same macro // possible that LLVM can be fixed to not rely on this uniqueness, at which
// expansion will still get the same line/column and break debug info. It's // point this workaround can be removed.
// possible that LLVM can be fixed to not rely on this uniqueness, at which ApplyDebugLocation DL(*this, E->getLocStart(),
// point this workaround can be removed. E->getDirectCallee() &&
const FunctionDecl* Callee = E->getDirectCallee(); E->getDirectCallee()->isInlineSpecified());
bool ForceColumnInfo = Callee && Callee->isInlineSpecified();
DI->EmitLocation(Builder, Loc, ForceColumnInfo);
}
// Builtins never have block type. // Builtins never have block type.
if (E->getCallee()->getType()->isBlockPointerType()) if (E->getCallee()->getType()->isBlockPointerType())
@ -3151,8 +3136,6 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
RValue RV = EmitAnyExpr(E->getRHS()); RValue RV = EmitAnyExpr(E->getRHS());
LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, E->getLocStart());
EmitStoreThroughLValue(RV, LV); EmitStoreThroughLValue(RV, LV);
return LV; return LV;
} }

View File

@ -187,8 +187,6 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0; unsigned ArgsToSkip = isa<CXXOperatorCallExpr>(CE) ? 1 : 0;
llvm::Value *RHS = llvm::Value *RHS =
EmitLValue(*(CE->arg_begin() + ArgsToSkip)).getAddress(); EmitLValue(*(CE->arg_begin() + ArgsToSkip)).getAddress();
if (auto *DI = getDebugInfo())
DI->EmitLocation(Builder, CE->getLocStart());
EmitAggregateAssign(This, RHS, CE->getType()); EmitAggregateAssign(This, RHS, CE->getType());
return RValue::get(This); return RValue::get(This);
} }
@ -754,15 +752,13 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
} }
static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init, static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
QualType AllocType, llvm::Value *NewPtr, QualType AllocType, llvm::Value *NewPtr) {
SourceLocation DbgLoc = SourceLocation()) {
// FIXME: Refactor with EmitExprAsInit. // FIXME: Refactor with EmitExprAsInit.
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType); CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
switch (CGF.getEvaluationKind(AllocType)) { switch (CGF.getEvaluationKind(AllocType)) {
case TEK_Scalar: case TEK_Scalar:
CGF.EmitScalarInit(Init, nullptr, CGF.EmitScalarInit(Init, nullptr,
CGF.MakeAddrLValue(NewPtr, AllocType, Alignment), false, CGF.MakeAddrLValue(NewPtr, AllocType, Alignment), false);
DbgLoc);
return; return;
case TEK_Complex: case TEK_Complex:
CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType, CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType,
@ -1020,12 +1016,12 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr, llvm::Value *NewPtr,
llvm::Value *NumElements, llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) { llvm::Value *AllocSizeWithoutCookie) {
ApplyDebugLocation DL(CGF, E->getStartLoc());
if (E->isArray()) if (E->isArray())
CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements, CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements,
AllocSizeWithoutCookie); AllocSizeWithoutCookie);
else if (const Expr *Init = E->getInitializer()) else if (const Expr *Init = E->getInitializer())
StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr, StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr);
E->getStartLoc());
} }
/// Emit a call to an operator new or operator delete function, as implicitly /// Emit a call to an operator new or operator delete function, as implicitly
@ -1269,9 +1265,6 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
E->placement_arg_end(), /* CalleeDecl */ nullptr, E->placement_arg_end(), /* CalleeDecl */ nullptr,
/*ParamsToSkip*/ 1); /*ParamsToSkip*/ 1);
if (auto *DI = getDebugInfo())
DI->EmitLocation(Builder, E->getLocStart());
// Emit the allocation call. If the allocator is a global placement // Emit the allocation call. If the allocator is a global placement
// operator, just "inline" it directly. // operator, just "inline" it directly.
RValue RV; RValue RV;

View File

@ -81,8 +81,7 @@ public:
/// EmitStoreOfComplex - Store the specified real/imag parts into the /// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer. /// specified value pointer.
void EmitStoreOfComplex(ComplexPairTy Val, LValue LV, bool isInit, void EmitStoreOfComplex(ComplexPairTy Val, LValue LV, bool isInit);
SourceLocation DbgLoc);
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType, ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
@ -335,11 +334,7 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue,
/// EmitStoreOfComplex - Store the specified real/imag parts into the /// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer. /// specified value pointer.
void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue, void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue,
bool isInit, bool isInit) {
SourceLocation DbgLoc) {
if (auto *DI = CGF.getDebugInfo())
DI->EmitLocation(CGF.Builder, DbgLoc);
if (lvalue.getType()->isAtomicType()) if (lvalue.getType()->isAtomicType())
return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit); return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
@ -869,7 +864,7 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
// Truncate the result and store it into the LHS lvalue. // Truncate the result and store it into the LHS lvalue.
if (LHSTy->isAnyComplexType()) { if (LHSTy->isAnyComplexType()) {
ComplexPairTy ResVal = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); ComplexPairTy ResVal = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
EmitStoreOfComplex(ResVal, LHS, /*isInit*/ false, E->getLocStart()); EmitStoreOfComplex(ResVal, LHS, /*isInit*/ false);
Val = RValue::getComplex(ResVal); Val = RValue::getComplex(ResVal);
} else { } else {
llvm::Value *ResVal = llvm::Value *ResVal =
@ -914,7 +909,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
LValue LHS = CGF.EmitLValue(E->getLHS()); LValue LHS = CGF.EmitLValue(E->getLHS());
// Store the result value into the LHS lvalue. // Store the result value into the LHS lvalue.
EmitStoreOfComplex(Val, LHS, /*isInit*/ false, E->getLocStart()); EmitStoreOfComplex(Val, LHS, /*isInit*/ false);
return LHS; return LHS;
} }
@ -1042,19 +1037,18 @@ ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
} }
void CodeGenFunction::EmitComplexExprIntoLValue(const Expr *E, LValue dest, void CodeGenFunction::EmitComplexExprIntoLValue(const Expr *E, LValue dest,
bool isInit, bool isInit) {
SourceLocation DbgLoc) {
assert(E && getComplexType(E->getType()) && assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit"); "Invalid complex expression to emit");
ComplexExprEmitter Emitter(*this); ComplexExprEmitter Emitter(*this);
ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E)); ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
Emitter.EmitStoreOfComplex(Val, dest, isInit, DbgLoc); Emitter.EmitStoreOfComplex(Val, dest, isInit);
} }
/// EmitStoreOfComplex - Store a complex number into the specified l-value. /// EmitStoreOfComplex - Store a complex number into the specified l-value.
void CodeGenFunction::EmitStoreOfComplex(ComplexPairTy V, LValue dest, void CodeGenFunction::EmitStoreOfComplex(ComplexPairTy V, LValue dest,
bool isInit, SourceLocation DbgLoc) { bool isInit) {
ComplexExprEmitter(*this).EmitStoreOfComplex(V, dest, isInit, DbgLoc); ComplexExprEmitter(*this).EmitStoreOfComplex(V, dest, isInit);
} }
/// EmitLoadOfComplex - Load a complex number from the specified address. /// EmitLoadOfComplex - Load a complex number from the specified address.

View File

@ -196,6 +196,7 @@ public:
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
Value *Visit(Expr *E) { Value *Visit(Expr *E) {
ApplyDebugLocation DL(CGF, E->getLocStart());
return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E); return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
} }
@ -3042,7 +3043,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// Emit an unconditional branch from this block to ContBlock. // Emit an unconditional branch from this block to ContBlock.
{ {
// There is no need to emit line number for unconditional branch. // There is no need to emit line number for unconditional branch.
SuppressDebugLocation S(Builder); ApplyDebugLocation DL(CGF);
CGF.EmitBlock(ContBlock); CGF.EmitBlock(ContBlock);
} }
// Insert an entry into the phi node for the edge with the value of RHSCond. // Insert an entry into the phi node for the edge with the value of RHSCond.

View File

@ -565,7 +565,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
if (const Stmt *Else = S.getElse()) { if (const Stmt *Else = S.getElse()) {
{ {
// There is no need to emit line number for unconditional branch. // There is no need to emit line number for unconditional branch.
SuppressDebugLocation S(Builder); ApplyDebugLocation DL(*this);
EmitBlock(ElseBlock); EmitBlock(ElseBlock);
} }
{ {
@ -574,7 +574,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
} }
{ {
// There is no need to emit line number for unconditional branch. // There is no need to emit line number for unconditional branch.
SuppressDebugLocation S(Builder); ApplyDebugLocation DL(*this);
EmitBranch(ContBlock); EmitBranch(ContBlock);
} }
} }

View File

@ -86,13 +86,13 @@ static void EmitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond,
// Emit the 'else' code if present. // Emit the 'else' code if present.
{ {
// There is no need to emit line number for unconditional branch. // There is no need to emit line number for unconditional branch.
SuppressDebugLocation SDL(CGF.Builder); ApplyDebugLocation DL(CGF);
CGF.EmitBlock(ElseBlock); CGF.EmitBlock(ElseBlock);
} }
CodeGen(/*ThenBlock*/ false); CodeGen(/*ThenBlock*/ false);
{ {
// There is no need to emit line number for unconditional branch. // There is no need to emit line number for unconditional branch.
SuppressDebugLocation SDL(CGF.Builder); ApplyDebugLocation DL(CGF);
CGF.EmitBranch(ContBlock); CGF.EmitBranch(ContBlock);
} }
// Emit the continuation block for code after the if. // Emit the continuation block for code after the if.

View File

@ -93,19 +93,6 @@ enum TypeEvaluationKind {
TEK_Aggregate TEK_Aggregate
}; };
class SuppressDebugLocation {
llvm::DebugLoc CurLoc;
llvm::IRBuilderBase &Builder;
public:
SuppressDebugLocation(llvm::IRBuilderBase &Builder)
: CurLoc(Builder.getCurrentDebugLocation()), Builder(Builder) {
Builder.SetCurrentDebugLocation(llvm::DebugLoc());
}
~SuppressDebugLocation() {
Builder.SetCurrentDebugLocation(CurLoc);
}
};
/// CodeGenFunction - This class organizes the per-function state that is used /// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code. /// while generating LLVM code.
class CodeGenFunction : public CodeGenTypeCache { class CodeGenFunction : public CodeGenTypeCache {
@ -1300,8 +1287,7 @@ public:
FunctionArgList &Args); FunctionArgList &Args);
void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init, void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init,
ArrayRef<VarDecl *> ArrayIndexes, ArrayRef<VarDecl *> ArrayIndexes);
SourceLocation DbgLoc = SourceLocation());
/// InitializeVTablePointer - Initialize the vtable pointer of the given /// InitializeVTablePointer - Initialize the vtable pointer of the given
/// subobject. /// subobject.
@ -1546,7 +1532,7 @@ public:
/// EmitExprAsInit - Emits the code necessary to initialize a /// EmitExprAsInit - Emits the code necessary to initialize a
/// location in memory with the given initializer. /// location in memory with the given initializer.
void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue, void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue,
bool capturedByInit, SourceLocation DbgLoc); bool capturedByInit);
/// hasVolatileMember - returns true if aggregate type has a volatile /// hasVolatileMember - returns true if aggregate type has a volatile
/// member. /// member.
@ -1833,8 +1819,7 @@ public:
void EmitVarDecl(const VarDecl &D); void EmitVarDecl(const VarDecl &D);
void EmitScalarInit(const Expr *init, const ValueDecl *D, LValue lvalue, void EmitScalarInit(const Expr *init, const ValueDecl *D, LValue lvalue,
bool capturedByInit, bool capturedByInit);
SourceLocation DbgLoc = SourceLocation());
void EmitScalarInit(llvm::Value *init, LValue lvalue); void EmitScalarInit(llvm::Value *init, LValue lvalue);
typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D, typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
@ -2164,8 +2149,7 @@ public:
/// EmitStoreThroughLValue - Store the specified rvalue into the specified /// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type /// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'. /// is 'Ty'.
void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit = false, void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit = false);
SourceLocation DbgLoc = SourceLocation());
void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst); void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst); void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst);
@ -2537,12 +2521,10 @@ public:
/// EmitComplexExprIntoLValue - Emit the given expression of complex /// EmitComplexExprIntoLValue - Emit the given expression of complex
/// type and place its result into the specified l-value. /// type and place its result into the specified l-value.
void EmitComplexExprIntoLValue(const Expr *E, LValue dest, bool isInit, void EmitComplexExprIntoLValue(const Expr *E, LValue dest, bool isInit);
SourceLocation DbgLoc = SourceLocation());
/// EmitStoreOfComplex - Store a complex number into the specified l-value. /// EmitStoreOfComplex - Store a complex number into the specified l-value.
void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit, void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit);
SourceLocation DbgLoc = SourceLocation());
/// EmitLoadOfComplex - Load a complex number from the specified l-value. /// EmitLoadOfComplex - Load a complex number from the specified l-value.
ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc); ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc);

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -g -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -triple %itanium_abi_triple -g -mllvm -no-discriminators -emit-llvm %s -o - | FileCheck %s
struct C { struct C {
~C(); ~C();
@ -8,9 +8,7 @@ extern bool b;
// CHECK: call {{.*}}, !dbg [[DTOR_CALL2_LOC:![0-9]*]] // CHECK: call {{.*}}, !dbg [[DTOR_CALL2_LOC:![0-9]*]]
// CHECK: [[FUN1:.*]] = {{.*}}; [ DW_TAG_subprogram ] {{.*}} [def] [fun1] // CHECK: [[FUN1:.*]] = {{.*}}; [ DW_TAG_subprogram ] {{.*}} [def] [fun1]
// CHECK: [[FUN2:.*]] = {{.*}}; [ DW_TAG_subprogram ] {{.*}} [def] [fun2] // CHECK: [[FUN2:.*]] = {{.*}}; [ DW_TAG_subprogram ] {{.*}} [def] [fun2]
// CHECK: [[DTOR_CALL1_LOC]] = !{i32 [[@LINE+2]], i32 0, [[FUN1_BLOCK:.*]], null} // CHECK: [[DTOR_CALL1_LOC]] = !{i32 [[@LINE+1]], i32 0, [[FUN1]], null}
// CHECK: [[FUN1_BLOCK]] = !{!"0xb{{[^,]*}}", {{[^,]*}}, [[FUN1]]}
void fun1() { b && (C(), 1); } void fun1() { b && (C(), 1); }
// CHECK: [[DTOR_CALL2_LOC]] = !{i32 [[@LINE+2]], i32 0, [[FUN2_BLOCK1:.*]], null} // CHECK: [[DTOR_CALL2_LOC]] = !{i32 [[@LINE+1]], i32 0, [[FUN2]], null}
// CHECK: [[FUN2_BLOCK1]] = !{!"0xb{{[^,]*}}", {{[^,]*}}, [[FUN2]]}
bool fun2() { return (C(), b) && 0; } bool fun2() { return (C(), b) && 0; }

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -g -std=c++11 -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -g -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple i686-linux-gnu -g -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
int &src(); int &src();
int *sink(); int *sink();
@ -110,6 +111,23 @@ void f10() {
new (void_src()) int(src())); new (void_src()) int(src()));
} }
// CHECK-LABEL: define
__complex double f11() {
__complex double f;
// CHECK: store {{.*}} !dbg [[DBG_F11:!.*]]
#line 1200
return f;
}
// CHECK-LABEL: define
void f12() {
int f12_1();
void f12_2(int = f12_1());
// CHECK: call i32 {{.*}} !dbg [[DBG_F12:!.*]]
#line 1300
f12_2();
}
// CHECK: [[DBG_F1]] = !{i32 100, // CHECK: [[DBG_F1]] = !{i32 100,
// CHECK: [[DBG_FOO_VALUE]] = !{i32 200, // CHECK: [[DBG_FOO_VALUE]] = !{i32 200,
// CHECK: [[DBG_FOO_REF]] = !{i32 202, // CHECK: [[DBG_FOO_REF]] = !{i32 202,
@ -124,3 +142,5 @@ void f10() {
// CHECK: [[DBG_F9]] = !{i32 1000, // CHECK: [[DBG_F9]] = !{i32 1000,
// CHECK: [[DBG_F10_ICMP]] = !{i32 1100, // CHECK: [[DBG_F10_ICMP]] = !{i32 1100,
// CHECK: [[DBG_F10_STORE]] = !{i32 1100, // CHECK: [[DBG_F10_STORE]] = !{i32 1100,
// CHECK: [[DBG_F11]] = !{i32 1200,
// CHECK: [[DBG_F12]] = !{i32 1300,

View File

@ -36,12 +36,12 @@ void func() {
// CHECK: = !{!"0x100\00{{.*}}", [[FOR:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [i] [line [[@LINE+2]]] // CHECK: = !{!"0x100\00{{.*}}", [[FOR:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [i] [line [[@LINE+2]]]
// CHECK: [[FOR]] = !{!"0xb\00[[@LINE+1]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ] // CHECK: [[FOR]] = !{!"0xb\00[[@LINE+1]]\00{{.*}}", !{{.*}}} ; [ DW_TAG_lexical_block ]
for (int i = 0; i != 10; ++i) { for (int i = 0; i != 10; ++i) {
// FIXME: Do not include scopes that have only other scopes (and no variables // FIXME: Do not include scopes that have only other scopes (and no variables
// or using declarations) as direct children, they just waste // or using declarations) as direct children, they just waste
// space/relocations/etc. // space/relocations/etc.
// CHECK: = !{!"0x100\00{{.*}}", [[FOR_COMPOUND:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [b] [line [[@LINE+3]]] // CHECK: [[FOR_LOOP_INCLUDING_COND:!.*]] = !{!"0xb\00[[@LINE-4]]\00{{.*}}", !{{[0-9]+}}, [[FOR]]} ; [ DW_TAG_lexical_block ]
// CHECK: [[FOR_COMPOUND]] = !{!"0xb\00[[@LINE-5]]\00{{.*}}", !{{[0-9]+}}, [[FOR_BODY:![0-9]+]]} ; [ DW_TAG_lexical_block ] // CHECK: = !{!"0x100\00{{.*}}", [[FOR_COMPOUND:![0-9]*]], {{.*}} ; [ DW_TAG_auto_variable ] [b] [line [[@LINE+2]]]
// CHECK: [[FOR_BODY]] = !{!"0xb\00[[@LINE-6]]\00{{.*}}", !{{[0-9]+}}, [[FOR]]} ; [ DW_TAG_lexical_block ] // CHECK: [[FOR_COMPOUND]] = !{!"0xb\00[[@LINE-6]]\00{{.*}}", !{{[0-9]+}}, [[FOR_LOOP_INCLUDING_COND]]} ; [ DW_TAG_lexical_block ]
bool b = i % 2; bool b = i % 2;
} }