https://gcc.gnu.org/g:b905ce8caf04253e02e153d60d6ea8f99d300af6

commit r15-9379-gb905ce8caf04253e02e153d60d6ea8f99d300af6
Author: Iain Buclaw <ibuc...@gdcproject.org>
Date:   Fri Apr 11 12:39:23 2025 +0200

    d: Merge upstream dmd 1b34fea478, phobos 40ffbb364
    
    D front-end changes:
    
            - Import latest fixes from dmd v2.111.1-rc.1.
    
    Phobos changes:
    
            - Import latest fixes from phobos v2.111.1-rc.1.
            - Restore compatibility with older Linux platforms where
              `getrandom' is unavailable.
    
    gcc/d/ChangeLog:
    
            * dmd/MERGE: Merge upstream dmd 1b34fea478.
    
    libphobos/ChangeLog:
    
            * src/MERGE: Merge upstream phobos 40ffbb364.
            * Makefile.in: Regenerate.
            * configure: Regenerate.
            * configure.ac: Call DRUNTIME_OS_FEATURES.
            * libdruntime/Makefile.am (AM_DFLAGS): Add OS_DFLAGS.
            * libdruntime/Makefile.in: Regenerate.
            * m4/druntime/os.m4 (DRUNTIME_OS_FEATURES): Define.
            * src/Makefile.am: Add OS_DFLAGS.
            * src/Makefile.in: Regenerate.
            * testsuite/Makefile.in: Regenerate.
            * testsuite/testsuite_flags.in: Add OS_DFLAGS.

Diff:
---
 gcc/d/dmd/MERGE                                    |  2 +-
 gcc/d/dmd/globals.h                                |  1 +
 gcc/d/dmd/lexer.d                                  |  4 +-
 gcc/d/dmd/location.d                               | 23 +++++---
 gcc/d/dmd/typesem.d                                | 16 +++++-
 gcc/testsuite/gdc.test/compilable/test21179.d      | 11 ++++
 .../gdc.test/fail_compilation/fail_pretty_errors.d | 18 +++---
 libphobos/Makefile.in                              |  1 +
 libphobos/configure                                | 53 ++++++++++++++++-
 libphobos/configure.ac                             |  1 +
 libphobos/libdruntime/Makefile.am                  |  3 +-
 libphobos/libdruntime/Makefile.in                  |  4 +-
 libphobos/m4/druntime/os.m4                        | 27 +++++++++
 libphobos/src/MERGE                                |  2 +-
 libphobos/src/Makefile.am                          |  3 +-
 libphobos/src/Makefile.in                          |  4 +-
 libphobos/src/std/format/write.d                   | 11 +++-
 libphobos/src/std/random.d                         | 66 ++++++++++++++++++----
 libphobos/testsuite/Makefile.in                    |  1 +
 libphobos/testsuite/testsuite_flags.in             |  2 +-
 20 files changed, 210 insertions(+), 43 deletions(-)

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index a05a50eefb8d..ee5eb853284b 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-51816cd01deee5cc1d7d2c6e1e24788ec655b73e
+1b34fea4788136b54ec77c6ed9678754d109fc79
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 59952a2c1053..62a575e322e3 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -421,6 +421,7 @@ struct SourceLoc
     uint32_t line;
     uint32_t column;
     uint32_t fileOffset;
+    DString fileContent;
 };
 
 struct Loc
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 63313ac2eddf..ed9f7f1ce775 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -132,7 +132,7 @@ class Lexer
         // debug printf("Lexer::Lexer(%p)\n", base);
         // debug printf("lexer.filename = %s\n", filename);
         token = Token.init;
-        this.baseLoc = newBaseLoc(filename, endoffset);
+        this.baseLoc = newBaseLoc(filename, base[0 .. endoffset]);
         this.linnum = 1;
         this.base = base;
         this.end = base + endoffset;
@@ -224,7 +224,7 @@ class Lexer
         inTokenStringConstant = 0;
         lastDocLine = 0;
 
-        baseLoc = newBaseLoc("#defines", slice.length);
+        baseLoc = newBaseLoc("#defines", slice);
         scanloc = baseLoc.getLoc(0);
     }
 
diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d
index 54b3fb6e0aed..393ffb8a92d4 100644
--- a/gcc/d/dmd/location.d
+++ b/gcc/d/dmd/location.d
@@ -64,7 +64,7 @@ nothrow:
     extern (C++) static Loc singleFilename(const char* filename)
     {
         Loc result;
-        locFileTable ~= new BaseLoc(filename.toDString, locIndex, 0, [0]);
+        locFileTable ~= new BaseLoc(filename.toDString, null, locIndex, 0, 
[0]);
         result.index = locIndex++;
         return result;
     }
@@ -235,16 +235,20 @@ struct SourceLoc
     uint column; /// column number (starts at 1)
     uint fileOffset; /// byte index into file
 
+    /// Index `fileOffset` into this to to obtain source code context of this 
location
+    const(char)[] fileContent;
+
     // aliases for backwards compatibility
     alias linnum = line;
     alias charnum = column;
 
-    this(const(char)[] filename, uint line, uint column, uint fileOffset = 0) 
nothrow @nogc pure @safe
+    this(const(char)[] filename, uint line, uint column, uint fileOffset = 0, 
const(char)[] fileContent = null) nothrow @nogc pure @safe
     {
         this.filename = filename;
         this.line = line;
         this.column = column;
         this.fileOffset = fileOffset;
+        this.fileContent = fileContent;
     }
 
     this(Loc loc) nothrow @nogc @trusted
@@ -300,15 +304,15 @@ private size_t fileTableIndex(uint index) nothrow @nogc
  * Create a new source location map for a file
  * Params:
  *   filename = source file name
- *   size = space to reserve for locations, equal to the file size in bytes
+ *   fileContent = content of source file
  * Returns: new BaseLoc
  */
-BaseLoc* newBaseLoc(const(char)* filename, size_t size) nothrow
+BaseLoc* newBaseLoc(const(char)* filename, const(char)[] fileContent) nothrow
 {
-    locFileTable ~= new BaseLoc(filename.toDString, locIndex, 1, [0]);
+    locFileTable ~= new BaseLoc(filename.toDString, fileContent, locIndex, 1, 
[0]);
     // Careful: the endloc of a FuncDeclaration can
     // point to 1 past the very last byte in the file, so account for that
-    locIndex += size + 1;
+    locIndex += fileContent.length + 1;
     return locFileTable[$ - 1];
 }
 
@@ -354,6 +358,7 @@ struct BaseLoc
 @safe nothrow:
 
     const(char)[] filename; /// Source file name
+    const(char)[] fileContents; /// Source file contents
     uint startIndex; /// Subtract this from Loc.index to get file offset
     int startLine = 1; /// Line number at index 0
     uint[] lines; /// For each line, the file offset at which it starts. At 
index 0 there's always a 0 entry.
@@ -384,11 +389,11 @@ struct BaseLoc
     {
         auto fname = filename.toDString;
         if (substitutions.length == 0)
-            substitutions ~= BaseLoc(this.filename, 0, 0);
+            substitutions ~= BaseLoc(this.filename, null, 0, 0);
 
         if (fname.length == 0)
             fname = substitutions[$ - 1].filename;
-        substitutions ~= BaseLoc(fname, offset, cast(int) (line - lines.length 
+ startLine - 2));
+        substitutions ~= BaseLoc(fname, null, offset, cast(int) (line - 
lines.length + startLine - 2));
     }
 
     /// Returns: `loc` modified by substitutions from #file / #line directives
@@ -408,7 +413,7 @@ struct BaseLoc
     private SourceLoc getSourceLoc(uint offset) @nogc
     {
         const i = getLineIndex(offset);
-        const sl = SourceLoc(filename, cast(int) (i + startLine), cast(int) (1 
+ offset - lines[i]), offset);
+        const sl = SourceLoc(filename, cast(int) (i + startLine), cast(int) (1 
+ offset - lines[i]), offset, fileContents);
         return substitute(sl);
     }
 
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 3bc0489bffc5..d4c7a5865d25 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -3266,9 +3266,19 @@ Type merge(Type type)
 
         case Tsarray:
             // prevents generating the mangle if the array dim is not yet known
-            if (!type.isTypeSArray().dim.isIntegerExp())
-                return type;
-            goto default;
+            if (auto ie = type.isTypeSArray().dim.isIntegerExp())
+            {
+                // After TypeSemantic, the length is always converted to 
size_t, but the parser
+                // usually generates regular integer types (e.g. in cast(const 
ubyte[2])) which
+                // it may try to merge, which then leads to failing implicit 
conversions as 2LU != 2
+                // according to Expression.equals. Only merge array types with 
size_t lengths for now.
+                // https://github.com/dlang/dmd/issues/21179
+                if (ie.type != Type.tsize_t)
+                    return type;
+
+                goto default;
+            }
+            return type;
 
         case Tenum:
             break;
diff --git a/gcc/testsuite/gdc.test/compilable/test21179.d 
b/gcc/testsuite/gdc.test/compilable/test21179.d
new file mode 100644
index 000000000000..78bdffda5506
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21179.d
@@ -0,0 +1,11 @@
+// https://github.com/dlang/dmd/issues/21179
+
+void bigEndianToNative(ubyte[2] a) {}
+
+void main()
+{
+    ubyte[] arr;
+    const ubyte[2] bytes;
+    bigEndianToNative(bytes);
+    auto b = cast(const ubyte[2][]) arr;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d 
b/gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d
index 2016a5017511..79242b163eea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d
@@ -1,22 +1,24 @@
-/*
+/*
 REQUIRED_ARGS: -verrors=context
 TEST_OUTPUT:
 ---
-fail_compilation/fail_pretty_errors.d(27): Error: undefined identifier `a`
+fail_compilation/fail_pretty_errors.d(29): Error: undefined identifier `a`
     a = 1;
     ^
-fail_compilation/fail_pretty_errors.d-mixin-32(32): Error: undefined 
identifier `b`
-fail_compilation/fail_pretty_errors.d(37): Error: cannot implicitly convert 
expression `5` of type `int` to `string`
+fail_compilation/fail_pretty_errors.d-mixin-34(34): Error: undefined 
identifier `b`
+b = 1;
+^
+fail_compilation/fail_pretty_errors.d(39): Error: cannot implicitly convert 
expression `5` of type `int` to `string`
     string x = 5;
                ^
-fail_compilation/fail_pretty_errors.d(42): Error: mixin 
`fail_pretty_errors.testMixin2.mixinTemplate!()` error instantiating
+fail_compilation/fail_pretty_errors.d(44): Error: mixin 
`fail_pretty_errors.testMixin2.mixinTemplate!()` error instantiating
     mixin mixinTemplate;
     ^
-fail_compilation/fail_pretty_errors.d(48): Error: invalid array operation `"" 
+ ""` (possible missing [])
+fail_compilation/fail_pretty_errors.d(50): Error: invalid array operation `"" 
+ ""` (possible missing [])
     auto x = ""+"";
              ^
-fail_compilation/fail_pretty_errors.d(48):        did you mean to concatenate 
(`"" ~ ""`) instead ?
-fail_compilation/fail_pretty_errors.d(51): Error: cannot implicitly convert 
expression `1111` of type `int` to `byte`
+fail_compilation/fail_pretty_errors.d(50):        did you mean to concatenate 
(`"" ~ ""`) instead ?
+fail_compilation/fail_pretty_errors.d(53): Error: cannot implicitly convert 
expression `1111` of type `int` to `byte`
         byte ɑ =    1111;
                     ^
 ---
diff --git a/libphobos/Makefile.in b/libphobos/Makefile.in
index 162e83bd57e0..cd64fd531ca9 100644
--- a/libphobos/Makefile.in
+++ b/libphobos/Makefile.in
@@ -258,6 +258,7 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OS_DFLAGS = @OS_DFLAGS@
 OS_LINK_SPEC = @OS_LINK_SPEC@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
diff --git a/libphobos/configure b/libphobos/configure
index df48a6b4d959..4f5be7d4ff4e 100755
--- a/libphobos/configure
+++ b/libphobos/configure
@@ -655,6 +655,7 @@ DCFG_HAVE_LIBATOMIC
 DCFG_HAVE_64BIT_ATOMICS
 DCFG_HAVE_ATOMIC_BUILTINS
 DCFG_HAVE_QSORT_R
+OS_DFLAGS
 OS_LINK_SPEC
 DCFG_DLPI_TLS_MODID
 DRUNTIME_OS_MINFO_BRACKETING_FALSE
@@ -11863,7 +11864,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11866 "configure"
+#line 11867 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11969,7 +11970,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11972 "configure"
+#line 11973 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14717,6 +14718,54 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 
+
+  OS_DFLAGS=
+
+  case "$druntime_cv_target_os" in
+    linux*)  druntime_target_os_parsed="linux"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getrandom" >&5
+$as_echo_n "checking for getrandom... " >&6; }
+      ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext 
$LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/syscall.h>
+#include <unistd.h>
+int
+main ()
+{
+
+        syscall (__NR_getrandom);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+         OS_DFLAGS=-fversion=linux_legacy_emulate_getrandom
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext 
$LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+      ;;
+  esac
+
+
+
+
   ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
diff --git a/libphobos/configure.ac b/libphobos/configure.ac
index 3b2ec2c91db8..406373be0594 100644
--- a/libphobos/configure.ac
+++ b/libphobos/configure.ac
@@ -143,6 +143,7 @@ DRUNTIME_OS_ARM_EABI_UNWINDER
 DRUNTIME_OS_MINFO_BRACKETING
 DRUNTIME_OS_DLPI_TLS_MODID
 DRUNTIME_OS_LINK_SPEC
+DRUNTIME_OS_FEATURES
 DRUNTIME_LIBRARIES_CLIB
 
 WITH_LOCAL_DRUNTIME([
diff --git a/libphobos/libdruntime/Makefile.am 
b/libphobos/libdruntime/Makefile.am
index 252c6a3eebbc..9adb5034b088 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -25,7 +25,8 @@ D_EXTRA_DFLAGS=-fpreview=dip1000 -fpreview=fieldwise 
-fpreview=dtorfields \
 # D flags for compilation
 AM_DFLAGS= \
        $(phobos_lt_pic_flag) $(phobos_compiler_shared_flag) \
-       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS)
+       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS) \
+       $(OS_DFLAGS)
 
 # Flags for other kinds of sources
 AM_CFLAGS=$(CET_FLAGS)
diff --git a/libphobos/libdruntime/Makefile.in 
b/libphobos/libdruntime/Makefile.in
index 52b0c377241e..8f8072c6dc9e 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -676,6 +676,7 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OS_DFLAGS = @OS_DFLAGS@
 OS_LINK_SPEC = @OS_LINK_SPEC@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
@@ -783,7 +784,8 @@ D_EXTRA_DFLAGS = -fpreview=dip1000 -fpreview=fieldwise 
-fpreview=dtorfields \
 # D flags for compilation
 AM_DFLAGS = \
        $(phobos_lt_pic_flag) $(phobos_compiler_shared_flag) \
-       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS)
+       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS) \
+       $(OS_DFLAGS)
 
 
 # Flags for other kinds of sources
diff --git a/libphobos/m4/druntime/os.m4 b/libphobos/m4/druntime/os.m4
index 15cde3b04b8d..ef8ca4344071 100644
--- a/libphobos/m4/druntime/os.m4
+++ b/libphobos/m4/druntime/os.m4
@@ -121,6 +121,33 @@ AC_DEFUN([DRUNTIME_OS_SOURCES],
 ])
 
 
+# DRUNTIME_OS_FEATURES
+# -----------------------
+# Perform various feature checks on the target platform.
+AC_DEFUN([DRUNTIME_OS_FEATURES],
+[
+  AC_REQUIRE([DRUNTIME_OS_DETECT])
+  OS_DFLAGS=
+
+  case "$druntime_cv_target_os" in
+    linux*)  druntime_target_os_parsed="linux"
+      AC_MSG_CHECKING([for getrandom])
+      AC_LANG_PUSH([C])
+      AC_TRY_COMPILE([#include <sys/syscall.h>
+#include <unistd.h>],[
+        syscall (__NR_getrandom);
+      ],
+        [AC_MSG_RESULT([yes])],
+        [AC_MSG_RESULT([no])
+         OS_DFLAGS=-fversion=linux_legacy_emulate_getrandom])
+      AC_LANG_POP([C])
+      ;;
+  esac
+
+  AC_SUBST(OS_DFLAGS)
+])
+
+
 # DRUNTIME_OS_ARM_EABI_UNWINDER
 # ------------------------
 # Check if using ARM unwinder and substitute DCFG_ARM_EABI_UNWINDER
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index d870a91ba963..a28116af8f23 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-35977c8029e7bb4dbe1b887688dabebe04ebea02
+40ffbb3641495b02815891ee004d4c6e173b1089
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/Makefile.am b/libphobos/src/Makefile.am
index 5d690dddf2bd..a84fc4d237fa 100644
--- a/libphobos/src/Makefile.am
+++ b/libphobos/src/Makefile.am
@@ -26,7 +26,8 @@ D_EXTRA_DFLAGS=-fpreview=dip1000 -fpreview=dtorfields 
-fpreview=fieldwise \
 # D flags for compilation
 AM_DFLAGS= \
        $(phobos_lt_pic_flag) $(phobos_compiler_shared_flag) \
-       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS)
+       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS) \
+       $(OS_DFLAGS)
 
 # Flags for other kinds of sources
 AM_CFLAGS=$(CET_FLAGS)
diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in
index 2bf7e3f28747..64cc9c3d0104 100644
--- a/libphobos/src/Makefile.in
+++ b/libphobos/src/Makefile.in
@@ -411,6 +411,7 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OS_DFLAGS = @OS_DFLAGS@
 OS_LINK_SPEC = @OS_LINK_SPEC@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
@@ -519,7 +520,8 @@ D_EXTRA_DFLAGS = -fpreview=dip1000 -fpreview=dtorfields 
-fpreview=fieldwise \
 # D flags for compilation
 AM_DFLAGS = \
        $(phobos_lt_pic_flag) $(phobos_compiler_shared_flag) \
-       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS)
+       $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_FLAGS) \
+       $(OS_DFLAGS)
 
 
 # Flags for other kinds of sources
diff --git a/libphobos/src/std/format/write.d b/libphobos/src/std/format/write.d
index d704c14f5faa..68a96d48625c 100644
--- a/libphobos/src/std/format/write.d
+++ b/libphobos/src/std/format/write.d
@@ -534,6 +534,8 @@ uint formattedWrite(Writer, Char, Args...)(auto ref Writer 
w, const scope Char[]
 
     // Are we already done with formats? Then just dump each parameter in turn
     uint currentArg = 0;
+    bool lastWasConsumeAll;
+
     while (spec.writeUpToNextSpec(w))
     {
         if (currentArg == Args.length && !spec.indexStart)
@@ -649,7 +651,10 @@ uint formattedWrite(Writer, Char, Args...)(auto ref Writer 
w, const scope Char[]
             }
         default:
             if (spec.indexEnd == spec.indexEnd.max)
+            {
+                lastWasConsumeAll = true;
                 break;
+            }
             else if (spec.indexEnd == spec.indexStart)
                 throw new FormatException(
                     text("Positional specifier %", spec.indexStart, '$', 
spec.spec,
@@ -660,7 +665,8 @@ uint formattedWrite(Writer, Char, Args...)(auto ref Writer 
w, const scope Char[]
                     " index exceeds ", Args.length));
         }
     }
-    return currentArg;
+
+    return lastWasConsumeAll ? Args.length : currentArg;
 }
 
 ///
@@ -1212,7 +1218,8 @@ if (isSomeString!(typeof(fmt)))
     import std.array : appender;
     auto w = appender!(char[])();
 
-    formattedWrite(w, "%1:$d", 1, 2, 3);
+    uint count = formattedWrite(w, "%1:$d", 1, 2, 3);
+    assert(count == 3);
     assert(w.data == "123");
 }
 
diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d
index dc1763cf71c3..edb8902c6493 100644
--- a/libphobos/src/std/random.d
+++ b/libphobos/src/std/random.d
@@ -1774,19 +1774,65 @@ else
 
 version (linux)
 {
-    // `getrandom()` was introduced in Linux 3.17.
+    version (linux_legacy_emulate_getrandom)
+    {
+        /+
+            Emulates `getrandom()` for backwards compatibility
+            with outdated kernels and legacy libc versions.
+
+            `getrandom()` was added to the GNU C Library in v2.25.
+         +/
+        pragma(msg, "`getrandom()` emulation for legacy Linux targets is 
enabled.");
+
+        /+
+            On modern kernels (5.6+), `/dev/random` would behave more similar
+            to `getrandom()`.
+            However, this emulator was specifically written for systems older
+            than that. Hence, `/dev/urandom` is the CSPRNG of choice.
+
+            
<https://web.archive.org/web/20200914181930/https://www.2uo.de/myths-about-urandom/>
+         +/
+        private static immutable _pathLinuxSystemCSPRNG = "/dev/urandom";
+
+        import core.sys.posix.sys.types : ssize_t;
+
+        /+
+            Linux `getrandom()` emulation built upon `/dev/urandom`.
+            The fourth parameter (`uint flags`) is happily ignored.
+         +/
+        private ssize_t getrandom(
+                void* buf,
+                size_t buflen,
+                uint,
+        ) @system nothrow @nogc
+        {
+            import core.stdc.stdio : fclose, fopen, fread;
 
-    // Shim for missing bindings in druntime
-    version (none)
-        import core.sys.linux.sys.random : getrandom;
+            auto blockDev = fopen(_pathLinuxSystemCSPRNG.ptr, "r");
+            if (blockDev is null)
+                assert(false, "System CSPRNG unavailable: `fopen(\"" ~ 
_pathLinuxSystemCSPRNG ~ "\")` failed.");
+            scope (exit) fclose(blockDev);
+
+            const bytesRead = fread(buf, 1, buflen, blockDev);
+            return bytesRead;
+        }
+    }
     else
     {
-        import core.sys.posix.sys.types : ssize_t;
-        extern extern(C) ssize_t getrandom(
-            void* buf,
-            size_t buflen,
-            uint flags,
-        ) @system nothrow @nogc;
+        // `getrandom()` was introduced in Linux 3.17.
+
+        // Shim for missing bindings in druntime
+        version (none)
+            import core.sys.linux.sys.random : getrandom;
+        else
+        {
+            import core.sys.posix.sys.types : ssize_t;
+            private extern extern(C) ssize_t getrandom(
+                void* buf,
+                size_t buflen,
+                uint flags,
+            ) @system nothrow @nogc;
+        }
     }
 }
 
