[committed] d: Merge upstream dmd 609c3ce2d, phobos 3dd5df686

Iain Buclaw ibuclaw@gdcproject.org
Tue Jan 26 08:56:44 GMT 2021


Hi,

This patch merges the D front-end implementation with upstream dmd
609c3ce2d, and the Phobos standard library with upstream 3dd5df686.

D front-end changes:

 - Contracts for pre- and postconditions are now implicitly "this"
   const, so that state can no longer be altered in these functions.

 - Inside a constructor scope, assigning to aggregate declaration
   members is done by considering the first assignment as initialization
   and subsequent assignments as modifications of the constructed
   object.  For const/immutable fields the initialization is accepted in
   the constructor but subsequent modifications are not.  However this
   rule did not apply when inside a constructor scope there is a call to
   a different constructor.  This been changed so it is now an error
   when there's a double initialization of immutable fields inside a
   constructor.

Phobos changes:

 - Don't run unit-tests for unsupported clocks in std.datetime.  The
   phobos and phobos_shared tests now add -fversion=Linux_Pre_2639 if
   required.

 - Deprecate public extern(C) bindings for getline and getdelim in
   std.stdio.  The correct module for bindings is core.sys.posix.stdio.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and
committed to mainline.

Regards,
Iain

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 609c3ce2d.
	* d-compiler.cc (Compiler::loadModule): Rename to ...
	(Compiler::onParseModule): ... this.
	(Compiler::onImport): New function.
	* d-lang.cc (d_parse_file): Remove call to Compiler::loadModule.

libphobos/ChangeLog:

	* src/MERGE: Merge upstream phobos 3dd5df686.
	* testsuite/libphobos.phobos/phobos.exp: Add compiler flag
	-fversion=Linux_Pre_2639 if target is linux_pre_2639.
	* testsuite/libphobos.phobos_shared/phobos_shared.exp: Likewise.
---
 gcc/d/d-compiler.cc                           |  12 +-
 gcc/d/d-lang.cc                               |   1 -
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/compiler.h                          |   7 +-
 gcc/d/dmd/declaration.c                       |  14 +
 gcc/d/dmd/dmodule.c                           |  12 +-
 gcc/d/dmd/expressionsem.c                     |   7 +
 gcc/d/dmd/func.c                              |   2 -
 gcc/d/dmd/root/array.h                        |   4 +-
 .../gdc.test/fail_compilation/fail18143.d     |  43 ++
 .../gdc.test/fail_compilation/fail18719.d     |  41 ++
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/std/datetime/systime.d          |  32 +-
 libphobos/src/std/file.d                      |  23 +-
 libphobos/src/std/stdio.d                     | 602 +++++++++---------
 .../testsuite/libphobos.phobos/phobos.exp     |   8 +-
 .../libphobos.phobos_shared/phobos_shared.exp |   8 +-
 17 files changed, 496 insertions(+), 324 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail18143.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail18719.d

diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc
index 881d48228c8..3907d010684 100644
--- a/gcc/d/d-compiler.cc
+++ b/gcc/d/d-compiler.cc
@@ -157,7 +157,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
     - core.stdc.*: For all gcc library builtins.  */
 
 void
-Compiler::loadModule (Module *m)
+Compiler::onParseModule (Module *m)
 {
   ModuleDeclaration *md = m->md;
 
@@ -180,3 +180,13 @@ Compiler::loadModule (Module *m)
 	d_add_builtin_module (m);
     }
 }
+
+/* A callback function that is called once an imported module is parsed.
+   If the callback returns true, then it tells the front-end that the
+   driver intends on compiling the import.  */
+
+bool
+Compiler::onImport (Module *)
+{
+  return false;
+}
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 72dcb716987..0fd207da7f3 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -980,7 +980,6 @@ d_parse_file (void)
 
       m->importedFrom = m;
       m->parse ();
-      Compiler::loadModule (m);
 
       if (m->isDocFile)
 	{
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 1f907b8f19f..228eed838b2 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-3a7ebef73cc01d4a877a95cf95cd3776c9e3ee66
+609c3ce2d5d5d8a3dc4ba12c5e6e1100873f9ed1
 
 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/compiler.h b/gcc/d/dmd/compiler.h
index 124829b297d..7f9006ce851 100644
--- a/gcc/d/dmd/compiler.h
+++ b/gcc/d/dmd/compiler.h
@@ -27,12 +27,17 @@ extern Module *entrypoint;
 // Module in which the D main is
 extern Module *rootHasMain;
 
+extern bool includeImports;
+// array of module patterns used to include/exclude imported modules
+extern Array<const char*> includeModulePatterns;
+extern Array<Module *> compiledImports;
+
 struct Compiler
 {
     // CTFE support for cross-compilation.
     static Expression *paintAsType(UnionExp *, Expression *, Type *);
     // Backend
-    static void loadModule(Module *);
     static void genCmain(Scope *);
     static bool onImport(Module *);
+    static void onParseModule(Module *);
 };
diff --git a/gcc/d/dmd/declaration.c b/gcc/d/dmd/declaration.c
index 72a07d9b8f5..d20f6636445 100644
--- a/gcc/d/dmd/declaration.c
+++ b/gcc/d/dmd/declaration.c
@@ -145,6 +145,20 @@ int Declaration::checkModify(Loc loc, Scope *sc, Type *, Expression *e1, int fla
         }
     }
 
