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
