This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG6cf14a72390f: [clang][Interp] Check Neg ops for errors (authored by tbaeder).
Changed prior to commit: https://reviews.llvm.org/D148987?vs=517054&id=517503#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D148987/new/ https://reviews.llvm.org/D148987 Files: clang/lib/AST/Interp/Integral.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/PrimType.h clang/test/AST/Interp/literals.cpp Index: clang/test/AST/Interp/literals.cpp =================================================================== --- clang/test/AST/Interp/literals.cpp +++ clang/test/AST/Interp/literals.cpp @@ -80,6 +80,12 @@ static_assert(~INT_MIN == INT_MAX, ""); static_assert(~INT_MAX == INT_MIN, ""); +static_assert(-(1 << 31), ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{outside the range of representable values}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{outside the range of representable values}} \ + + enum E {}; constexpr E e = static_cast<E>(0); static_assert(~e == -1, ""); Index: clang/lib/AST/Interp/PrimType.h =================================================================== --- clang/lib/AST/Interp/PrimType.h +++ clang/lib/AST/Interp/PrimType.h @@ -42,6 +42,8 @@ PT_FnPtr, }; +constexpr bool isIntegralType(PrimType T) { return T <= PT_Uint64; } + /// Mapping from primitive types to their representation. template <PrimType T> struct PrimConv; template <> struct PrimConv<PT_Sint8> { using T = Integral<8, true>; }; Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -413,12 +413,32 @@ template <PrimType Name, class T = typename PrimConv<Name>::T> bool Neg(InterpState &S, CodePtr OpPC) { - const T &Val = S.Stk.pop<T>(); + const T &Value = S.Stk.pop<T>(); T Result; - T::neg(Val, &Result); + if (!T::neg(Value, &Result)) { + S.Stk.push<T>(Result); + return true; + } + + assert(isIntegralType(Name) && + "don't expect other types to fail at constexpr negation"); S.Stk.push<T>(Result); - return true; + + APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); + const Expr *E = S.Current->getExpr(OpPC); + QualType Type = E->getType(); + + if (S.checkingForUndefinedBehavior()) { + SmallString<32> Trunc; + NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10); + auto Loc = E->getExprLoc(); + S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type; + return true; + } + + S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type; + return S.noteUndefinedBehavior(); } enum class PushVal : bool { Index: clang/lib/AST/Interp/Integral.h =================================================================== --- clang/lib/AST/Interp/Integral.h +++ clang/lib/AST/Interp/Integral.h @@ -223,6 +223,9 @@ } static bool neg(Integral A, Integral *R) { + if (Signed && A.isMin()) + return true; + *R = -A; return false; }
Index: clang/test/AST/Interp/literals.cpp =================================================================== --- clang/test/AST/Interp/literals.cpp +++ clang/test/AST/Interp/literals.cpp @@ -80,6 +80,12 @@ static_assert(~INT_MIN == INT_MAX, ""); static_assert(~INT_MAX == INT_MIN, ""); +static_assert(-(1 << 31), ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{outside the range of representable values}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{outside the range of representable values}} \ + + enum E {}; constexpr E e = static_cast<E>(0); static_assert(~e == -1, ""); Index: clang/lib/AST/Interp/PrimType.h =================================================================== --- clang/lib/AST/Interp/PrimType.h +++ clang/lib/AST/Interp/PrimType.h @@ -42,6 +42,8 @@ PT_FnPtr, }; +constexpr bool isIntegralType(PrimType T) { return T <= PT_Uint64; } + /// Mapping from primitive types to their representation. template <PrimType T> struct PrimConv; template <> struct PrimConv<PT_Sint8> { using T = Integral<8, true>; }; Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -413,12 +413,32 @@ template <PrimType Name, class T = typename PrimConv<Name>::T> bool Neg(InterpState &S, CodePtr OpPC) { - const T &Val = S.Stk.pop<T>(); + const T &Value = S.Stk.pop<T>(); T Result; - T::neg(Val, &Result); + if (!T::neg(Value, &Result)) { + S.Stk.push<T>(Result); + return true; + } + + assert(isIntegralType(Name) && + "don't expect other types to fail at constexpr negation"); S.Stk.push<T>(Result); - return true; + + APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); + const Expr *E = S.Current->getExpr(OpPC); + QualType Type = E->getType(); + + if (S.checkingForUndefinedBehavior()) { + SmallString<32> Trunc; + NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10); + auto Loc = E->getExprLoc(); + S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type; + return true; + } + + S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type; + return S.noteUndefinedBehavior(); } enum class PushVal : bool { Index: clang/lib/AST/Interp/Integral.h =================================================================== --- clang/lib/AST/Interp/Integral.h +++ clang/lib/AST/Interp/Integral.h @@ -223,6 +223,9 @@ } static bool neg(Integral A, Integral *R) { + if (Signed && A.isMin()) + return true; + *R = -A; return false; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits