Skip to content

Commit ed304b6

Browse files
committed
[clang][Interp] Diagnose left shifts of negative values
1 parent de02994 commit ed304b6

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

clang/lib/AST/Interp/Interp.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,6 +2234,20 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
22342234
: ShiftDir::Left > (S, OpPC, LHS, RHS);
22352235
}
22362236

2237+
if constexpr (Dir == ShiftDir::Left) {
2238+
if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {
2239+
// C++11 [expr.shift]p2: A signed left shift must have a non-negative
2240+
// operand, and must not overflow the corresponding unsigned type.
2241+
// C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
2242+
// E1 x 2^E2 module 2^N.
2243+
const SourceInfo &Loc = S.Current->getSource(OpPC);
2244+
S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
2245+
if (S.getLangOpts().CPlusPlus11 && S.getEvalStatus().Diag &&
2246+
!S.getEvalStatus().Diag->empty())
2247+
return false;
2248+
}
2249+
}
2250+
22372251
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
22382252
return false;
22392253

clang/test/AST/Interp/shifts.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,10 @@ enum shiftof {
203203
X = (1<<-29) // all-error {{expression is not an integral constant expression}} \
204204
// all-note {{negative shift count -29}}
205205
};
206+
207+
enum shiftof2 {
208+
X2 = (-1<<29) // cxx17-error {{expression is not an integral constant expression}} \
209+
// cxx17-note {{left shift of negative value -1}} \
210+
// ref-cxx17-error {{expression is not an integral constant expression}} \
211+
// ref-cxx17-note {{left shift of negative value -1}}
212+
};

0 commit comments

Comments
 (0)