Skip to content

Commit 39fd3fc

Browse files
committed
[clang][Interp] Don't fail on shifts greater than type bitwidth
We need to limit the shift width to the type bitwidth, then do the shift and report success, but still diagnose what we limited the shiftwidth.
1 parent ec2c770 commit 39fd3fc

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

clang/lib/AST/Interp/Interp.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
135135
const APSInt Val = RHS.toAPSInt();
136136
QualType Ty = E->getType();
137137
S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
138-
return false;
138+
return true; // We will do the shift anyway but fix up the shift amount.
139139
}
140140

141141
if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
@@ -1798,11 +1798,17 @@ inline bool Shr(InterpState &S, CodePtr OpPC) {
17981798
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
17991799
return false;
18001800

1801+
// Limit the shift amount to Bits - 1. If this happened,
1802+
// it has already been diagnosed by CheckShift() above,
1803+
// but we still need to handle it.
18011804
typename LT::AsUnsigned R;
1802-
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1803-
LT::AsUnsigned::from(RHS), Bits, &R);
1805+
if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1806+
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1807+
LT::AsUnsigned::from(Bits - 1), Bits, &R);
1808+
else
1809+
LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1810+
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
18041811
S.Stk.push<LT>(LT::from(R));
1805-
18061812
return true;
18071813
}
18081814

@@ -1817,9 +1823,17 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
18171823
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
18181824
return false;
18191825

1826+
// Limit the shift amount to Bits - 1. If this happened,
1827+
// it has already been diagnosed by CheckShift() above,
1828+
// but we still need to handle it.
18201829
typename LT::AsUnsigned R;
1821-
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1822-
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1830+
if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1831+
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1832+
LT::AsUnsigned::from(Bits - 1), Bits, &R);
1833+
else
1834+
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1835+
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1836+
18231837
S.Stk.push<LT>(LT::from(R));
18241838
return true;
18251839
}

clang/test/AST/Interp/shifts.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ namespace shifts {
3434
// ref-warning {{shift count is negative}} \
3535
// ref-cxx17-warning {{shift count is negative}}
3636
c = 1 << (unsigned)-1; // expected-warning {{shift count >= width of type}} \
37-
// FIXME: 'implicit conversion' warning missing in the new interpreter. \
37+
// expected-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
3838
// cxx17-warning {{shift count >= width of type}} \
39+
// cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
3940
// ref-warning {{shift count >= width of type}} \
40-
// ref-warning {{implicit conversion}} \
41+
// ref-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
4142
// ref-cxx17-warning {{shift count >= width of type}} \
42-
// ref-cxx17-warning {{implicit conversion}}
43+
// ref-cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}}
4344
c = 1 >> (unsigned)-1; // expected-warning {{shift count >= width of type}} \
4445
// cxx17-warning {{shift count >= width of type}} \
4546
// ref-warning {{shift count >= width of type}} \

0 commit comments

Comments
 (0)