+    if (e1 && e1->op == TOKthis && isField())
+    {
+        VarDeclaration *vthis = e1->isThisExp()->var;
+        for (Scope *scx = sc; scx; scx = scx->enclosing)
+        {
+            if (scx->func == vthis->parent && (scx->flags & SCOPEcontract))
+            {
+                if (!flag)
+                    error(loc, "cannot modify parameter `this` in contract");
+                return 2;   // do not report type related errors
+            }
+        }
+    }
+
     if (v && (isCtorinit() || isField()))
     {
         // It's only modifiable if inside the right constructor
diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c
index 305b1331146..95c263fc425 100644
--- a/gcc/d/dmd/dmodule.c
+++ b/gcc/d/dmd/dmodule.c
@@ -375,8 +375,15 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident)
 
     m = m->parse();
 
-    Compiler::loadModule(m);
-
+    // Call onImport here because if the module is going to be compiled then we
+    // need to determine it early because it affects semantic analysis. This is
+    // being done after parsing the module so the full module name can be taken
+    // from whatever was declared in the file.
+    if (!m->isRoot() && Compiler::onImport(m))
+    {
+        m->importedFrom = m;
+        assert(m->isRoot());
+    }
     return m;
 }
 
@@ -736,6 +743,7 @@ Module *Module::parse()
         // Add to global array of all modules
         amodules.push(this);
     }
+    Compiler::onParseModule(this);
     return this;
 }
 
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
index a4ff0b41c43..7cebd9a3023 100644
--- a/gcc/d/dmd/expressionsem.c
+++ b/gcc/d/dmd/expressionsem.c
@@ -3344,6 +3344,13 @@ public:
                 return setError();
             }
 
