aboutsummaryrefslogtreecommitdiff
path: root/libcpp/expr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp/expr.cc')
-rw-r--r--libcpp/expr.cc28
1 files changed, 23 insertions, 5 deletions
diff --git a/libcpp/expr.cc b/libcpp/expr.cc
index 4573752..7bb57a3 100644
--- a/libcpp/expr.cc
+++ b/libcpp/expr.cc
@@ -53,7 +53,7 @@ static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,
static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num);
static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype,
location_t);
-static cpp_num num_lshift (cpp_num, size_t, size_t);
+static cpp_num num_lshift (cpp_reader *, cpp_num, size_t, size_t);
static cpp_num num_rshift (cpp_num, size_t, size_t);
static cpp_num append_digit (cpp_num, int, int, size_t);
@@ -2049,7 +2049,7 @@ num_rshift (cpp_num num, size_t precision, size_t n)
/* Shift NUM, of width PRECISION, left by N bits. */
static cpp_num
-num_lshift (cpp_num num, size_t precision, size_t n)
+num_lshift (cpp_reader *pfile, cpp_num num, size_t precision, size_t n)
{
if (n >= precision)
{
@@ -2075,8 +2075,26 @@ num_lshift (cpp_num num, size_t precision, size_t n)
}
num = num_trim (num, precision);
- if (num.unsignedp)
+ if (num.unsignedp
+ /* For C++20 or later since P1236R1, there is no overflow for signed
+ left shifts, it is as if the shift was in uintmax_t and cast
+ back to intmax_t afterwards. */
+ || (CPP_OPTION (pfile, cplusplus)
+ && CPP_OPTION (pfile, lang) >= CLK_GNUCXX20))
num.overflow = false;
+ else if (CPP_OPTION (pfile, cplusplus)
+ && CPP_OPTION (pfile, lang) >= CLK_GNUCXX11
+ && num_positive (orig, precision))
+ {
+ /* For C++11 - C++17 since CWG1457, 1 << 63 is allowed because it is
+ representable in uintmax_t, but 3 << 63 is not.
+ Test whether num >> (precision - 1 - n) as logical
+ shift is > 1. */
+ maybe_orig = orig;
+ maybe_orig.unsignedp = true;
+ maybe_orig = num_rshift (maybe_orig, precision, precision - 1 - n);
+ num.overflow = maybe_orig.high || maybe_orig.low > 1;
+ }
else
{
maybe_orig = num_rshift (num, precision, n);
@@ -2149,7 +2167,7 @@ num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
else
n = rhs.low;
if (op == CPP_LSHIFT)
- lhs = num_lshift (lhs, precision, n);
+ lhs = num_lshift (pfile, lhs, precision, n);
else
lhs = num_rshift (lhs, precision, n);
break;
@@ -2347,7 +2365,7 @@ num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op,
rhs.unsignedp = true;
lhs.unsignedp = true;
i = precision - i - 1;
- sub = num_lshift (rhs, precision, i);
+ sub = num_lshift (pfile, rhs, precision, i);
result.high = result.low = 0;
for (;;)