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:
parent
eb77a934ee
commit
5a36cae275
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -980,7 +980,6 @@ d_parse_file (void)
|
|||
|
||||
m->importedFrom = m;
|
||||
m->parse ();
|
||||
Compiler::loadModule (m);
|
||||
|
||||
if (m->isDocFile)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 *);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 { }
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ""
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue