Fix undefined behaviour caused by shifting (unsigned char) << 24.

Reported by Tim Sweet <tsweet64@protonmail.com>
at <https://savannah.gnu.org/bugs/?66289>.

* lib/ucs4.h (ucs4_mbtowc): Cast 'unsigned char' values to ucs4_t before
shifting them to the left.
* lib/ucs4be.h (ucs4be_mbtowc): Likewise.
* lib/ucs4le.h (ucs4le_mbtowc): Likewise.
* lib/utf32.h (utf32_mbtowc): Likewise.
* lib/utf32be.h (utf32be_mbtowc): Likewise.
* lib/utf32le.h (utf32le_mbtowc): Likewise.
diff --git a/ChangeLog b/ChangeLog
index 467d642..b57b3f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-10-04  Bruno Haible  <bruno@clisp.org>
+
+	Fix undefined behaviour caused by shifting (unsigned char) << 24.
+	Reported by Tim Sweet <tsweet64@protonmail.com>
+	at <https://savannah.gnu.org/bugs/?66289>.
+	* lib/ucs4.h (ucs4_mbtowc): Cast 'unsigned char' values to ucs4_t before
+	shifting them to the left.
+	* lib/ucs4be.h (ucs4be_mbtowc): Likewise.
+	* lib/ucs4le.h (ucs4le_mbtowc): Likewise.
+	* lib/utf32.h (utf32_mbtowc): Likewise.
+	* lib/utf32be.h (utf32be_mbtowc): Likewise.
+	* lib/utf32le.h (utf32le_mbtowc): Likewise.
+
 2024-09-26  Bruno Haible  <bruno@clisp.org>
 
 	Switch to libtool 2.5.3.
diff --git a/lib/ucs4.h b/lib/ucs4.h
index e7a0c37..4ec051f 100644
--- a/lib/ucs4.h
+++ b/lib/ucs4.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2001, 2008, 2011, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2008, 2011, 2016, 2024 Free Software Foundation, Inc.
  * This file is part of the GNU LIBICONV Library.
  *
  * The GNU LIBICONV Library is free software; you can redistribute it
@@ -31,8 +31,14 @@
   int count = 0;
   for (; n >= 4 && count <= RET_COUNT_MAX && count <= INT_MAX-4;) {
     ucs4_t wc = (state
-                  ? s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24)
-                  : (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]);
+                  ?    (ucs4_t) s[0]
+                    + ((ucs4_t) s[1] << 8)
+                    + ((ucs4_t) s[2] << 16)
+                    + ((ucs4_t) s[3] << 24)
+                  :   ((ucs4_t) s[0] << 24)
+                    + ((ucs4_t) s[1] << 16)
+                    + ((ucs4_t) s[2] << 8)
+                    +  (ucs4_t) s[3]);
     if (wc == 0x0000feff) {
     } else if (wc == 0xfffe0000u) {
       state ^= 1;
diff --git a/lib/ucs4be.h b/lib/ucs4be.h
index 2bbd8cf..942878d 100644
--- a/lib/ucs4be.h
+++ b/lib/ucs4be.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2000, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2000, 2016, 2024 Free Software Foundation, Inc.
  * This file is part of the GNU LIBICONV Library.
  *
  * The GNU LIBICONV Library is free software; you can redistribute it
@@ -25,7 +25,10 @@
 ucs4be_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
 {
   if (n >= 4) {
-    *pwc = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
+    *pwc =   ((ucs4_t) s[0] << 24)
+           + ((ucs4_t) s[1] << 16)
+           + ((ucs4_t) s[2] << 8)
+           +  (ucs4_t) s[3];
     return 4;
   }
   return RET_TOOFEW(0);
diff --git a/lib/ucs4le.h b/lib/ucs4le.h
index e1627c9..bd431c2 100644
--- a/lib/ucs4le.h
+++ b/lib/ucs4le.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2000, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2000, 2016, 2024 Free Software Foundation, Inc.
  * This file is part of the GNU LIBICONV Library.
  *
  * The GNU LIBICONV Library is free software; you can redistribute it
@@ -25,7 +25,10 @@
 ucs4le_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
 {
   if (n >= 4) {
-    *pwc = s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
+    *pwc =    (ucs4_t) s[0]
+           + ((ucs4_t) s[1] << 8)
+           + ((ucs4_t) s[2] << 16)
+           + ((ucs4_t) s[3] << 24);
     return 4;
   }
   return RET_TOOFEW(0);
diff --git a/lib/utf32.h b/lib/utf32.h
index 9ed5454..4c11a89 100644
--- a/lib/utf32.h
+++ b/lib/utf32.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2001, 2008, 2011, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2008, 2011, 2016, 2024 Free Software Foundation, Inc.
  * This file is part of the GNU LIBICONV Library.
  *
  * The GNU LIBICONV Library is free software; you can redistribute it
@@ -37,8 +37,14 @@
   int count = 0;
   for (; n >= 4 && count <= RET_COUNT_MAX && count <= INT_MAX-4;) {
     ucs4_t wc = (state
-                  ? s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24)
-                  : (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3]);
+                  ?    (ucs4_t) s[0]
+                    + ((ucs4_t) s[1] << 8)
+                    + ((ucs4_t) s[2] << 16)
+                    + ((ucs4_t) s[3] << 24)
+                  :   ((ucs4_t) s[0] << 24)
+                    + ((ucs4_t) s[1] << 16)
+                    + ((ucs4_t) s[2] << 8)
+                    +  (ucs4_t) s[3]);
     if (wc == 0x0000feff) {
     } else if (wc == 0xfffe0000u) {
       state ^= 1;
diff --git a/lib/utf32be.h b/lib/utf32be.h
index 1d33772..217706e 100644
--- a/lib/utf32be.h
+++ b/lib/utf32be.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2001, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2016, 2024 Free Software Foundation, Inc.
  * This file is part of the GNU LIBICONV Library.
  *
  * The GNU LIBICONV Library is free software; you can redistribute it
@@ -27,7 +27,10 @@
 utf32be_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
 {
   if (n >= 4) {
-    ucs4_t wc = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
+    ucs4_t wc =   ((ucs4_t) s[0] << 24)
+                + ((ucs4_t) s[1] << 16)
+                + ((ucs4_t) s[2] << 8)
+                +  (ucs4_t) s[3];
     if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000)) {
       *pwc = wc;
       return 4;
diff --git a/lib/utf32le.h b/lib/utf32le.h
index 41cf550..2d44526 100644
--- a/lib/utf32le.h
+++ b/lib/utf32le.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2001, 2016 Free Software Foundation, Inc.
+ * Copyright (C) 1999-2001, 2016, 2024 Free Software Foundation, Inc.
  * This file is part of the GNU LIBICONV Library.
  *
  * The GNU LIBICONV Library is free software; you can redistribute it
@@ -27,7 +27,10 @@
 utf32le_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
 {
   if (n >= 4) {
-    ucs4_t wc = s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
+    ucs4_t wc =    (ucs4_t) s[0]
+                + ((ucs4_t) s[1] << 8)
+                + ((ucs4_t) s[2] << 16)
+                + ((ucs4_t) s[3] << 24);
     if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000)) {
       *pwc = wc;
       return 4;