@@ -2209,66 +2209,76 @@ inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2209
2209
// ===----------------------------------------------------------------------===//
2210
2210
// Shr, Shl
2211
2211
// ===----------------------------------------------------------------------===//
2212
+ enum class ShiftDir { Left, Right };
2212
2213
2213
- template <PrimType NameL, PrimType NameR>
2214
- inline bool Shr (InterpState &S, CodePtr OpPC) {
2215
- using LT = typename PrimConv<NameL>::T;
2216
- using RT = typename PrimConv<NameR>::T;
2217
- auto RHS = S.Stk .pop <RT>();
2218
- const auto &LHS = S.Stk .pop <LT>();
2214
+ template <class LT , class RT , ShiftDir Dir>
2215
+ inline bool DoShift (InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2219
2216
const unsigned Bits = LHS.bitWidth ();
2220
2217
2221
2218
// OpenCL 6.3j: shift values are effectively % word size of LHS.
2222
2219
if (S.getLangOpts ().OpenCL )
2223
2220
RT::bitAnd (RHS, RT::from (LHS.bitWidth () - 1 , RHS.bitWidth ()),
2224
2221
RHS.bitWidth (), &RHS);
2225
2222
2223
+ if (RHS.isNegative ()) {
2224
+ // During constant-folding, a negative shift is an opposite shift. Such a
2225
+ // shift is not a constant expression.
2226
+ const SourceInfo &Loc = S.Current ->getSource (OpPC);
2227
+ S.CCEDiag (Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt ();
2228
+ if (S.getLangOpts ().CPlusPlus11 && S.getEvalStatus ().Diag &&
2229
+ !S.getEvalStatus ().Diag ->empty ())
2230
+ return false ;
2231
+ RHS = -RHS;
2232
+ return DoShift < LT, RT,
2233
+ Dir == ShiftDir::Left ? ShiftDir::Right
2234
+ : ShiftDir::Left > (S, OpPC, LHS, RHS);
2235
+ }
2236
+
2226
2237
if (!CheckShift (S, OpPC, LHS, RHS, Bits))
2227
2238
return false ;
2228
2239
2229
2240
// Limit the shift amount to Bits - 1. If this happened,
2230
2241
// it has already been diagnosed by CheckShift() above,
2231
2242
// but we still need to handle it.
2232
2243
typename LT::AsUnsigned R;
2233
- if (RHS > RT::from (Bits - 1 , RHS.bitWidth ()))
2234
- LT::AsUnsigned::shiftRight (LT::AsUnsigned::from (LHS),
2235
- LT::AsUnsigned::from (Bits - 1 ), Bits, &R);
2236
- else
2237
- LT::AsUnsigned::shiftRight (LT::AsUnsigned::from (LHS),
2238
- LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2244
+ if constexpr (Dir == ShiftDir::Left) {
2245
+ if (RHS > RT::from (Bits - 1 , RHS.bitWidth ()))
2246
+ LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
2247
+ LT::AsUnsigned::from (Bits - 1 ), Bits, &R);
2248
+ else
2249
+ LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
2250
+ LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2251
+ } else {
2252
+ if (RHS > RT::from (Bits - 1 , RHS.bitWidth ()))
2253
+ LT::AsUnsigned::shiftRight (LT::AsUnsigned::from (LHS),
2254
+ LT::AsUnsigned::from (Bits - 1 ), Bits, &R);
2255
+ else
2256
+ LT::AsUnsigned::shiftRight (LT::AsUnsigned::from (LHS),
2257
+ LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2258
+ }
2259
+
2239
2260
S.Stk .push <LT>(LT::from (R));
2240
2261
return true ;
2241
2262
}
2242
2263
2243
2264
template <PrimType NameL, PrimType NameR>
2244
- inline bool Shl (InterpState &S, CodePtr OpPC) {
2265
+ inline bool Shr (InterpState &S, CodePtr OpPC) {
2245
2266
using LT = typename PrimConv<NameL>::T;
2246
2267
using RT = typename PrimConv<NameR>::T;
2247
2268
auto RHS = S.Stk .pop <RT>();
2248
- const auto &LHS = S.Stk .pop <LT>();
2249
- const unsigned Bits = LHS.bitWidth ();
2250
-
2251
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
2252
- if (S.getLangOpts ().OpenCL )
2253
- RT::bitAnd (RHS, RT::from (LHS.bitWidth () - 1 , RHS.bitWidth ()),
2254
- RHS.bitWidth (), &RHS);
2269
+ auto LHS = S.Stk .pop <LT>();
2255
2270
2256
- if (! CheckShift ( S, OpPC, LHS, RHS, Bits))
2257
- return false ;
2271
+ return DoShift<LT, RT, ShiftDir::Right>( S, OpPC, LHS, RHS);
2272
+ }
2258
2273
2259
- // Limit the shift amount to Bits - 1. If this happened,
2260
- // it has already been diagnosed by CheckShift() above,
2261
- // but we still need to handle it.
2262
- typename LT::AsUnsigned R;
2263
- if (RHS > RT::from (Bits - 1 , RHS.bitWidth ()))
2264
- LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
2265
- LT::AsUnsigned::from (Bits - 1 ), Bits, &R);
2266
- else
2267
- LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
2268
- LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2274
+ template <PrimType NameL, PrimType NameR>
2275
+ inline bool Shl (InterpState &S, CodePtr OpPC) {
2276
+ using LT = typename PrimConv<NameL>::T;
2277
+ using RT = typename PrimConv<NameR>::T;
2278
+ auto RHS = S.Stk .pop <RT>();
2279
+ auto LHS = S.Stk .pop <LT>();
2269
2280
2270
- S.Stk .push <LT>(LT::from (R));
2271
- return true ;
2281
+ return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2272
2282
}
2273
2283
2274
2284
// ===----------------------------------------------------------------------===//
0 commit comments