Author: David Zbarsky
Date: 2026-07-06T15:37:34+02:00
New Revision: 5ddd08310373371d416f148727c707beeffc1b8a

URL: 
https://github.com/llvm/llvm-project/commit/5ddd08310373371d416f148727c707beeffc1b8a
DIFF: 
https://github.com/llvm/llvm-project/commit/5ddd08310373371d416f148727c707beeffc1b8a.diff

LOG: [clang][AST] Outline constant-interpreter shift diagnostics (#202633)

CheckShift is instantiated for each primitive left-hand and right-hand
type
and for both shift directions. Its four diagnostic paths are cold, but
each
instantiation currently emits the diagnostic construction and undefined
behavior handling.

Move those paths to the non-template, noinline diagnoseShiftFailure
function.
Valid shifts retain the existing checks and do not call the outlined
function.
Invalid shifts preserve the same diagnostic arguments and call
noteUndefinedBehavior exactly once.

On arm64 macOS with a Release build of standalone Clang, this changes:

  linked binary:  222,173,192 -> 221,924,960 bytes (-248,232)
  stripped binary: 128,407,464 -> 128,291,224 bytes (-116,240)
  __TEXT,__text:   98,369,916 -> 98,255,864 bytes (-114,052)

Work towards #202616

AI tool disclosure: Co-authored with OpenAI Codex.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/Interp.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 63364287cc859..7185569dc103b 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -237,6 +237,33 @@ namespace interp {
 PRESERVE_NONE static bool BCP(InterpState &S, CodePtr OpPC, int32_t Offset,
                               PrimType PT);
 
+bool diagnoseShiftFailure(InterpState &S, CodePtr OpPC, ShiftFailure Failure,
+                          const APSInt *Value, unsigned Bits) {
+  switch (Failure) {
+  case ShiftFailure::NegativeCount:
+    assert(Value);
+    S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_negative_shift)
+        << *Value;
+    break;
+  case ShiftFailure::TooLarge: {
+    assert(Value);
+    const Expr *E = S.Current->getExpr(OpPC);
+    S.CCEDiag(E, diag::note_constexpr_large_shift)
+        << *Value << E->getType() << Bits;
+    break;
+  }
+  case ShiftFailure::NegativeLeftOperand:
+    assert(Value);
+    S.CCEDiag(S.Current->getExpr(OpPC), 
diag::note_constexpr_lshift_of_negative)
+        << *Value;
+    break;
+  case ShiftFailure::DiscardsBits:
+    S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
+    break;
+  }
+  return S.noteUndefinedBehavior();
+}
+
 void cleanupAfterFunctionCall(InterpState &S, const Function *Func) {
   assert(S.Current);
   assert(Func);

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 4b8fc93909697..d16a00414f45a 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -35,6 +35,7 @@
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/Compiler.h"
 #include <type_traits>
 
 // preserve_none causes problems when asan is enabled on both AArch64 and other
@@ -153,25 +154,33 @@ bool CastFloatingIntegralAPS(InterpState &S, CodePtr 
OpPC, uint32_t BitWidth,
 
 enum class ShiftDir { Left, Right };
 
+enum class ShiftFailure {
+  NegativeCount,
+  TooLarge,
+  NegativeLeftOperand,
+  DiscardsBits,
+};
+
+LLVM_ATTRIBUTE_NOINLINE bool diagnoseShiftFailure(InterpState &S, CodePtr OpPC,
+                                                  ShiftFailure Failure,
+                                                  const APSInt *Value = 
nullptr,
+                                                  unsigned Bits = 0);
+
 /// Checks if the shift operation is legal.
 template <ShiftDir Dir, typename LT, typename RT>
 bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
                 unsigned Bits) {
   if (RHS.isNegative()) {
-    const SourceInfo &Loc = S.Current->getSource(OpPC);
-    S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
-    if (!S.noteUndefinedBehavior())
+    const APSInt Value = RHS.toAPSInt();
+    if (!diagnoseShiftFailure(S, OpPC, ShiftFailure::NegativeCount, &Value))
       return false;
   }
 
   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
   // the shifted type.
   if (Bits > 1 && RHS >= Bits) {
-    const Expr *E = S.Current->getExpr(OpPC);
-    const APSInt Val = RHS.toAPSInt();
-    QualType Ty = E->getType();
-    S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
-    if (!S.noteUndefinedBehavior())
+    const APSInt Value = RHS.toAPSInt();
+    if (!diagnoseShiftFailure(S, OpPC, ShiftFailure::TooLarge, &Value, Bits))
       return false;
   }
 
@@ -180,15 +189,13 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT 
&LHS, const RT &RHS,
       // C++11 [expr.shift]p2: A signed left shift must have a non-negative
       // operand, and must not overflow the corresponding unsigned type.
       if (LHS.isNegative()) {
-        const Expr *E = S.Current->getExpr(OpPC);
-        S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << 
LHS.toAPSInt();
-        if (!S.noteUndefinedBehavior())
+        const APSInt Value = LHS.toAPSInt();
+        if (!diagnoseShiftFailure(S, OpPC, ShiftFailure::NegativeLeftOperand,
+                                  &Value))
           return false;
       } else if (LHS.toUnsigned().countLeadingZeros() <
                  static_cast<unsigned>(RHS)) {
-        const Expr *E = S.Current->getExpr(OpPC);
-        S.CCEDiag(E, diag::note_constexpr_lshift_discards);
-        if (!S.noteUndefinedBehavior())
+        if (!diagnoseShiftFailure(S, OpPC, ShiftFailure::DiscardsBits))
           return false;
       }
     }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to