+            // https://issues.dlang.org/show_bug.cgi?id=18719
+            // If `exp` is a call expression to another constructor
+            // then it means that all struct/class fields will be
+            // initialized after this call.
+            for (size_t i = 0; i < sc->fieldinit_dim; i++)
+                sc->fieldinit[i] |= CSXthis_ctor;
+
             if (!sc->intypeof && !(sc->callSuper & CSXhalt))
             {
                 if (sc->noctor || sc->callSuper & CSXlabel)
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
index f8f43dc09bb..2f1d648bf35 100644
--- a/gcc/d/dmd/func.c
+++ b/gcc/d/dmd/func.c
@@ -2181,7 +2181,6 @@ void FuncDeclaration::semantic3(Scope *sc)
             sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPErequire;
 
             // BUG: need to error if accessing out parameters
-            // BUG: need to treat parameters as const
             // BUG: need to disallow returns and throws
             // BUG: verify that all in and ref parameters are read
             freq = ::semantic(freq, sc2);
@@ -2213,7 +2212,6 @@ void FuncDeclaration::semantic3(Scope *sc)
             sc2 = scout;    //push
             sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPEensure;
 
-            // BUG: need to treat parameters as const
             // BUG: need to disallow returns and throws
             if (fensure && f->next->ty != Tvoid)
                 buildResultVar(scout, f->next);
diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h
index d4eccd86dbd..633414b1530 100644
--- a/gcc/d/dmd/root/array.h
+++ b/gcc/d/dmd/root/array.h
@@ -28,9 +28,9 @@ struct Array
   public:
     Array()
     {
-        data.ptr = SMALLARRAYCAP ? &smallarray[0] : NULL;
+        data.ptr = NULL;
         length = 0;
-        data.length = SMALLARRAYCAP;
+        data.length = 0;
     }
 
     ~Array()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18143.d b/gcc/testsuite/gdc.test/fail_compilation/fail18143.d
new file mode 100644
index 00000000000..28df93a1997
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18143.d
@@ -0,0 +1,43 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18143.d(20): Error: variable `fail18143.S.a` cannot modify parameter `this` in contract
+fail_compilation/fail18143.d(21): Error: variable `fail18143.S.a` cannot modify parameter `this` in contract
+fail_compilation/fail18143.d(25): Error: variable `fail18143.S.a` cannot modify parameter `this` in contract
+fail_compilation/fail18143.d(26): Error: variable `fail18143.S.a` cannot modify parameter `this` in contract
+fail_compilation/fail18143.d(35): Error: variable `fail18143.C.a` cannot modify parameter `this` in contract
+fail_compilation/fail18143.d(36): Error: variable `fail18143.C.a` cannot modify parameter `this` in contract
+fail_compilation/fail18143.d(40): Error: variable `fail18143.C.a` cannot modify parameter `this` in contract
+fail_compilation/fail18143.d(41): Error: variable `fail18143.C.a` cannot modify parameter `this` in contract
+---
+*/
+
+struct S
+{
+    int a;
+
+    this(int n)
+    in { a = n; }   // error, modifying this.a in contract
+    out { a = n; }  // error, modifying this.a in contract
+    do { }
+
+    void foo(int n)
+    in { a = n; }   // error, modifying this.a in contract
+    out { a = n; }  // error, modifying this.a in contract
+    do { }
+}
+
+class C
+{
+    int a;
+
+    this(int n)
+    in { a = n; }   // error, modifying this.a in contract
+    out { a = n; }  // error, modifying this.a in contract
+    do { }
+
+    void foo(int n)
+    in { a = n; }   // error, modifying this.a in contract
+    out { a = n; }  // error, modifying this.a in contract
+    do { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18719.d b/gcc/testsuite/gdc.test/fail_compilation/fail18719.d
new file mode 100644
index 00000000000..7d993d13485
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18719.d
@@ -0,0 +1,41 @@
+// https://issues.dlang.org/show_bug.cgi?id=18719
+
+// REQUIRED_ARGS:
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18719.d(30): Error: immutable field `x` initialized multiple times
+       Previous initialization is here.
+---
+*/
+
+struct S
+{
+    int x = -1;
+    this(int y) immutable
+    {
+        x = y;
+        import std.stdio;
+        writeln("Ctor called with ", y);
+    }
+    void opAssign(int) immutable;
+}
+
+class C
+{
+    S x;
+    this() immutable
+    {
+        this(42); /* Initializes x. */
+        x = 13; /* Breaking immutable, or ok? */
+    }
+    this(int x) immutable
+    {
+        this.x = x;
+    }
+}
+
+void main()
+{
+    new immutable C;
+}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index cd620c9c362..1d8f8dfb46d 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-38873fe6ee70fe8e2b7a41b7c3663e090e27d61b
+3dd5df6864b3849450d3657e219b90909663a513
 
 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/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index 326b5441724..0b11ed96745 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -39,6 +39,16 @@ version (unittest)
     initializeTests();
 }
 
+version (unittest) private bool clockSupported(ClockType c)
+{
+    // Skip unsupported clocks on older linux kernels, assume that only
+    // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
+    // common denominator supported by all versions of Linux pre-2.6.12.
+    version (Linux_Pre_2639)
+        return c == ClockType.normal || c == ClockType.precise;
+    else
+        return true;
+}
 
 /++
     Effectively a namespace to make it clear that the methods it contains are
@@ -95,10 +105,13 @@ public:
         foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
         {
             scope(failure) writefln("ClockType.%s", ct);
-            auto value1 = Clock.currTime!ct;
-            auto value2 = Clock.currTime!ct(UTC());
-            assert(value1 <= value2, format("%s %s", value1, value2));
-            assert(abs(value1 - value2) <= seconds(2));
+            static if (clockSupported(ct))
+            {
+                auto value1 = Clock.currTime!ct;
+                auto value2 = Clock.currTime!ct(UTC());
+                assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
+                assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
+            }
         }
     }
 
@@ -270,10 +283,13 @@ public:
         foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
         {
             scope(failure) writefln("ClockType.%s", ct);
-            auto value1 = Clock.currStdTime!ct;
-            auto value2 = Clock.currStdTime!ct;
-            assert(value1 <= value2, format("%s %s", value1, value2));
-            assert(abs(value1 - value2) <= limit);
+            static if (clockSupported(ct))
+            {
+                auto value1 = Clock.currStdTime!ct;
+                auto value2 = Clock.currStdTime!ct;
+                assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
+                assert(abs(value1 - value2) <= limit);
+            }
         }
     }
 
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 9ba992944eb..380ecfc2bcd 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -164,6 +164,16 @@ class FileException : Exception
      +/
     immutable uint errno;
 
+    private this(in char[] name, in char[] msg, string file, size_t line, uint errno) @safe pure
+    {
+        if (msg.empty)
+            super(name.idup, file, line);
+        else
+            super(text(name, ": ", msg), file, line);
+
+        this.errno = errno;
+    }
+
     /++
         Constructor which takes an error message.
 
@@ -175,12 +185,7 @@ class FileException : Exception
      +/
     this(in char[] name, in char[] msg, string file = __FILE__, size_t line = __LINE__) @safe pure
     {
-        if (msg.empty)
-            super(name.idup, file, line);
-        else
-            super(text(name, ": ", msg), file, line);
-
-        errno = 0;
+        this(name, msg, file, line, 0);
     }
 
     /++
@@ -200,8 +205,7 @@ class FileException : Exception
                           string file = __FILE__,
                           size_t line = __LINE__) @safe
     {
-        this(name, sysErrorString(errno), file, line);
-        this.errno = errno;
+        this(name, sysErrorString(errno), file, line, errno);
     }
     else version (Posix) this(in char[] name,
                              uint errno = .errno,
@@ -209,8 +213,7 @@ class FileException : Exception
                              size_t line = __LINE__) @trusted
     {
         import std.exception : errnoString;
-        this(name, errnoString(errno), file, line);
-        this.errno = errno;
+        this(name, errnoString(errno), file, line, errno);
     }
 }
 
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index 4c1ad0baa15..c59bc4c219b 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -37,48 +37,55 @@ else version (CRuntime_DigitalMars)
     // Specific to the way Digital Mars C does stdio
     version = DIGITAL_MARS_STDIO;
 }
-
-version (CRuntime_Glibc)
+else version (CRuntime_Glibc)
 {
     // Specific to the way Gnu C does stdio
     version = GCC_IO;
-    version = HAS_GETDELIM;
 }
 else version (CRuntime_Bionic)
 {
     version = GENERIC_IO;
-    version = HAS_GETDELIM;
 }
 else version (CRuntime_Musl)
 {
     version = GENERIC_IO;
-    version = HAS_GETDELIM;
 }
-
-version (OSX)
+else version (CRuntime_UClibc)
+{
+    // uClibc supports GCC IO
+    version = GCC_IO;
+}
+else version (OSX)
+{
+    version = GENERIC_IO;
+}
+else version (iOS)
+{
+    version = GENERIC_IO;
+}
+else version (TVOS)
+{
+    version = GENERIC_IO;
+}
+else version (WatchOS)
 {
     version = GENERIC_IO;
-    version = HAS_GETDELIM;
 }
 else version (FreeBSD)
 {
     version = GENERIC_IO;
-    version = HAS_GETDELIM;
 }
 else version (NetBSD)
 {
     version = GENERIC_IO;
-    version = HAS_GETDELIM;
 }
 else version (DragonFlyBSD)
 {
     version = GENERIC_IO;
-    version = HAS_GETDELIM;
 }
 else version (Solaris)
 {
     version = GENERIC_IO;
-    version = NO_GETDELIM;
 }
 
 // Character type used for operating system filesystem APIs
@@ -105,6 +112,11 @@ version (Windows)
     import core.sys.windows.windows : HANDLE;
 }
 
+version (Posix)
+{
+    static import core.sys.posix.stdio; // getdelim
+}
+
 version (DIGITAL_MARS_STDIO)
 {
     extern (C)
@@ -244,11 +256,19 @@ else
     static assert(0, "unsupported C I/O system");
 }
 
-version (HAS_GETDELIM) extern(C) nothrow @nogc
+static if (__traits(compiles, core.sys.posix.stdio.getdelim))
 {
-    ptrdiff_t getdelim(char**, size_t*, int, FILE*);
-    // getline() always comes together with getdelim()
-    ptrdiff_t getline(char**, size_t*, FILE*);
+    extern(C) nothrow @nogc
+    {
+        // @@@DEPRECATED_2.104@@@
+        deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getdelim instead.")
+        ptrdiff_t getdelim(char**, size_t*, int, FILE*);
+
+        // @@@DEPRECATED_2.104@@@
+        // getline() always comes together with getdelim()
+        deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getline instead.")
+        ptrdiff_t getline(char**, size_t*, FILE*);
+    }
 }
 
 //------------------------------------------------------------------------------
@@ -4718,59 +4738,142 @@ private struct ReadlnAppender
 }
 
 // Private implementation of readln
-version (DIGITAL_MARS_STDIO)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/)
+private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
 {
-    FLOCK(fps);
-    scope(exit) FUNLOCK(fps);
+    version (DIGITAL_MARS_STDIO)
+    {
+        FLOCK(fps);
+        scope(exit) FUNLOCK(fps);
 
-    /* Since fps is now locked, we can create an "unshared" version
-     * of fp.
-     */
-    auto fp = cast(_iobuf*) fps;
+        /* Since fps is now locked, we can create an "unshared" version
+         * of fp.
+         */
+        auto fp = cast(_iobuf*) fps;
 
-    ReadlnAppender app;
-    app.initialize(buf);
+        ReadlnAppender app;
+        app.initialize(buf);
 
-    if (__fhnd_info[fp._file] & FHND_WCHAR)
-    {   /* Stream is in wide characters.
-         * Read them and convert to chars.
-         */
-        static assert(wchar_t.sizeof == 2);
-        for (int c = void; (c = FGETWC(fp)) != -1; )
+        if (__fhnd_info[fp._file] & FHND_WCHAR)
+        {   /* Stream is in wide characters.
+             * Read them and convert to chars.
+             */
+            static assert(wchar_t.sizeof == 2);
+            for (int c = void; (c = FGETWC(fp)) != -1; )
+            {
+                if ((c & ~0x7F) == 0)
+                {
+                    app.putchar(cast(char) c);
+                    if (c == terminator)
+                        break;
+                }
+                else
+                {
+                    if (c >= 0xD800 && c <= 0xDBFF)
+                    {
+                        int c2 = void;
+                        if ((c2 = FGETWC(fp)) != -1 ||
+                                c2 < 0xDC00 && c2 > 0xDFFF)
+                        {
+                            StdioException("unpaired UTF-16 surrogate");
+                        }
+                        c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+                    }
+                    app.putdchar(cast(dchar) c);
+                }
+            }
+            if (ferror(fps))
+                StdioException();
+        }
+
+        else if (fp._flag & _IONBF)
         {
-            if ((c & ~0x7F) == 0)
+            /* Use this for unbuffered I/O, when running
+             * across buffer boundaries, or for any but the common
+             * cases.
+             */
+        L1:
+            int c;
+            while ((c = FGETC(fp)) != -1)
             {
                 app.putchar(cast(char) c);
                 if (c == terminator)
-                    break;
+                {
+                    buf = app.data;
+                    return buf.length;
+                }
+
             }
-            else
-            {
-                if (c >= 0xD800 && c <= 0xDBFF)
+
+            if (ferror(fps))
+                StdioException();
+        }
+        else
+        {
+            int u = fp._cnt;
+            char* p = fp._ptr;
+            int i;
+            if (fp._flag & _IOTRAN)
+            {   /* Translated mode ignores \r and treats ^Z as end-of-file
+                 */
+                char c;
+                while (1)
                 {
-                    int c2 = void;
-                    if ((c2 = FGETWC(fp)) != -1 ||
-                            c2 < 0xDC00 && c2 > 0xDFFF)
+                    if (i == u)         // if end of buffer
+                        goto L1;        // give up
+                    c = p[i];
+                    i++;
+                    if (c != '\r')
                     {
-                        StdioException("unpaired UTF-16 surrogate");
+                        if (c == terminator)
+                            break;
+                        if (c != 0x1A)
+                            continue;
+                        goto L1;
+                    }
+                    else
+                    {   if (i != u && p[i] == terminator)
+                            break;
+                        goto L1;
                     }
-                    c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
                 }
-                app.putdchar(cast(dchar) c);
+                app.putonly(p[0 .. i]);
+                app.buf[i - 1] = cast(char) terminator;
+                if (terminator == '\n' && c == '\r')
+                    i++;
             }
+            else
+            {
+                while (1)
+                {
+                    if (i == u)         // if end of buffer
+                        goto L1;        // give up
+                    auto c = p[i];
+                    i++;
+                    if (c == terminator)
+                        break;
+                }
+                app.putonly(p[0 .. i]);
+            }
+            fp._cnt -= i;
+            fp._ptr += i;
         }
-        if (ferror(fps))
-            StdioException();
-    }
 
-    else if (fp._flag & _IONBF)
+        buf = app.data;
+        return buf.length;
+    }
+    else version (MICROSOFT_STDIO)
     {
-        /* Use this for unbuffered I/O, when running
-         * across buffer boundaries, or for any but the common
-         * cases.
+        FLOCK(fps);
+        scope(exit) FUNLOCK(fps);
+
+        /* Since fps is now locked, we can create an "unshared" version
+         * of fp.
          */
-      L1:
+        auto fp = cast(_iobuf*) fps;
+
+        ReadlnAppender app;
+        app.initialize(buf);
+
         int c;
         while ((c = FGETC(fp)) != -1)
         {
@@ -4785,295 +4888,208 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
 
         if (ferror(fps))
             StdioException();
+        buf = app.data;
+        return buf.length;
     }
-    else
+    else static if (__traits(compiles, core.sys.posix.stdio.getdelim))
     {
-        int u = fp._cnt;
-        char* p = fp._ptr;
-        int i;
-        if (fp._flag & _IOTRAN)
-        {   /* Translated mode ignores \r and treats ^Z as end-of-file
+        import core.stdc.stdlib : free;
+        import core.stdc.wchar_ : fwide;
+
+        if (orientation == File.Orientation.wide)
+        {
+            /* Stream is in wide characters.
+             * Read them and convert to chars.
              */
-            char c;
-            while (1)
+            FLOCK(fps);
+            scope(exit) FUNLOCK(fps);
+            auto fp = cast(_iobuf*) fps;
+            version (Windows)
             {
-                if (i == u)         // if end of buffer
-                    goto L1;        // give up
-                c = p[i];
-                i++;
-                if (c != '\r')
+                buf.length = 0;
+                for (int c = void; (c = FGETWC(fp)) != -1; )
                 {
-                    if (c == terminator)
-                        break;
-                    if (c != 0x1A)
-                        continue;
-                    goto L1;
+                    if ((c & ~0x7F) == 0)
+                    {   buf ~= c;
+                        if (c == terminator)
+                            break;
+                    }
+                    else
+                    {
+                        if (c >= 0xD800 && c <= 0xDBFF)
+                        {
+                            int c2 = void;
+                            if ((c2 = FGETWC(fp)) != -1 ||
+                                    c2 < 0xDC00 && c2 > 0xDFFF)
+                            {
+                                StdioException("unpaired UTF-16 surrogate");
+                            }
+                            c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+                        }
+                        import std.utf : encode;
+                        encode(buf, c);
+                    }
                 }
-                else
-                {   if (i != u && p[i] == terminator)
+                if (ferror(fp))
+                    StdioException();
+                return buf.length;
+            }
+            else version (Posix)
+            {
+                buf.length = 0;
+                for (int c; (c = FGETWC(fp)) != -1; )
+                {
+                    import std.utf : encode;
+
+                    if ((c & ~0x7F) == 0)
+                        buf ~= cast(char) c;
+                    else
+                        encode(buf, cast(dchar) c);
+                    if (c == terminator)
                         break;
-                    goto L1;
                 }
+                if (ferror(fps))
+                    StdioException();
+                return buf.length;
+            }
+            else
+            {
+                static assert(0);
             }
-            app.putonly(p[0 .. i]);
-            app.buf[i - 1] = cast(char) terminator;
-            if (terminator == '\n' && c == '\r')
-                i++;
         }
-        else
+
+        static char *lineptr = null;
+        static size_t n = 0;
+        scope(exit)
         {
-            while (1)
+            if (n > 128 * 1024)
             {
-                if (i == u)         // if end of buffer
-                    goto L1;        // give up
-                auto c = p[i];
-                i++;
-                if (c == terminator)
-                    break;
+                // Bound memory used by readln
+                free(lineptr);
+                lineptr = null;
+                n = 0;
             }
-            app.putonly(p[0 .. i]);
         }
-        fp._cnt -= i;
-        fp._ptr += i;
-    }
-
-    buf = app.data;
-    return buf.length;
-}
-
-version (MICROSOFT_STDIO)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/)
-{
-    FLOCK(fps);
-    scope(exit) FUNLOCK(fps);
-
-    /* Since fps is now locked, we can create an "unshared" version
-     * of fp.
-     */
-    auto fp = cast(_iobuf*) fps;
-
-    ReadlnAppender app;
-    app.initialize(buf);
 
-    int c;
-    while ((c = FGETC(fp)) != -1)
-    {
-        app.putchar(cast(char) c);
-        if (c == terminator)
+        auto s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps);
+        if (s < 0)
         {
-            buf = app.data;
-            return buf.length;
+            if (ferror(fps))
+                StdioException();
+            buf.length = 0;                // end of file
+            return 0;
         }
 
+        if (s <= buf.length)
+        {
+            buf = buf[0 .. s];
+            buf[] = lineptr[0 .. s];
+        }
+        else
+        {
+            buf = lineptr[0 .. s].dup;
+        }
+        return s;
     }
-
-    if (ferror(fps))
-        StdioException();
-    buf = app.data;
-    return buf.length;
-}
-
-version (HAS_GETDELIM)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
-{
-    import core.stdc.stdlib : free;
-    import core.stdc.wchar_ : fwide;
-
-    if (orientation == File.Orientation.wide)
+    else // version (NO_GETDELIM)
     {
-        /* Stream is in wide characters.
-         * Read them and convert to chars.
-         */
+        import core.stdc.wchar_ : fwide;
+
         FLOCK(fps);
         scope(exit) FUNLOCK(fps);
         auto fp = cast(_iobuf*) fps;
-        version (Windows)
+        if (orientation == File.Orientation.wide)
         {
-            buf.length = 0;
-            for (int c = void; (c = FGETWC(fp)) != -1; )
+            /* Stream is in wide characters.
+             * Read them and convert to chars.
+             */
+            version (Windows)
             {
-                if ((c & ~0x7F) == 0)
-                {   buf ~= c;
-                    if (c == terminator)
-                        break;
-                }
-                else
+                buf.length = 0;
+                for (int c; (c = FGETWC(fp)) != -1; )
                 {
-                    if (c >= 0xD800 && c <= 0xDBFF)
+                    if ((c & ~0x7F) == 0)
+                    {   buf ~= c;
+                        if (c == terminator)
+                            break;
+                    }
+                    else
                     {
-                        int c2 = void;
-                        if ((c2 = FGETWC(fp)) != -1 ||
-                                c2 < 0xDC00 && c2 > 0xDFFF)
+                        if (c >= 0xD800 && c <= 0xDBFF)
                         {
-                            StdioException("unpaired UTF-16 surrogate");
+                            int c2 = void;
+                            if ((c2 = FGETWC(fp)) != -1 ||
+                                    c2 < 0xDC00 && c2 > 0xDFFF)
+                            {
+                                StdioException("unpaired UTF-16 surrogate");
+                            }
+                            c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
                         }
-                        c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+                        import std.utf : encode;
+                        encode(buf, c);
                     }
-                    import std.utf : encode;
-                    encode(buf, c);
                 }
+                if (ferror(fp))
+                    StdioException();
+                return buf.length;
             }
-            if (ferror(fp))
-                StdioException();
-            return buf.length;
-        }
-        else version (Posix)
-        {
-            buf.length = 0;
-            for (int c; (c = FGETWC(fp)) != -1; )
+            else version (Posix)
             {
                 import std.utf : encode;
-
-                if ((c & ~0x7F) == 0)
-                    buf ~= cast(char) c;
-                else
-                    encode(buf, cast(dchar) c);
-                if (c == terminator)
-                    break;
-            }
-            if (ferror(fps))
-                StdioException();
-            return buf.length;
-        }
-        else
-        {
-            static assert(0);
-        }
-    }
-
-    static char *lineptr = null;
-    static size_t n = 0;
-    scope(exit)
-    {
-        if (n > 128 * 1024)
-        {
-            // Bound memory used by readln
-            free(lineptr);
-            lineptr = null;
-            n = 0;
-        }
-    }
-
-    auto s = getdelim(&lineptr, &n, terminator, fps);
-    if (s < 0)
-    {
-        if (ferror(fps))
-            StdioException();
-        buf.length = 0;                // end of file
-        return 0;
-    }
-
-    if (s <= buf.length)
-    {
-        buf = buf[0 .. s];
-        buf[] = lineptr[0 .. s];
-    }
-    else
-    {
-        buf = lineptr[0 .. s].dup;
-    }
-    return s;
-}
-
-version (NO_GETDELIM)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
-{
-    import core.stdc.wchar_ : fwide;
-
-    FLOCK(fps);
-    scope(exit) FUNLOCK(fps);
-    auto fp = cast(_iobuf*) fps;
-    if (orientation == File.Orientation.wide)
-    {
-        /* Stream is in wide characters.
-         * Read them and convert to chars.
-         */
-        version (Windows)
-        {
-            buf.length = 0;
-            for (int c; (c = FGETWC(fp)) != -1; )
-            {
-                if ((c & ~0x7F) == 0)
-                {   buf ~= c;
+                buf.length = 0;
+                for (int c; (c = FGETWC(fp)) != -1; )
+                {
+                    if ((c & ~0x7F) == 0)
+                        buf ~= cast(char) c;
+                    else
+                        encode(buf, cast(dchar) c);
                     if (c == terminator)
                         break;
                 }
-                else
-                {
-                    if (c >= 0xD800 && c <= 0xDBFF)
-                    {
-                        int c2 = void;
-                        if ((c2 = FGETWC(fp)) != -1 ||
-                                c2 < 0xDC00 && c2 > 0xDFFF)
-                        {
-                            StdioException("unpaired UTF-16 surrogate");
-                        }
-                        c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
-                    }
-                    import std.utf : encode;
-                    encode(buf, c);
-                }
+                if (ferror(fps))
+                    StdioException();
+                return buf.length;
             }
-            if (ferror(fp))
-                StdioException();
-            return buf.length;
-        }
-        else version (Posix)
-        {
-            import std.utf : encode;
-            buf.length = 0;
-            for (int c; (c = FGETWC(fp)) != -1; )
+            else
             {
-                if ((c & ~0x7F) == 0)
-                    buf ~= cast(char) c;
-                else
-                    encode(buf, cast(dchar) c);
-                if (c == terminator)
-                    break;
+                static assert(0);
             }
-            if (ferror(fps))
-                StdioException();
-            return buf.length;
         }
-        else
-        {
-            static assert(0);
-        }
-    }
 
-    // Narrow stream
-    // First, fill the existing buffer
-    for (size_t bufPos = 0; bufPos < buf.length; )
-    {
-        immutable c = FGETC(fp);
-        if (c == -1)
-        {
-            buf.length = bufPos;
-            goto endGame;
-        }
-        buf[bufPos++] = cast(char) c;
-        if (c == terminator)
+        // Narrow stream
+        // First, fill the existing buffer
+        for (size_t bufPos = 0; bufPos < buf.length; )
         {
-            // No need to test for errors in file
-            buf.length = bufPos;
-            return bufPos;
+            immutable c = FGETC(fp);
+            if (c == -1)
+            {
+                buf.length = bufPos;
+                goto endGame;
+            }
+            buf[bufPos++] = cast(char) c;
+            if (c == terminator)
+            {
+                // No need to test for errors in file
+                buf.length = bufPos;
+                return bufPos;
+            }
         }
-    }
-    // Then, append to it
-    for (int c; (c = FGETC(fp)) != -1; )
-    {
-        buf ~= cast(char) c;
-        if (c == terminator)
+        // Then, append to it
+        for (int c; (c = FGETC(fp)) != -1; )
         {
-            // No need to test for errors in file
-            return buf.length;
+            buf ~= cast(char) c;
+            if (c == terminator)
+            {
+                // No need to test for errors in file
+                return buf.length;
+            }
         }
-    }
 
-  endGame:
-    if (ferror(fps))
-        StdioException();
-    return buf.length;
+    endGame:
+        if (ferror(fps))
+            StdioException();
+        return buf.length;
+    }
 }
 
 @system unittest
diff --git a/libphobos/testsuite/libphobos.phobos/phobos.exp b/libphobos/testsuite/libphobos.phobos/phobos.exp
index 46dea2bfad0..0975ab1f801 100644
--- a/libphobos/testsuite/libphobos.phobos/phobos.exp
+++ b/libphobos/testsuite/libphobos.phobos/phobos.exp
@@ -27,6 +27,12 @@ if { ![is-effective-target d_runtime_has_std_library] } {
 # Gather a list of all tests.
 set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]]
 
+set version_flags ""
+
+if { [is-effective-target linux_pre_2639] } {
+    lappend version_flags "-fversion=Linux_Pre_2639"
+}
+
 set libphobos_skip_tests {
     # Skip curl tests if library is not available
     { libphobos.phobos/etc/c/curl.d { ! libcurl_available } }
@@ -39,7 +45,7 @@ dg-init
 # Main loop.
 foreach test $tests {
     set libphobos_test_name "$subdir/[dg-trim-dirname $srcdir/../src $test]"
-    dg-runtest $test "" "-fmain -fbuilding-libphobos-tests"
+    dg-runtest $test "" "-fmain -fbuilding-libphobos-tests $version_flags"
     set libphobos_test_name ""
 }
 
diff --git a/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp b/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp
index 31c7cb29d98..da313044908 100644
--- a/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp
+++ b/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp
@@ -27,6 +27,12 @@ if { ![is-effective-target d_runtime_has_std_library] } {
 # Gather a list of all tests.
 set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]]
 
+set version_flags ""
+
+if { [is-effective-target linux_pre_2639] } {
+    lappend version_flags "-fversion=Linux_Pre_2639"
+}
+
 set libphobos_skip_tests {
     # Skip curl tests if library is not available
     { libphobos.phobos_shared/etc/c/curl.d { ! libcurl_available } }
@@ -40,7 +46,7 @@ dg-init
 foreach test $tests {
     set libphobos_test_name "$subdir/[dg-trim-dirname $srcdir/../src $test]"
     dg-runtest $test "-fversion=Shared -shared-libphobos" \
-	"-fmain -fbuilding-libphobos-tests -fno-moduleinfo"
+	"-fmain -fbuilding-libphobos-tests -fno-moduleinfo $version_flags"
     set libphobos_test_name ""
 }
 
-- 
2.27.0




More information about the Gcc-patches mailing list