[clang] [clang][bytecode] Add source info to jump ops (PR #188003)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 23 02:29:07 PDT 2026
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/188003
The attached test case otherwise results in a function with one jump op but no source info at all.
>From 5f522910159ad6639761032286e49fc0471c0f7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 23 Mar 2026 10:25:51 +0100
Subject: [PATCH] Jumps
---
clang/lib/AST/ByteCode/ByteCodeEmitter.cpp | 12 ++---
clang/lib/AST/ByteCode/ByteCodeEmitter.h | 6 +--
clang/lib/AST/ByteCode/Compiler.cpp | 56 ++++++++++-----------
clang/lib/AST/ByteCode/Compiler.h | 2 +-
clang/lib/AST/ByteCode/EvalEmitter.cpp | 12 +++--
clang/lib/AST/ByteCode/EvalEmitter.h | 6 +--
clang/test/AST/ByteCode/constexpr-steps.cpp | 7 +++
7 files changed, 56 insertions(+), 45 deletions(-)
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
index c08ccf69aef85..393b8481fecd1 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
@@ -221,16 +221,16 @@ bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &...Args, SourceInfo SI) {
return Success;
}
-bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
- return emitJt(getOffset(Label), SourceInfo{});
+bool ByteCodeEmitter::jumpTrue(const LabelTy &Label, SourceInfo SI) {
+ return emitJt(getOffset(Label), SI);
}
-bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
- return emitJf(getOffset(Label), SourceInfo{});
+bool ByteCodeEmitter::jumpFalse(const LabelTy &Label, SourceInfo SI) {
+ return emitJf(getOffset(Label), SI);
}
-bool ByteCodeEmitter::jump(const LabelTy &Label) {
- return emitJmp(getOffset(Label), SourceInfo{});
+bool ByteCodeEmitter::jump(const LabelTy &Label, SourceInfo SI) {
+ return emitJmp(getOffset(Label), SI);
}
bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index 873edeea71d96..102ce939c6717 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
@@ -52,9 +52,9 @@ class ByteCodeEmitter {
virtual bool emitBool(bool V, const Expr *E) = 0;
/// Emits jumps.
- bool jumpTrue(const LabelTy &Label);
- bool jumpFalse(const LabelTy &Label);
- bool jump(const LabelTy &Label);
+ bool jumpTrue(const LabelTy &Label, SourceInfo SI);
+ bool jumpFalse(const LabelTy &Label, SourceInfo SI);
+ bool jump(const LabelTy &Label, SourceInfo SI);
bool fallthrough(const LabelTy &Label);
/// Speculative execution.
bool speculate(const CallExpr *E, const LabelTy &EndLabel);
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index a881d77a73cbd..10f586ce145d3 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -1344,12 +1344,12 @@ bool Compiler<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
if (!this->visitBool(LHS))
return false;
- if (!this->jumpTrue(LabelTrue))
+ if (!this->jumpTrue(LabelTrue, E))
return false;
if (!this->visitBool(RHS))
return false;
- if (!this->jump(LabelEnd))
+ if (!this->jump(LabelEnd, E))
return false;
this->emitLabel(LabelTrue);
@@ -1366,12 +1366,12 @@ bool Compiler<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
if (!this->visitBool(LHS))
return false;
- if (!this->jumpFalse(LabelFalse))
+ if (!this->jumpFalse(LabelFalse, E))
return false;
if (!this->visitBool(RHS))
return false;
- if (!this->jump(LabelEnd))
+ if (!this->jump(LabelEnd, E))
return false;
this->emitLabel(LabelFalse);
@@ -2833,12 +2833,12 @@ bool Compiler<Emitter>::VisitAbstractConditionalOperator(
return false;
}
- if (!this->jumpFalse(LabelFalse))
+ if (!this->jumpFalse(LabelFalse, E))
return false;
if (!this->delegate(TrueExpr))
return false;
- if (!this->jump(LabelEnd))
+ if (!this->jump(LabelEnd, E))
return false;
this->emitLabel(LabelFalse);
if (!this->delegate(FalseExpr))
@@ -4028,7 +4028,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
return false;
if (!this->emitEQPtr(E))
return false;
- if (!this->jumpTrue(EndLabel))
+ if (!this->jumpTrue(EndLabel, E))
return false;
}
@@ -4049,7 +4049,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
return false;
if (!this->emitLT(SizeT, E))
return false;
- if (!this->jumpFalse(EndLabel))
+ if (!this->jumpFalse(EndLabel, E))
return false;
// Pointer to the allocated array is already on the stack.
@@ -4098,7 +4098,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
if (!this->emitIncPop(SizeT, false, E))
return false;
- if (!this->jump(StartLabel))
+ if (!this->jump(StartLabel, E))
return false;
this->fallthrough(EndLabel);
@@ -6077,11 +6077,11 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
if (const Stmt *Else = IS->getElse()) {
LabelTy LabelElse = this->getLabel();
LabelTy LabelEnd = this->getLabel();
- if (!this->jumpFalse(LabelElse))
+ if (!this->jumpFalse(LabelElse, IS))
return false;
if (!visitChildStmt(IS->getThen()))
return false;
- if (!this->jump(LabelEnd))
+ if (!this->jump(LabelEnd, IS))
return false;
this->emitLabel(LabelElse);
if (!visitChildStmt(Else))
@@ -6089,7 +6089,7 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
this->emitLabel(LabelEnd);
} else {
LabelTy LabelEnd = this->getLabel();
- if (!this->jumpFalse(LabelEnd))
+ if (!this->jumpFalse(LabelEnd, IS))
return false;
if (!visitChildStmt(IS->getThen()))
return false;
@@ -6129,7 +6129,7 @@ bool Compiler<Emitter>::visitWhileStmt(const WhileStmt *S) {
if (!this->maybeEmitDeferredVarInit(S->getConditionVariable()))
return false;
- if (!this->jumpFalse(EndLabel))
+ if (!this->jumpFalse(EndLabel, S))
return false;
if (!this->visitStmt(Body))
@@ -6139,7 +6139,7 @@ bool Compiler<Emitter>::visitWhileStmt(const WhileStmt *S) {
return false;
// } End of loop body.
- if (!this->jump(CondLabel))
+ if (!this->jump(CondLabel, S))
return false;
this->fallthrough(EndLabel);
this->emitLabel(EndLabel);
@@ -6172,7 +6172,7 @@ template <class Emitter> bool Compiler<Emitter>::visitDoStmt(const DoStmt *S) {
if (!CondScope.destroyLocals())
return false;
}
- if (!this->jumpTrue(StartLabel))
+ if (!this->jumpTrue(StartLabel, S))
return false;
this->fallthrough(EndLabel);
@@ -6210,7 +6210,7 @@ bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
if (Cond) {
if (!this->visitBool(Cond))
return false;
- if (!this->jumpFalse(EndLabel))
+ if (!this->jumpFalse(EndLabel, S))
return false;
}
if (!this->maybeEmitDeferredVarInit(S->getConditionVariable()))
@@ -6226,7 +6226,7 @@ bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
if (!CondScope.destroyLocals())
return false;
- if (!this->jump(CondLabel))
+ if (!this->jump(CondLabel, S))
return false;
// } End of loop body.
@@ -6267,7 +6267,7 @@ bool Compiler<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
this->emitLabel(CondLabel);
if (!this->visitBool(Cond))
return false;
- if (!this->jumpFalse(EndLabel))
+ if (!this->jumpFalse(EndLabel, S))
return false;
if (!this->visitDeclStmt(S->getLoopVarStmt(), /*EvaluateConditionDecl=*/true))
@@ -6284,7 +6284,7 @@ bool Compiler<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
return false;
}
- if (!this->jump(CondLabel))
+ if (!this->jump(CondLabel, S))
return false;
this->fallthrough(EndLabel);
@@ -6329,7 +6329,7 @@ bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
return false;
}
- return this->jump(*TargetLabel);
+ return this->jump(*TargetLabel, S);
}
template <class Emitter>
@@ -6366,7 +6366,7 @@ bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
return false;
}
- return this->jump(*TargetLabel);
+ return this->jump(*TargetLabel, S);
}
template <class Emitter>
@@ -6421,7 +6421,7 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
PrimType LT = this->classifyPrim(Low->getType());
if (!this->emitGE(LT, S))
return false;
- if (!this->jumpFalse(EndOfRangeCheck))
+ if (!this->jumpFalse(EndOfRangeCheck, S))
return false;
if (!this->emitGetLocal(CondT, CondVar, CS))
@@ -6431,7 +6431,7 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
PrimType HT = this->classifyPrim(High->getType());
if (!this->emitLE(HT, S))
return false;
- if (!this->jumpTrue(CaseLabels[CS]))
+ if (!this->jumpTrue(CaseLabels[CS], S))
return false;
this->emitLabel(EndOfRangeCheck);
continue;
@@ -6451,7 +6451,7 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
// Compare and jump to the case label.
if (!this->emitEQ(ValueT, S))
return false;
- if (!this->jumpTrue(CaseLabels[CS]))
+ if (!this->jumpTrue(CaseLabels[CS], S))
return false;
} else {
assert(!DefaultLabel);
@@ -6462,10 +6462,10 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
// If none of the conditions above were true, fall through to the default
// statement or jump after the switch statement.
if (DefaultLabel) {
- if (!this->jump(*DefaultLabel))
+ if (!this->jump(*DefaultLabel, S))
return false;
} else {
- if (!this->jump(EndLabel))
+ if (!this->jump(EndLabel, S))
return false;
}
@@ -7698,7 +7698,7 @@ bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
// We now have the bool value of E[0] on the stack.
LabelTy LabelTrue = this->getLabel();
- if (!this->jumpTrue(LabelTrue))
+ if (!this->jumpTrue(LabelTrue, E))
return false;
if (!this->emitArrayElemPop(ElemT, 1, E))
@@ -7712,7 +7712,7 @@ bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
}
// Leave the boolean value of E[1] on the stack.
LabelTy EndLabel = this->getLabel();
- this->jump(EndLabel);
+ this->jump(EndLabel, E);
this->emitLabel(LabelTrue);
if (!this->emitPopPtr(E))
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 717928dc1fbbd..f867fcc9fcbaa 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -597,7 +597,7 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
typename Emitter::LabelTy EndLabel = this->Ctx->getLabel();
if (!this->Ctx->emitGetLocalEnabled(Local.Offset, E))
return false;
- if (!this->Ctx->jumpFalse(EndLabel))
+ if (!this->Ctx->jumpFalse(EndLabel, E))
return false;
if (!this->Ctx->emitGetPtrLocal(Local.Offset, E))
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 1bc82b2ecab1a..3cfc1de1ff35e 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -125,25 +125,29 @@ Scope::Local EvalEmitter::createLocal(Descriptor *D) {
return {Off, D};
}
-bool EvalEmitter::jumpTrue(const LabelTy &Label) {
+bool EvalEmitter::jumpTrue(const LabelTy &Label, SourceInfo SI) {
if (isActive()) {
+ CurrentSource = SI;
if (S.Stk.pop<bool>())
ActiveLabel = Label;
}
return true;
}
-bool EvalEmitter::jumpFalse(const LabelTy &Label) {
+bool EvalEmitter::jumpFalse(const LabelTy &Label, SourceInfo SI) {
if (isActive()) {
+ CurrentSource = SI;
if (!S.Stk.pop<bool>())
ActiveLabel = Label;
}
return true;
}
-bool EvalEmitter::jump(const LabelTy &Label) {
- if (isActive())
+bool EvalEmitter::jump(const LabelTy &Label, SourceInfo SI) {
+ if (isActive()) {
+ CurrentSource = SI;
CurrentLabel = ActiveLabel = Label;
+ }
return true;
}
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h
index 3de12366a2b3d..8f6da7aef422a 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -68,9 +68,9 @@ class EvalEmitter : public SourceMapper {
virtual bool emitBool(bool V, const Expr *E) = 0;
/// Emits jumps.
- bool jumpTrue(const LabelTy &Label);
- bool jumpFalse(const LabelTy &Label);
- bool jump(const LabelTy &Label);
+ bool jumpTrue(const LabelTy &Label, SourceInfo SI);
+ bool jumpFalse(const LabelTy &Label, SourceInfo SI);
+ bool jump(const LabelTy &Label, SourceInfo SI);
bool fallthrough(const LabelTy &Label);
/// Speculative execution.
bool speculate(const CallExpr *E, const LabelTy &EndLabel);
diff --git a/clang/test/AST/ByteCode/constexpr-steps.cpp b/clang/test/AST/ByteCode/constexpr-steps.cpp
index 490425107a140..bd461547032a9 100644
--- a/clang/test/AST/ByteCode/constexpr-steps.cpp
+++ b/clang/test/AST/ByteCode/constexpr-steps.cpp
@@ -8,3 +8,10 @@ constexpr int foo() { // expected-error {{never produces a constant expression}}
static_assert (foo() == 0, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}
+constexpr void addr() { // expected-error {{never produces a constant expression}}
+ for (;;) // expected-note 2{{constexpr evaluation hit maximum step limit}}
+ ;
+}
+static_assert((addr(), 1) == 1); // expected-error {{not an integral constant expression}} \
+ // expected-note {{in call to}}
+
More information about the cfe-commits
mailing list