From f0a25ca26397135c10b8b35d7ee532485395ab07 Mon Sep 17 00:00:00 2001
From: Michael Matz <matz@suse.de>
Date: Sat, 31 Mar 2018 21:52:20 +0200
Subject: [PATCH] Fix shortening casts of long long

see added testcase.
---
 tccgen.c        | 10 +++++++---
 tests/tcctest.c |  5 +++++
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/tccgen.c b/tccgen.c
index 5265e494..a8523755 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -2633,18 +2633,22 @@ static void gen_cast(CType *type)
                     tcc_warning("nonportable conversion from pointer to char/short");
                 }
                 force_charshort_cast(dbt);
-#if PTR_SIZE == 4
             } else if ((dbt & VT_BTYPE) == VT_INT) {
                 /* scalar to int */
                 if ((sbt & VT_BTYPE) == VT_LLONG) {
+#if PTR_SIZE == 4
                     /* from long long: just take low order word */
                     lexpand();
                     vpop();
-                } 
+#else
+		    vpushi(0xffffffff);
+		    vtop->type.t |= VT_UNSIGNED;
+		    gen_op('&');
+#endif
+                }
                 /* if lvalue and single word type, nothing to do because
                    the lvalue already contains the real type size (see
                    VT_LVAL_xxx constants) */
-#endif
             }
         }
     } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) {
diff --git a/tests/tcctest.c b/tests/tcctest.c
index f807966f..56d51dc8 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -2491,6 +2491,11 @@ void longlong_test(void)
     a = 0x123;
     long long *p = &a;
     llshift(*p, 5);
+
+    /* shortening followed by widening */
+    unsigned long long u = 0x8000000000000001ULL;
+    u = (unsigned)(u + 1);
+    printf("long long u=" ULONG_LONG_FORMAT "\n", u);
 }
 
 void manyarg_test(void)