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.
This commit is contained in:
Iain Buclaw 2021-01-25 13:50:55 +01:00
parent eb77a934ee
commit 5a36cae275
17 changed files with 504 additions and 332 deletions

View File

@ -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;
}

View File

@ -980,7 +980,6 @@ d_parse_file (void)
m->importedFrom = m;
m->parse ();
Compiler::loadModule (m);
if (m->isDocFile)
{

View File

@ -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.

View File

@ -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 *);
};

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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);

View File

@ -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()

View File

@ -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 { }
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
ReadlnAppender app;
app.initialize(buf);
if (__fhnd_info[fp._file] & FHND_WCHAR)
{ /* Stream is in wide characters.
* Read them and convert to chars.
/* Since fps is now locked, we can create an "unshared" version
* of fp.
*/
static assert(wchar_t.sizeof == 2);
for (int c = void; (c = FGETWC(fp)) != -1; )
auto fp = cast(_iobuf*) fps;
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 ((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;
}
}
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)
{
if (i == u) // if end of buffer
goto L1; // give up
c = p[i];
i++;
if (c != '\r')
{
if (c == terminator)
break;
if (c != 0x1A)
continue;
goto L1;
}
else
{ if (i != u && p[i] == terminator)
break;
goto L1;
}
}
app.putonly(p[0 .. i]);
app.buf[i - 1] = cast(char) terminator;
if (terminator == '\n' && c == '\r')
i++;
}
else
{
if (c >= 0xD800 && c <= 0xDBFF)
while (1)
{
int c2 = void;
if ((c2 = FGETWC(fp)) != -1 ||
c2 < 0xDC00 && c2 > 0xDFFF)
{
StdioException("unpaired UTF-16 surrogate");
}
c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
if (i == u) // if end of buffer
goto L1; // give up
auto c = p[i];
i++;
if (c == terminator)
break;
}
app.putdchar(cast(dchar) c);
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 & ~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);
}
}
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;
if (c != 0x1A)
continue;
goto L1;
}
else
{ if (i != u && p[i] == terminator)
break;
goto L1;
}
if (ferror(fps))
StdioException();
return buf.length;
}
app.putonly(p[0 .. i]);
app.buf[i - 1] = cast(char) terminator;
if (terminator == '\n' && c == '\r')
i++;
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 = core.sys.posix.stdio.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
{
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]);
buf = lineptr[0 .. s].dup;
}
fp._cnt -= i;
fp._ptr += i;
return s;
}
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)
else // version (NO_GETDELIM)
{
app.putchar(cast(char) c);
if (c == terminator)
{
buf = app.data;
return buf.length;
}
import core.stdc.wchar_ : fwide;
}
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)
{
/* Stream is in wide characters.
* Read them and convert to chars.
*/
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)
{
int c2 = void;
if ((c2 = FGETWC(fp)) != -1 ||
c2 < 0xDC00 && c2 > 0xDFFF)
{
StdioException("unpaired UTF-16 surrogate");
}
c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
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);
}
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)
// Narrow stream
// First, fill the existing buffer
for (size_t bufPos = 0; bufPos < buf.length; )
{
buf.length = bufPos;
goto endGame;
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;
}
}
buf[bufPos++] = 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
buf.length = bufPos;
return bufPos;
buf ~= cast(char) c;
if (c == terminator)
{
// No need to test for errors in file
return buf.length;
}
}
}
// Then, append to it
for (int c; (c = FGETC(fp)) != -1; )
{
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

View File

@ -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 ""
}

View File

@ -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 ""
}