Author: Timm Bäder Date: 2024-07-14T07:28:02+02:00 New Revision: de029943cc5ad0028f16e6ecaffa03e32ffd1a6f
URL: https://github.com/llvm/llvm-project/commit/de029943cc5ad0028f16e6ecaffa03e32ffd1a6f DIFF: https://github.com/llvm/llvm-project/commit/de029943cc5ad0028f16e6ecaffa03e32ffd1a6f.diff LOG: [clang][Interp] Handle negative shift amounts correctly We need to invert them and use the opposite shift. Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/shifts.cpp clang/test/Sema/shift-count-negative.c Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 95f89990a7a18..8502b7ca136ee 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2209,13 +2209,10 @@ inline bool RVOPtr(InterpState &S, CodePtr OpPC) { //===----------------------------------------------------------------------===// // Shr, Shl //===----------------------------------------------------------------------===// +enum class ShiftDir { Left, Right }; -template <PrimType NameL, PrimType NameR> -inline bool Shr(InterpState &S, CodePtr OpPC) { - using LT = typename PrimConv<NameL>::T; - using RT = typename PrimConv<NameR>::T; - auto RHS = S.Stk.pop<RT>(); - const auto &LHS = S.Stk.pop<LT>(); +template <class LT, class RT, ShiftDir Dir> +inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { const unsigned Bits = LHS.bitWidth(); // OpenCL 6.3j: shift values are effectively % word size of LHS. @@ -2223,6 +2220,20 @@ inline bool Shr(InterpState &S, CodePtr OpPC) { RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), RHS.bitWidth(), &RHS); + if (RHS.isNegative()) { + // During constant-folding, a negative shift is an opposite shift. Such a + // shift is not a constant expression. + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); + if (S.getLangOpts().CPlusPlus11 && S.getEvalStatus().Diag && + !S.getEvalStatus().Diag->empty()) + return false; + RHS = -RHS; + return DoShift < LT, RT, + Dir == ShiftDir::Left ? ShiftDir::Right + : ShiftDir::Left > (S, OpPC, LHS, RHS); + } + if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; @@ -2230,45 +2241,44 @@ inline bool Shr(InterpState &S, CodePtr OpPC) { // it has already been diagnosed by CheckShift() above, // but we still need to handle it. typename LT::AsUnsigned R; - if (RHS > RT::from(Bits - 1, RHS.bitWidth())) - LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(Bits - 1), Bits, &R); - else - LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(RHS, Bits), Bits, &R); + if constexpr (Dir == ShiftDir::Left) { + if (RHS > RT::from(Bits - 1, RHS.bitWidth())) + LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), + LT::AsUnsigned::from(Bits - 1), Bits, &R); + else + LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), + LT::AsUnsigned::from(RHS, Bits), Bits, &R); + } else { + if (RHS > RT::from(Bits - 1, RHS.bitWidth())) + LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), + LT::AsUnsigned::from(Bits - 1), Bits, &R); + else + LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), + LT::AsUnsigned::from(RHS, Bits), Bits, &R); + } + S.Stk.push<LT>(LT::from(R)); return true; } template <PrimType NameL, PrimType NameR> -inline bool Shl(InterpState &S, CodePtr OpPC) { +inline bool Shr(InterpState &S, CodePtr OpPC) { using LT = typename PrimConv<NameL>::T; using RT = typename PrimConv<NameR>::T; auto RHS = S.Stk.pop<RT>(); - const auto &LHS = S.Stk.pop<LT>(); - const unsigned Bits = LHS.bitWidth(); - - // OpenCL 6.3j: shift values are effectively % word size of LHS. - if (S.getLangOpts().OpenCL) - RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), - RHS.bitWidth(), &RHS); + auto LHS = S.Stk.pop<LT>(); - if (!CheckShift(S, OpPC, LHS, RHS, Bits)) - return false; + return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS); +} - // Limit the shift amount to Bits - 1. If this happened, - // it has already been diagnosed by CheckShift() above, - // but we still need to handle it. - typename LT::AsUnsigned R; - if (RHS > RT::from(Bits - 1, RHS.bitWidth())) - LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(Bits - 1), Bits, &R); - else - LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(RHS, Bits), Bits, &R); +template <PrimType NameL, PrimType NameR> +inline bool Shl(InterpState &S, CodePtr OpPC) { + using LT = typename PrimConv<NameL>::T; + using RT = typename PrimConv<NameR>::T; + auto RHS = S.Stk.pop<RT>(); + auto LHS = S.Stk.pop<LT>(); - S.Stk.push<LT>(LT::from(R)); - return true; + return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS); } //===----------------------------------------------------------------------===// diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp index 76047d0f752d5..ce17fabc7833f 100644 --- a/clang/test/AST/Interp/shifts.cpp +++ b/clang/test/AST/Interp/shifts.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify %s -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17 %s -// RUN: %clang_cc1 -std=c++20 -verify=ref %s -// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17 %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,all %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17,all %s +// RUN: %clang_cc1 -std=c++20 -verify=ref,all %s +// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17,all %s #define INT_MIN (~__INT_MAX__) @@ -198,3 +198,8 @@ namespace LongInt { } static_assert(f() == 1, ""); }; + +enum shiftof { + X = (1<<-29) // all-error {{expression is not an integral constant expression}} \ + // all-note {{negative shift count -29}} +}; diff --git a/clang/test/Sema/shift-count-negative.c b/clang/test/Sema/shift-count-negative.c index 97f85feed52c0..84c7625187a68 100644 --- a/clang/test/Sema/shift-count-negative.c +++ b/clang/test/Sema/shift-count-negative.c @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s // RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp %s +// RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp %s -fexperimental-new-constant-interpreter + enum shiftof { X = (1<<-29) // c-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}} // cpp-error@-1 {{expression is not an integral constant expression}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits