From 5a36cae275ad84cc7e623f2f5829bdad767e3f6a Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 25 Jan 2021 13:50:55 +0100 Subject: [PATCH] d: Merge upstream dmd 609c3ce2d, phobos 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. Reviewed-on: https://github.com/dlang/dmd/pull/12153 https://github.com/dlang/phobos/pull/7768 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 +++++++++++---------- libphobos/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 881d482..3907d01 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 72dcb71..0fd207d 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 1f907b8..228eed8 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 124829b..7f9006c 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 includeModulePatterns; +extern Array 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 72a07d9b8..d20f663 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 305b133..95c263f 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 a4ff0b4..7cebd9a 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 f8f43dc..2f1d648 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 d4eccd8..633414b 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 0000000..28df93a --- /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 0000000..7d993d1 --- /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 cd620c9..1d8f8df 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 326b544..0b11ed9 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 9ba9929..380ecfc 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 4c1ad0b..c59bc4c 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 46dea2b..0975ab1 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 31c7cb2..da31304 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.7.4