diff --git a/libphobos/testsuite/Makefile.in b/libphobos/testsuite/Makefile.in
index b410f17254a6..3df08152b740 100644
--- a/libphobos/testsuite/Makefile.in
+++ b/libphobos/testsuite/Makefile.in
@@ -202,6 +202,7 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OS_DFLAGS = @OS_DFLAGS@
 OS_LINK_SPEC = @OS_LINK_SPEC@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
diff --git a/libphobos/testsuite/testsuite_flags.in 
b/libphobos/testsuite/testsuite_flags.in
index 9933667b4eae..d69127249a80 100755
--- a/libphobos/testsuite/testsuite_flags.in
+++ b/libphobos/testsuite/testsuite_flags.in
@@ -28,7 +28,7 @@ case ${query} in
       ;;
     --gdcflags)
       GDCFLAGS_default="-fmessage-length=0 -fno-show-column"
-      GDCFLAGS_config="@WARN_DFLAGS@ @GDCFLAGS@ @CET_FLAGS@
+      GDCFLAGS_config="@WARN_DFLAGS@ @GDCFLAGS@ @CET_FLAGS@ @OS_DFLAGS@
                       @phobos_compiler_shared_flag@
                       -fall-instantiations -fpreview=dip1000
                       -fno-release -funittest"

Reply via email to