[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