mirror of git://gcc.gnu.org/git/gcc.git
d: Merge upstream dmd, druntime 2bbf64907c, phobos b64bfbf91
D front-end changes:
- Import dmd v2.106.0.
D runtime changes:
- Import druntime v2.106.0.
Phobos changes:
- Import phobos v2.106.0.
gcc/d/ChangeLog:
* Make-lang.in (D_FRONTEND_OBJS): Rename d/common-string.o to
d/common-smallbuffer.o.
* dmd/MERGE: Merge upstream dmd 2bbf64907c.
* dmd/VERSION: Bump version to v2.106.0.
* modules.cc (layout_moduleinfo_fields): Update for new front-end
interface.
(layout_moduleinfo): Likewise.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 2bbf64907c.
* src/MERGE: Merge upstream phobos b64bfbf91.
This commit is contained in:
parent
63194a0e8e
commit
f9b4dbb8ac
|
|
@ -95,7 +95,7 @@ D_FRONTEND_OBJS = \
|
|||
d/common-bitfields.o \
|
||||
d/common-file.o \
|
||||
d/common-outbuffer.o \
|
||||
d/common-string.o \
|
||||
d/common-smallbuffer.o \
|
||||
d/compiler.o \
|
||||
d/cond.o \
|
||||
d/constfold.o \
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
ff57fec51558013b25cadb7e83da9f4675915d56
|
||||
2bbf64907cbbb483d003e0a8fcf8b502e4883799
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
v2.106.0-rc.1
|
||||
v2.106.0
|
||||
|
|
|
|||
|
|
@ -178,16 +178,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
|
|||
return sc2;
|
||||
}
|
||||
|
||||
override final void setScope(Scope* sc)
|
||||
{
|
||||
// Might need a scope to resolve forward references. The check for
|
||||
// semanticRun prevents unnecessary setting of _scope during deferred
|
||||
// setScope phases for aggregates which already finished semantic().
|
||||
// See https://issues.dlang.org/show_bug.cgi?id=16607
|
||||
if (semanticRun < PASS.semanticdone)
|
||||
ScopeDsymbol.setScope(sc);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Returns:
|
||||
* The total number of fields minus the number of hidden fields.
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ public:
|
|||
Sizeok sizeok; // set when structsize contains valid data
|
||||
|
||||
virtual Scope *newScope(Scope *sc);
|
||||
void setScope(Scope *sc) override final;
|
||||
virtual void finalizeSize() = 0;
|
||||
uinteger_t size(const Loc &loc) override final;
|
||||
bool fill(const Loc &loc, Expressions &elements, bool ctorinit);
|
||||
|
|
|
|||
|
|
@ -123,19 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
|
|||
return sc;
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
Dsymbols* d = include(sc);
|
||||
//printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
|
||||
if (d)
|
||||
{
|
||||
Scope* sc2 = newScope(sc);
|
||||
d.foreachDsymbol( s => s.setScope(sc2) );
|
||||
if (sc2 != sc)
|
||||
sc2.pop();
|
||||
}
|
||||
}
|
||||
|
||||
override void importAll(Scope* sc)
|
||||
{
|
||||
Dsymbols* d = include(sc);
|
||||
|
|
@ -338,14 +325,6 @@ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
|
|||
return scx;
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
//printf("DeprecatedDeclaration::setScope() %p\n", this);
|
||||
if (decl)
|
||||
Dsymbol.setScope(sc); // for forward reference
|
||||
return AttribDeclaration.setScope(sc);
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
|
|
@ -433,13 +412,6 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration
|
|||
sc.aligndecl, sc.inlining);
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
if (decl)
|
||||
Dsymbol.setScope(sc); // for forward reference
|
||||
return AttribDeclaration.setScope(sc);
|
||||
}
|
||||
|
||||
override const(char)* toChars() const
|
||||
{
|
||||
return toString().ptr;
|
||||
|
|
@ -703,13 +675,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
|
|||
return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
if (decl)
|
||||
Dsymbol.setScope(sc);
|
||||
return AttribDeclaration.setScope(sc);
|
||||
}
|
||||
|
||||
override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
|
||||
{
|
||||
//printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
|
||||
|
|
@ -913,11 +878,6 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
|
|||
}
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
include(sc).foreachDsymbol( s => s.setScope(sc) );
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
|
|
@ -983,13 +943,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
|
|||
}
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
// do not evaluate condition before semantic pass
|
||||
// But do set the scope, in case we need it for forward referencing
|
||||
Dsymbol.setScope(sc);
|
||||
}
|
||||
|
||||
override void importAll(Scope* sc)
|
||||
{
|
||||
// do not evaluate condition before semantic pass
|
||||
|
|
@ -1104,13 +1057,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
|
|||
// change this to give semantics to documentation comments on static foreach declarations
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
// do not evaluate condition before semantic pass
|
||||
// But do set the scope, in case we need it for forward referencing
|
||||
Dsymbol.setScope(sc);
|
||||
}
|
||||
|
||||
override void importAll(Scope* sc)
|
||||
{
|
||||
// do not evaluate aggregate before semantic pass
|
||||
|
|
@ -1209,11 +1155,6 @@ extern (C++) final class MixinDeclaration : AttribDeclaration
|
|||
return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps));
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
Dsymbol.setScope(sc);
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return "mixin";
|
||||
|
|
@ -1264,14 +1205,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
|
|||
return sc2;
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
//printf("UserAttributeDeclaration::setScope() %p\n", this);
|
||||
if (decl)
|
||||
Dsymbol.setScope(sc); // for forward reference of UDAs
|
||||
return AttribDeclaration.setScope(sc);
|
||||
}
|
||||
|
||||
extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
|
||||
{
|
||||
Expressions* udas;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ public:
|
|||
|
||||
virtual Dsymbols *include(Scope *sc);
|
||||
virtual Scope *newScope(Scope *sc);
|
||||
void setScope(Scope *sc) override;
|
||||
void importAll(Scope *sc) override;
|
||||
void addComment(const utf8_t *comment) override;
|
||||
const char *kind() const override;
|
||||
|
|
@ -61,7 +60,6 @@ public:
|
|||
|
||||
DeprecatedDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
Scope *newScope(Scope *sc) override;
|
||||
void setScope(Scope *sc) override;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
};
|
||||
|
||||
|
|
@ -84,7 +82,6 @@ public:
|
|||
|
||||
CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
Scope *newScope(Scope *sc) override;
|
||||
void setScope(Scope *sc) override;
|
||||
const char *toChars() const override;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
};
|
||||
|
|
@ -135,7 +132,6 @@ public:
|
|||
unsigned anonalignsize; // size of anonymous struct for alignment purposes
|
||||
|
||||
AnonDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
void setScope(Scope *sc) override;
|
||||
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
|
||||
const char *kind() const override;
|
||||
AnonDeclaration *isAnonDeclaration() override { return this; }
|
||||
|
|
@ -163,7 +159,6 @@ public:
|
|||
bool oneMember(Dsymbol **ps, Identifier *ident) override final;
|
||||
Dsymbols *include(Scope *sc) override;
|
||||
void addComment(const utf8_t *comment) override final;
|
||||
void setScope(Scope *sc) override;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
};
|
||||
|
||||
|
|
@ -176,7 +171,6 @@ public:
|
|||
|
||||
StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
Dsymbols *include(Scope *sc) override;
|
||||
void setScope(Scope *sc) override;
|
||||
void importAll(Scope *sc) override;
|
||||
StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
|
||||
const char *kind() const override;
|
||||
|
|
@ -196,7 +190,6 @@ public:
|
|||
bool oneMember(Dsymbol **ps, Identifier *ident) override;
|
||||
Dsymbols *include(Scope *sc) override;
|
||||
void addComment(const utf8_t *comment) override;
|
||||
void setScope(Scope *sc) override;
|
||||
void importAll(Scope *sc) override;
|
||||
const char *kind() const override;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
|
|
@ -223,7 +216,6 @@ public:
|
|||
d_bool compiled;
|
||||
|
||||
MixinDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
void setScope(Scope *sc) override;
|
||||
const char *kind() const override;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
};
|
||||
|
|
@ -239,7 +231,6 @@ public:
|
|||
|
||||
UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
Scope *newScope(Scope *sc) override;
|
||||
void setScope(Scope *sc) override;
|
||||
Expressions *getAttributes();
|
||||
const char *kind() const override;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import dmd.declaration;
|
|||
import dmd.dsymbol;
|
||||
import dmd.errorsink;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.init;
|
||||
|
|
@ -81,6 +80,7 @@ CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink)
|
|||
if (!f.isDtorDeclaration())
|
||||
errorSupplementalInferredAttr(f, 10, false, STC.nothrow_);
|
||||
|
||||
import dmd.expressionsem : checkOverriddenDtor;
|
||||
f.checkOverriddenDtor(null, e.loc, dd => dd.type.toTypeFunction().isnothrow, "not nothrow");
|
||||
}
|
||||
else if (func)
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@
|
|||
| [bitfields.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields |
|
||||
| [file.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management |
|
||||
| [outbuffer.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data |
|
||||
| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/string.d) | Common string functions including filename manipulation |
|
||||
| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/smallbuffer.d) | Common string functions including filename manipulation |
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ module dmd.common.file;
|
|||
import core.stdc.errno : errno;
|
||||
import core.stdc.stdio : fprintf, remove, rename, stderr;
|
||||
import core.stdc.stdlib : exit;
|
||||
import core.stdc.string : strerror;
|
||||
import core.stdc.string : strerror, strlen;
|
||||
import core.sys.windows.winbase;
|
||||
import core.sys.windows.winnt;
|
||||
import core.sys.posix.fcntl;
|
||||
import core.sys.posix.unistd;
|
||||
|
||||
import dmd.common.string;
|
||||
import dmd.common.smallbuffer;
|
||||
|
||||
nothrow:
|
||||
|
||||
|
|
@ -129,7 +129,8 @@ struct FileMapping(Datum)
|
|||
enum openFlags = CREATE_ALWAYS;
|
||||
}
|
||||
|
||||
handle = filename.asDString.extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null));
|
||||
handle = filename[0 .. strlen(filename)].
|
||||
extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null));
|
||||
if (handle == invalidHandle)
|
||||
{
|
||||
static if (is(Datum == const))
|
||||
|
|
@ -312,7 +313,7 @@ struct FileMapping(Datum)
|
|||
else version(Windows)
|
||||
{
|
||||
import core.sys.windows.winbase;
|
||||
if (deleteme.asDString.extendedPathThen!(p => DeleteFileW(p.ptr)) == 0)
|
||||
if (deleteme[0 .. strlen(deleteme)].extendedPathThen!(p => DeleteFileW(p.ptr)) == 0)
|
||||
{
|
||||
fprintf(stderr, "DeleteFileW error %d\n", GetLastError());
|
||||
return false;
|
||||
|
|
@ -447,8 +448,8 @@ struct FileMapping(Datum)
|
|||
else version(Windows)
|
||||
{
|
||||
import core.sys.windows.winbase;
|
||||
auto r = oldname.asDString.extendedPathThen!(
|
||||
p1 => filename.asDString.extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING))
|
||||
auto r = oldname[0 .. strlen(oldname)].extendedPathThen!(
|
||||
p1 => filename[0 .. strlen(filename)].extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING))
|
||||
);
|
||||
if (r == 0)
|
||||
{
|
||||
|
|
@ -483,7 +484,7 @@ extern(D) static bool writeFile(const(char)* name, const void[] data) nothrow
|
|||
else version (Windows)
|
||||
{
|
||||
DWORD numwritten; // here because of the gotos
|
||||
const nameStr = name.asDString;
|
||||
const nameStr = name[0 .. strlen(name)];
|
||||
// work around Windows file path length limitation
|
||||
// (see documentation for extendedPathThen).
|
||||
HANDLE h = nameStr.extendedPathThen!
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
* Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: Walter Bright, https://www.digitalmars.com
|
||||
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d, common/_string.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_common_string.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/string.d
|
||||
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/smallbuffer.d, common/_smallbuffer.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_common_smallbuffer.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/smallbuffer
|
||||
*/
|
||||
module dmd.common.string;
|
||||
module dmd.common.smallbuffer;
|
||||
|
||||
nothrow:
|
||||
|
||||
|
|
@ -106,34 +106,12 @@ unittest
|
|||
assert(b[] !is buf[]);
|
||||
}
|
||||
|
||||
/**
|
||||
Converts a zero-terminated C string to a D slice. Takes linear time and allocates no memory.
|
||||
|
||||
Params:
|
||||
stringz = the C string to be converted
|
||||
|
||||
Returns:
|
||||
a slice comprehending the string. The terminating 0 is not part of the slice.
|
||||
*/
|
||||
auto asDString(C)(C* stringz) pure @nogc nothrow
|
||||
{
|
||||
import core.stdc.string : strlen;
|
||||
return stringz[0 .. strlen(stringz)];
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
const char* p = "123".ptr;
|
||||
assert(p.asDString == "123");
|
||||
}
|
||||
|
||||
/**
|
||||
(Windows only) Converts a narrow string to a wide string using `buffer` as strorage. Returns a slice managed by
|
||||
`buffer` containing the converted string. The terminating zero is not part of the returned slice,
|
||||
but is guaranteed to follow it.
|
||||
*/
|
||||
version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow
|
||||
version(Windows) wchar[] toWStringz(scope const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow
|
||||
{
|
||||
import core.sys.windows.winnls : MultiByteToWideChar;
|
||||
import dmd.common.file : CodePage;
|
||||
|
|
@ -141,16 +119,17 @@ version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar
|
|||
if (narrow is null)
|
||||
return null;
|
||||
|
||||
const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
|
||||
if (requiredLength < cast(int) buffer.length)
|
||||
size_t length;
|
||||
int i;
|
||||
while (1)
|
||||
{
|
||||
buffer[requiredLength] = 0;
|
||||
return buffer[0 .. requiredLength];
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar
|
||||
length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
|
||||
if (length < buffer.length)
|
||||
break;
|
||||
buffer.create(length + 1);
|
||||
assert(++i == 1); // ensure loop should only execute once or twice
|
||||
}
|
||||
|
||||
buffer.create(requiredLength + 1);
|
||||
const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, requiredLength);
|
||||
assert(length == requiredLength);
|
||||
buffer[length] = 0;
|
||||
return buffer[0 .. length];
|
||||
}
|
||||
|
|
@ -1890,6 +1890,14 @@ final class CParser(AST) : Parser!AST
|
|||
if (specifier.alignExps)
|
||||
error("no alignment-specifier for typedef declaration"); // C11 6.7.5-2
|
||||
|
||||
if (specifier.vector_size)
|
||||
{
|
||||
auto length = new AST.IntegerExp(token.loc, specifier.vector_size / dt.size(), AST.Type.tuns32);
|
||||
auto tsa = new AST.TypeSArray(dt, length);
|
||||
dt = new AST.TypeVector(tsa);
|
||||
specifier.vector_size = 0; // used it up
|
||||
}
|
||||
|
||||
bool isalias = true;
|
||||
if (auto ts = dt.isTypeStruct())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
|
|||
Expression visit(Expression e)
|
||||
{
|
||||
// printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
|
||||
|
||||
if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
|
||||
{
|
||||
// no need for an extra cast when matching is exact
|
||||
|
|
@ -802,8 +801,8 @@ extern(C++) MATCH implicitConvTo(Expression e, Type t)
|
|||
|
||||
return result;
|
||||
}
|
||||
else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
|
||||
{
|
||||
else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer))
|
||||
{ // Tpointer because ImportC eagerly converts Tsarray to Tpointer
|
||||
result = MATCH.exact;
|
||||
// Convert array literal to vector type
|
||||
TypeVector tv = tb.isTypeVector();
|
||||
|
|
@ -1487,6 +1486,10 @@ MATCH cimplicitConvTo(Expression e, Type t)
|
|||
|
||||
if (tb.equals(typeb))
|
||||
return MATCH.exact;
|
||||
|
||||
if (tb.isTypeVector() || typeb.isTypeVector())
|
||||
return implicitConvTo(e, t); // permissive checking doesn't apply to vectors
|
||||
|
||||
if ((typeb.isintegral() || typeb.isfloating()) &&
|
||||
(tb.isintegral() || tb.isfloating()))
|
||||
return MATCH.convert;
|
||||
|
|
@ -2298,9 +2301,10 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
|
|||
ae.type = tp;
|
||||
}
|
||||
}
|
||||
else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
|
||||
else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer))
|
||||
{
|
||||
// Convert array literal to vector type
|
||||
// The Tpointer case comes from C eagerly converting Tsarray to Tpointer
|
||||
TypeVector tv = tb.isTypeVector();
|
||||
TypeSArray tbase = tv.basetype.isTypeSArray();
|
||||
assert(tbase.ty == Tsarray);
|
||||
|
|
|
|||
|
|
@ -83,13 +83,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
|
|||
return ed;
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
if (semanticRun > PASS.initial)
|
||||
return;
|
||||
ScopeDsymbol.setScope(sc);
|
||||
}
|
||||
|
||||
override bool oneMember(Dsymbol* ps, Identifier ident)
|
||||
{
|
||||
if (isAnonymous())
|
||||
|
|
|
|||
|
|
@ -305,22 +305,6 @@ extern (C++) final class Import : Dsymbol
|
|||
return this;
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
Dsymbol.setScope(sc);
|
||||
if (aliasdecls.length)
|
||||
{
|
||||
if (!mod)
|
||||
importAll(sc);
|
||||
|
||||
sc = sc.push(mod);
|
||||
sc.visibility = visibility;
|
||||
foreach (ad; aliasdecls)
|
||||
ad.setScope(sc);
|
||||
sc = sc.pop();
|
||||
}
|
||||
}
|
||||
|
||||
override bool overloadInsert(Dsymbol s)
|
||||
{
|
||||
/* Allow multiple imports with the same package base, but disallow
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import dmd.errorsink;
|
|||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.file_manager;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
|
|
@ -969,7 +970,7 @@ extern (C++) final class Module : Package
|
|||
* If this works out well, it can be extended to all modules
|
||||
* before any semantic() on any of them.
|
||||
*/
|
||||
setScope(sc); // remember module scope for semantic
|
||||
this.setScope(sc); // remember module scope for semantic
|
||||
for (size_t i = 0; i < members.length; i++)
|
||||
{
|
||||
Dsymbol s = (*members)[i];
|
||||
|
|
@ -1576,3 +1577,36 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Look for member of the form:
|
||||
* const(MemberInfo)[] getMembers(string);
|
||||
* Returns NULL if not found
|
||||
*/
|
||||
extern(C++) FuncDeclaration findGetMembers(ScopeDsymbol dsym)
|
||||
{
|
||||
import dmd.opover : search_function;
|
||||
Dsymbol s = search_function(dsym, Id.getmembers);
|
||||
FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
|
||||
version (none)
|
||||
{
|
||||
// Finish
|
||||
__gshared TypeFunction tfgetmembers;
|
||||
if (!tfgetmembers)
|
||||
{
|
||||
Scope sc;
|
||||
sc.eSink = global.errorSink;
|
||||
auto parameters = new Parameters();
|
||||
Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
|
||||
parameters.push(p);
|
||||
Type tret = null;
|
||||
TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
|
||||
tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction();
|
||||
}
|
||||
if (fdx)
|
||||
fdx = fdx.overloadExactMatch(tfgetmembers);
|
||||
}
|
||||
if (fdx && fdx.isVirtual())
|
||||
fdx = null;
|
||||
return fdx;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import dmd.dmodule;
|
|||
import dmd.dversion;
|
||||
import dmd.dscope;
|
||||
import dmd.dstruct;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
import dmd.errors;
|
||||
import dmd.expression;
|
||||
|
|
@ -44,11 +43,9 @@ import dmd.lexer;
|
|||
import dmd.location;
|
||||
import dmd.mtype;
|
||||
import dmd.nspace;
|
||||
import dmd.opover;
|
||||
import dmd.root.aav;
|
||||
import dmd.root.rmem;
|
||||
import dmd.rootobject;
|
||||
import dmd.root.speller;
|
||||
import dmd.root.string;
|
||||
import dmd.statement;
|
||||
import dmd.staticassert;
|
||||
|
|
@ -386,40 +383,6 @@ extern (C++) class Dsymbol : ASTNode
|
|||
return '`' ~ cstr.toDString() ~ "`\0";
|
||||
}
|
||||
|
||||
final bool checkDeprecated(const ref Loc loc, Scope* sc)
|
||||
{
|
||||
if (global.params.useDeprecated == DiagnosticReporting.off)
|
||||
return false;
|
||||
if (!this.isDeprecated())
|
||||
return false;
|
||||
// Don't complain if we're inside a deprecated symbol's scope
|
||||
if (sc.isDeprecated())
|
||||
return false;
|
||||
// Don't complain if we're inside a template constraint
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21831
|
||||
if (sc.flags & SCOPE.constraint)
|
||||
return false;
|
||||
|
||||
const(char)* message = null;
|
||||
for (Dsymbol p = this; p; p = p.parent)
|
||||
{
|
||||
message = p.depdecl ? p.depdecl.getMessage() : null;
|
||||
if (message)
|
||||
break;
|
||||
}
|
||||
if (message)
|
||||
deprecation(loc, "%s `%s` is deprecated - %s", kind, toPrettyChars, message);
|
||||
else
|
||||
deprecation(loc, "%s `%s` is deprecated", kind, toPrettyChars);
|
||||
|
||||
if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
|
||||
ti.printInstantiationTrace(Classification.deprecation);
|
||||
else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null)
|
||||
ti.printInstantiationTrace(Classification.deprecation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Determine which Module a Dsymbol is in.
|
||||
*/
|
||||
|
|
@ -749,113 +712,10 @@ extern (C++) class Dsymbol : ASTNode
|
|||
return toAlias();
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Set scope for future semantic analysis so we can
|
||||
* deal better with forward references.
|
||||
*/
|
||||
void setScope(Scope* sc)
|
||||
{
|
||||
//printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
|
||||
if (!sc.nofree)
|
||||
sc.setNoFree(); // may need it even after semantic() finishes
|
||||
_scope = sc;
|
||||
if (sc.depdecl)
|
||||
depdecl = sc.depdecl;
|
||||
if (!userAttribDecl)
|
||||
userAttribDecl = sc.userAttribDecl;
|
||||
}
|
||||
|
||||
void importAll(Scope* sc)
|
||||
{
|
||||
}
|
||||
|
||||
extern (D) final Dsymbol search_correct(Identifier ident)
|
||||
{
|
||||
/***************************************************
|
||||
* Search for symbol with correct spelling.
|
||||
*/
|
||||
extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost)
|
||||
{
|
||||
/* If not in the lexer's string table, it certainly isn't in the symbol table.
|
||||
* Doing this first is a lot faster.
|
||||
*/
|
||||
if (!seed.length)
|
||||
return null;
|
||||
Identifier id = Identifier.lookup(seed);
|
||||
if (!id)
|
||||
return null;
|
||||
cost = 0; // all the same cost
|
||||
Dsymbol s = this;
|
||||
Module.clearCache();
|
||||
return s.search(Loc.initial, id, IgnoreErrors);
|
||||
}
|
||||
|
||||
if (global.gag)
|
||||
return null; // don't do it for speculative compiles; too time consuming
|
||||
// search for exact name first
|
||||
if (auto s = this.search(Loc.initial, ident, IgnoreErrors))
|
||||
return s;
|
||||
return speller!symbol_search_fp(ident.toString());
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Search for identifier id as a member of `this`.
|
||||
* `id` may be a template instance.
|
||||
*
|
||||
* Params:
|
||||
* loc = location to print the error messages
|
||||
* sc = the scope where the symbol is located
|
||||
* id = the id of the symbol
|
||||
* flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
|
||||
*
|
||||
* Returns:
|
||||
* symbol found, NULL if not
|
||||
*/
|
||||
extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags)
|
||||
{
|
||||
//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
|
||||
Dsymbol s = toAlias();
|
||||
Dsymbol sm;
|
||||
if (Declaration d = s.isDeclaration())
|
||||
{
|
||||
if (d.inuse)
|
||||
{
|
||||
.error(loc, "circular reference to `%s`", d.toPrettyChars());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
switch (id.dyncast())
|
||||
{
|
||||
case DYNCAST.identifier:
|
||||
sm = s.search(loc, cast(Identifier)id, flags);
|
||||
break;
|
||||
case DYNCAST.dsymbol:
|
||||
{
|
||||
// It's a template instance
|
||||
//printf("\ttemplate instance id\n");
|
||||
Dsymbol st = cast(Dsymbol)id;
|
||||
TemplateInstance ti = st.isTemplateInstance();
|
||||
sm = s.search(loc, ti.name);
|
||||
if (!sm)
|
||||
return null;
|
||||
sm = sm.toAlias();
|
||||
TemplateDeclaration td = sm.isTemplateDeclaration();
|
||||
if (!td)
|
||||
return null; // error but handled later
|
||||
ti.tempdecl = td;
|
||||
if (!ti.semanticRun)
|
||||
ti.dsymbolSemantic(sc);
|
||||
sm = ti.toAlias();
|
||||
break;
|
||||
}
|
||||
case DYNCAST.type:
|
||||
case DYNCAST.expression:
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return sm;
|
||||
}
|
||||
|
||||
bool overloadInsert(Dsymbol s)
|
||||
{
|
||||
//printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
|
||||
|
|
@ -1468,38 +1328,6 @@ public:
|
|||
return "ScopeDsymbol";
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Look for member of the form:
|
||||
* const(MemberInfo)[] getMembers(string);
|
||||
* Returns NULL if not found
|
||||
*/
|
||||
final FuncDeclaration findGetMembers()
|
||||
{
|
||||
Dsymbol s = search_function(this, Id.getmembers);
|
||||
FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
|
||||
version (none)
|
||||
{
|
||||
// Finish
|
||||
__gshared TypeFunction tfgetmembers;
|
||||
if (!tfgetmembers)
|
||||
{
|
||||
Scope sc;
|
||||
sc.eSink = global.errorSink;
|
||||
auto parameters = new Parameters();
|
||||
Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
|
||||
parameters.push(p);
|
||||
Type tret = null;
|
||||
TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
|
||||
tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction();
|
||||
}
|
||||
if (fdx)
|
||||
fdx = fdx.overloadExactMatch(tfgetmembers);
|
||||
}
|
||||
if (fdx && fdx.isVirtual())
|
||||
fdx = null;
|
||||
return fdx;
|
||||
}
|
||||
|
||||
/********************************
|
||||
* Insert Dsymbol in table.
|
||||
* Params:
|
||||
|
|
|
|||
|
|
@ -205,7 +205,6 @@ public:
|
|||
const char *locToChars();
|
||||
bool equals(const RootObject * const o) const override;
|
||||
bool isAnonymous() const;
|
||||
bool checkDeprecated(const Loc &loc, Scope *sc);
|
||||
Module *getModule();
|
||||
bool isCsymbol();
|
||||
Module *getAccessModule();
|
||||
|
|
@ -228,7 +227,6 @@ public:
|
|||
virtual const char *kind() const;
|
||||
virtual Dsymbol *toAlias(); // resolve real symbol
|
||||
virtual Dsymbol *toAlias2();
|
||||
virtual void setScope(Scope *sc);
|
||||
virtual void importAll(Scope *sc);
|
||||
virtual bool overloadInsert(Dsymbol *s);
|
||||
virtual uinteger_t size(const Loc &loc);
|
||||
|
|
@ -342,7 +340,6 @@ public:
|
|||
bool isforwardRef() override final;
|
||||
static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2);
|
||||
const char *kind() const override;
|
||||
FuncDeclaration *findGetMembers();
|
||||
virtual Dsymbol *symtabInsert(Dsymbol *s);
|
||||
virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
|
||||
bool hasStaticCtorOrDtor() override;
|
||||
|
|
@ -431,3 +428,5 @@ public:
|
|||
|
||||
void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
|
||||
Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
|
||||
bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc);
|
||||
void setScope(Dsymbol *d, Scope *sc);
|
||||
|
|
|
|||
|
|
@ -212,6 +212,39 @@ const(char)* getMessage(DeprecatedDeclaration dd)
|
|||
return dd.msgstr;
|
||||
}
|
||||
|
||||
bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
|
||||
{
|
||||
if (global.params.useDeprecated == DiagnosticReporting.off)
|
||||
return false;
|
||||
if (!d.isDeprecated())
|
||||
return false;
|
||||
// Don't complain if we're inside a deprecated symbol's scope
|
||||
if (sc.isDeprecated())
|
||||
return false;
|
||||
// Don't complain if we're inside a template constraint
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21831
|
||||
if (sc.flags & SCOPE.constraint)
|
||||
return false;
|
||||
|
||||
const(char)* message = null;
|
||||
for (Dsymbol p = d; p; p = p.parent)
|
||||
{
|
||||
message = p.depdecl ? p.depdecl.getMessage() : null;
|
||||
if (message)
|
||||
break;
|
||||
}
|
||||
if (message)
|
||||
deprecation(loc, "%s `%s` is deprecated - %s", d.kind, d.toPrettyChars, message);
|
||||
else
|
||||
deprecation(loc, "%s `%s` is deprecated", d.kind, d.toPrettyChars);
|
||||
|
||||
if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
|
||||
ti.printInstantiationTrace(Classification.deprecation);
|
||||
else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null)
|
||||
ti.printInstantiationTrace(Classification.deprecation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if a contract can appear without a function body.
|
||||
package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
|
||||
|
|
@ -7811,6 +7844,37 @@ extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int f
|
|||
return v.result;
|
||||
}
|
||||
|
||||
Dsymbol search_correct(Dsymbol d, Identifier ident)
|
||||
{
|
||||
/***************************************************
|
||||
* Search for symbol with correct spelling.
|
||||
*/
|
||||
Dsymbol symbol_search_fp(const(char)[] seed, out int cost)
|
||||
{
|
||||
/* If not in the lexer's string table, it certainly isn't in the symbol table.
|
||||
* Doing this first is a lot faster.
|
||||
*/
|
||||
if (!seed.length)
|
||||
return null;
|
||||
Identifier id = Identifier.lookup(seed);
|
||||
if (!id)
|
||||
return null;
|
||||
cost = 0; // all the same cost
|
||||
Dsymbol s = d;
|
||||
Module.clearCache();
|
||||
return s.search(Loc.initial, id, IgnoreErrors);
|
||||
}
|
||||
|
||||
if (global.gag)
|
||||
return null; // don't do it for speculative compiles; too time consuming
|
||||
// search for exact name first
|
||||
if (auto s = d.search(Loc.initial, ident, IgnoreErrors))
|
||||
return s;
|
||||
|
||||
import dmd.root.speller : speller;
|
||||
return speller!symbol_search_fp(ident.toString());
|
||||
}
|
||||
|
||||
private extern(C++) class SearchVisitor : Visitor
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
|
|
@ -8407,3 +8471,153 @@ private extern(C++) class SearchVisitor : Visitor
|
|||
return setResult(s);
|
||||
}
|
||||
}
|
||||
/*************************************
|
||||
* Set scope for future semantic analysis so we can
|
||||
* deal better with forward references.
|
||||
*
|
||||
* Params:
|
||||
* d = dsymbol for which the scope is set
|
||||
* sc = scope that is used to set the value
|
||||
*/
|
||||
extern(C++) void setScope(Dsymbol d, Scope* sc)
|
||||
{
|
||||
scope setScopeVisitor = new SetScopeVisitor(sc);
|
||||
d.accept(setScopeVisitor);
|
||||
}
|
||||
|
||||
private extern(C++) class SetScopeVisitor : Visitor
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
Scope* sc;
|
||||
|
||||
this(Scope* sc)
|
||||
{
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
override void visit(Dsymbol d)
|
||||
{
|
||||
//printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", d, d.toChars(), sc, sc.stc);
|
||||
if (!sc.nofree)
|
||||
sc.setNoFree(); // may need it even after semantic() finishes
|
||||
d._scope = sc;
|
||||
if (sc.depdecl)
|
||||
d.depdecl = sc.depdecl;
|
||||
if (!d.userAttribDecl)
|
||||
d.userAttribDecl = sc.userAttribDecl;
|
||||
}
|
||||
|
||||
override void visit(Import i)
|
||||
{
|
||||
visit(cast(Dsymbol)i);
|
||||
if (i.aliasdecls.length)
|
||||
{
|
||||
if (!i.mod)
|
||||
i.importAll(sc);
|
||||
|
||||
sc = sc.push(i.mod);
|
||||
sc.visibility = i.visibility;
|
||||
foreach (ad; i.aliasdecls)
|
||||
ad.setScope(sc);
|
||||
sc = sc.pop();
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(Nspace ns)
|
||||
{
|
||||
visit(cast(Dsymbol)ns);
|
||||
if (ns.members)
|
||||
{
|
||||
assert(sc);
|
||||
sc = sc.push(ns);
|
||||
sc.linkage = LINK.cpp; // namespaces default to C++ linkage
|
||||
sc.parent = ns;
|
||||
ns.members.foreachDsymbol(s => s.setScope(sc));
|
||||
sc.pop();
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(EnumDeclaration ed)
|
||||
{
|
||||
if (ed.semanticRun > PASS.initial)
|
||||
return;
|
||||
visit(cast(Dsymbol)ed);
|
||||
}
|
||||
|
||||
override void visit(AggregateDeclaration ad)
|
||||
{
|
||||
// Might need a scope to resolve forward references. The check for
|
||||
// semanticRun prevents unnecessary setting of _scope during deferred
|
||||
// setScope phases for aggregates which already finished semantic().
|
||||
// See https://issues.dlang.org/show_bug.cgi?id=16607
|
||||
if (ad.semanticRun < PASS.semanticdone)
|
||||
visit(cast(Dsymbol)ad);
|
||||
}
|
||||
|
||||
override void visit(AttribDeclaration atr)
|
||||
{
|
||||
Dsymbols* d = atr.include(sc);
|
||||
//printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
|
||||
if (d)
|
||||
{
|
||||
Scope* sc2 = atr.newScope(sc);
|
||||
d.foreachDsymbol( s => s.setScope(sc2) );
|
||||
if (sc2 != sc)
|
||||
sc2.pop();
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(DeprecatedDeclaration dd)
|
||||
{
|
||||
//printf("DeprecatedDeclaration::setScope() %p\n", this);
|
||||
if (dd.decl)
|
||||
visit(cast(Dsymbol)dd); // for forward reference
|
||||
visit(cast(AttribDeclaration)dd);
|
||||
}
|
||||
|
||||
override void visit(CPPMangleDeclaration cppmd)
|
||||
{
|
||||
if (cppmd.decl)
|
||||
visit(cast(Dsymbol)cppmd); // for forward reference
|
||||
visit(cast(AttribDeclaration)cppmd);
|
||||
}
|
||||
|
||||
override void visit(AnonDeclaration anond)
|
||||
{
|
||||
if (anond.decl)
|
||||
visit(cast(Dsymbol)anond); // for forward reference
|
||||
visit(cast(AttribDeclaration)anond);
|
||||
}
|
||||
|
||||
override void visit(ConditionalDeclaration condd)
|
||||
{
|
||||
condd.include(sc).foreachDsymbol( s => s.setScope(sc) );
|
||||
}
|
||||
|
||||
override void visit(StaticIfDeclaration sid)
|
||||
{
|
||||
// do not evaluate condition before semantic pass
|
||||
// But do set the scope, in case we need it for forward referencing
|
||||
visit(cast(Dsymbol)sid); // for forward reference
|
||||
}
|
||||
|
||||
override void visit(StaticForeachDeclaration sfd)
|
||||
{
|
||||
// do not evaluate condition before semantic pass
|
||||
// But do set the scope, in case we need it for forward referencing
|
||||
visit(cast(Dsymbol)sfd); // for forward reference
|
||||
}
|
||||
|
||||
override void visit(MixinDeclaration md)
|
||||
{
|
||||
visit(cast(Dsymbol)md);
|
||||
}
|
||||
|
||||
override void visit(UserAttributeDeclaration uad)
|
||||
{
|
||||
//printf("UserAttributeDeclaration::setScope() %p\n", this);
|
||||
if (uad.decl)
|
||||
visit(cast(Dsymbol)uad);
|
||||
visit(cast(AttribDeclaration)uad);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7515,7 +7515,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
|||
}
|
||||
//printf("\t-. mi = %s\n", mi.toPrettyChars());
|
||||
|
||||
assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module");
|
||||
if (memberOf) // already appended to some module
|
||||
{
|
||||
assert(mi.isRoot(), "can only re-append to a root module");
|
||||
if (memberOf.isRoot())
|
||||
return null; // no need to move to another root module
|
||||
}
|
||||
|
||||
Dsymbols* a = mi.members;
|
||||
a.push(this);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ public:
|
|||
bool inuse(bool v);
|
||||
|
||||
EnumDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
void setScope(Scope *sc) override;
|
||||
bool oneMember(Dsymbol **ps, Identifier *ident) override;
|
||||
Type *getType() override;
|
||||
const char *kind() const override;
|
||||
|
|
|
|||
|
|
@ -2343,7 +2343,7 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
|
|||
VarDeclaration[10] tmp = void;
|
||||
size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.length : 0);
|
||||
|
||||
import dmd.common.string : SmallBuffer;
|
||||
import dmd.common.smallbuffer : SmallBuffer;
|
||||
auto sb = SmallBuffer!VarDeclaration(dim, tmp[]);
|
||||
VarDeclaration[] array = sb[];
|
||||
|
||||
|
|
|
|||
|
|
@ -4387,7 +4387,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
|
||||
if (!e)
|
||||
{
|
||||
error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
|
||||
error(cle.loc, "cannot convert initializer `%s` to expression", toChars(init));
|
||||
return setError();
|
||||
}
|
||||
result = e;
|
||||
|
|
|
|||
|
|
@ -1968,6 +1968,10 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf,
|
|||
v._init.initializerToBuffer(buf, &hgs);
|
||||
}
|
||||
|
||||
const commentIt = hgs.importcHdr && isSpecialCName(v.ident);
|
||||
if (commentIt)
|
||||
buf.writestring("/+");
|
||||
|
||||
if (anywritten)
|
||||
{
|
||||
buf.writestring(", ");
|
||||
|
|
@ -2000,8 +2004,31 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf,
|
|||
buf.writestring(" = ");
|
||||
vinit(v);
|
||||
}
|
||||
if (commentIt)
|
||||
buf.writestring("+/");
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* The names __DATE__, __TIME__,__EOF__, __VENDOR__, __TIMESTAMP__, __VERSION__
|
||||
* are special to the D lexer and cannot be used as D source variable names.
|
||||
* Params:
|
||||
* id = name to check
|
||||
* Returns:
|
||||
* true if special C name
|
||||
*/
|
||||
private bool isSpecialCName(Identifier id)
|
||||
{
|
||||
auto s = id.toString();
|
||||
if (s.length >= 7 && s[0] == '_' && s[1] == '_' &&
|
||||
(id == Id.DATE ||
|
||||
id == Id.TIME ||
|
||||
id == Id.EOFX ||
|
||||
id == Id.VENDOR ||
|
||||
id == Id.TIMESTAMP ||
|
||||
id == Id.VERSIONX))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Print expression to buffer.
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ public:
|
|||
Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees
|
||||
void importAll(Scope *sc) override;
|
||||
Dsymbol *toAlias() override;
|
||||
void setScope(Scope* sc) override;
|
||||
bool overloadInsert(Dsymbol *s) override;
|
||||
|
||||
Import *isImport() override { return this; }
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
uint length;
|
||||
const(uint) amax = 0x80000000;
|
||||
bool errors = false;
|
||||
//printf("ArrayInitializer::semantic(%s), ai: %s %p\n", t.toChars(), i.toChars(), i);
|
||||
//printf("ArrayInitializer::semantic(%s), ai: %s\n", t.toChars(), toChars(i));
|
||||
if (i.sem) // if semantic() already run
|
||||
{
|
||||
return i;
|
||||
|
|
@ -600,7 +600,17 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
|
||||
Initializer visitC(CInitializer ci)
|
||||
{
|
||||
//printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), ci.toChars());
|
||||
//printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), toChars(ci));
|
||||
static if (0)
|
||||
if (auto ts = tx.isTypeStruct())
|
||||
{
|
||||
import dmd.common.outbuffer;
|
||||
OutBuffer buf;
|
||||
HdrGenStage hgs;
|
||||
toCBuffer(ts.sym, buf, hgs);
|
||||
printf("%s\n", buf.peekChars());
|
||||
}
|
||||
|
||||
/* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer
|
||||
*/
|
||||
t = t.toBasetype();
|
||||
|
|
@ -794,6 +804,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
for (size_t index = 0; index < ci.initializerList.length; )
|
||||
{
|
||||
CInitializer cprev;
|
||||
size_t indexprev;
|
||||
L1:
|
||||
DesigInit di = ci.initializerList[index];
|
||||
Designators* dlist = di.designatorList;
|
||||
|
|
@ -827,6 +838,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
/* The peeling didn't work, so unpeel it
|
||||
*/
|
||||
ci = cprev;
|
||||
index = indexprev;
|
||||
di = ci.initializerList[index];
|
||||
goto L2;
|
||||
}
|
||||
|
|
@ -837,12 +849,14 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
{
|
||||
if (fieldi == nfields)
|
||||
break;
|
||||
if (index == 0 && ci.initializerList.length == 1 && di.initializer.isCInitializer())
|
||||
if (/*index == 0 && ci.initializerList.length == 1 &&*/ di.initializer.isCInitializer())
|
||||
{
|
||||
/* Try peeling off this set of { } and see if it works
|
||||
*/
|
||||
cprev = ci;
|
||||
ci = di.initializer.isCInitializer();
|
||||
indexprev = index;
|
||||
index = 0;
|
||||
goto L1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,3 +169,4 @@ struct ModuleDeclaration
|
|||
};
|
||||
|
||||
extern void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses);
|
||||
FuncDeclaration *findGetMembers(ScopeDsymbol *dsym);
|
||||
|
|
|
|||
|
|
@ -85,20 +85,6 @@ extern (C++) final class Nspace : ScopeDsymbol
|
|||
return ns;
|
||||
}
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
ScopeDsymbol.setScope(sc);
|
||||
if (members)
|
||||
{
|
||||
assert(sc);
|
||||
sc = sc.push(this);
|
||||
sc.linkage = LINK.cpp; // namespaces default to C++ linkage
|
||||
sc.parent = this;
|
||||
members.foreachDsymbol(s => s.setScope(sc));
|
||||
sc.pop();
|
||||
}
|
||||
}
|
||||
|
||||
override bool hasPointers()
|
||||
{
|
||||
//printf("Nspace::hasPointers() %s\n", toChars());
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ class Nspace final : public ScopeDsymbol
|
|||
public:
|
||||
Expression *identExp;
|
||||
Nspace *syntaxCopy(Dsymbol *s) override;
|
||||
void setScope(Scope *sc) override;
|
||||
bool hasPointers() override;
|
||||
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
|
||||
const char *kind() const override;
|
||||
|
|
|
|||
|
|
@ -8428,7 +8428,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
AST.TemplateParameters* tpl = null;
|
||||
|
||||
nextToken();
|
||||
if (token.value == TOK.leftParenthesis)
|
||||
if (token.value != TOK.leftParenthesis)
|
||||
{
|
||||
error("expected `(` following `is`, not `%s`", token.toChars());
|
||||
goto Lerr;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextToken();
|
||||
if (token.value == TOK.identifier && peekNext() == TOK.leftParenthesis)
|
||||
|
|
@ -8476,11 +8481,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
else
|
||||
check(TOK.rightParenthesis);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("`type identifier : specialization` expected following `is`");
|
||||
goto Lerr;
|
||||
}
|
||||
e = new AST.IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import dmd.root.rmem;
|
|||
import dmd.root.string;
|
||||
|
||||
import dmd.common.file;
|
||||
import dmd.common.string;
|
||||
import dmd.common.smallbuffer;
|
||||
|
||||
nothrow:
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ version (Windows)
|
|||
import core.sys.windows.windef;
|
||||
import core.sys.windows.winnls;
|
||||
|
||||
import dmd.common.string : extendedPathThen;
|
||||
import dmd.common.smallbuffer : extendedPathThen;
|
||||
|
||||
extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc;
|
||||
extern (Windows) void SetLastError(DWORD) nothrow @nogc;
|
||||
|
|
@ -1177,7 +1177,7 @@ version(Windows)
|
|||
*/
|
||||
private auto toWStringzThen(alias F)(const(char)[] str) nothrow
|
||||
{
|
||||
import dmd.common.string : SmallBuffer, toWStringz;
|
||||
import dmd.common.smallbuffer : SmallBuffer, toWStringz;
|
||||
|
||||
if (!str.length) return F(""w.ptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ private:
|
|||
|
||||
import core.stdc.stdlib;
|
||||
import core.stdc.string;
|
||||
import dmd.common.string : SmallBuffer;
|
||||
import dmd.common.smallbuffer : SmallBuffer;
|
||||
|
||||
enum isSearchFunction(alias fun) = is(searchFunctionType!fun);
|
||||
alias searchFunctionType(alias fun) = typeof(() {int x; return fun("", x);}());
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ The return value of `T`
|
|||
auto toCStringThen(alias dg)(const(char)[] src) nothrow
|
||||
{
|
||||
import dmd.root.rmem : mem;
|
||||
import dmd.common.string : SmallBuffer;
|
||||
import dmd.common.smallbuffer : SmallBuffer;
|
||||
|
||||
const len = src.length + 1;
|
||||
char[512] small = void;
|
||||
|
|
|
|||
|
|
@ -372,6 +372,64 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
|
|||
pt = t.merge();
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Search for identifier id as a member of `this`.
|
||||
* `id` may be a template instance.
|
||||
*
|
||||
* Params:
|
||||
* loc = location to print the error messages
|
||||
* sc = the scope where the symbol is located
|
||||
* id = the id of the symbol
|
||||
* flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
|
||||
*
|
||||
* Returns:
|
||||
* symbol found, NULL if not
|
||||
*/
|
||||
private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, int flags)
|
||||
{
|
||||
//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
|
||||
Dsymbol s = dsym.toAlias();
|
||||
Dsymbol sm;
|
||||
if (Declaration d = s.isDeclaration())
|
||||
{
|
||||
if (d.inuse)
|
||||
{
|
||||
.error(loc, "circular reference to `%s`", d.toPrettyChars());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
switch (id.dyncast())
|
||||
{
|
||||
case DYNCAST.identifier:
|
||||
sm = s.search(loc, cast(Identifier)id, flags);
|
||||
break;
|
||||
case DYNCAST.dsymbol:
|
||||
{
|
||||
// It's a template instance
|
||||
//printf("\ttemplate instance id\n");
|
||||
Dsymbol st = cast(Dsymbol)id;
|
||||
TemplateInstance ti = st.isTemplateInstance();
|
||||
sm = s.search(loc, ti.name);
|
||||
if (!sm)
|
||||
return null;
|
||||
sm = sm.toAlias();
|
||||
TemplateDeclaration td = sm.isTemplateDeclaration();
|
||||
if (!td)
|
||||
return null; // error but handled later
|
||||
ti.tempdecl = td;
|
||||
if (!ti.semanticRun)
|
||||
ti.dsymbolSemantic(sc);
|
||||
sm = ti.toAlias();
|
||||
break;
|
||||
}
|
||||
case DYNCAST.type:
|
||||
case DYNCAST.expression:
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return sm;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* We've mistakenly parsed `t` as a type.
|
||||
* Redo `t` as an Expression only if there are no type modifiers.
|
||||
|
|
|
|||
|
|
@ -503,7 +503,7 @@ layout_moduleinfo_fields (Module *decl, tree type)
|
|||
if (decl->sshareddtor)
|
||||
layout_moduleinfo_field (ptr_type_node, type, offset);
|
||||
|
||||
if (decl->findGetMembers ())
|
||||
if (findGetMembers (decl))
|
||||
layout_moduleinfo_field (ptr_type_node, type, offset);
|
||||
|
||||
if (decl->sictor)
|
||||
|
|
@ -571,7 +571,7 @@ layout_moduleinfo (Module *decl)
|
|||
aimports_dim--;
|
||||
}
|
||||
|
||||
sgetmembers = decl->findGetMembers ();
|
||||
sgetmembers = findGetMembers (decl);
|
||||
|
||||
size_t flags = 0;
|
||||
if (decl->sctor)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ fail_compilation/misc_parser_err_cov1.d(30): Error: basic type expected, not `)`
|
|||
fail_compilation/misc_parser_err_cov1.d(31): Error: `__traits(identifier, args...)` expected
|
||||
fail_compilation/misc_parser_err_cov1.d(31): Error: semicolon expected following auto declaration, not `o`
|
||||
fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)`
|
||||
fail_compilation/misc_parser_err_cov1.d(32): Error: `type identifier : specialization` expected following `is`
|
||||
fail_compilation/misc_parser_err_cov1.d(32): Error: expected `(` following `is`, not `;`
|
||||
fail_compilation/misc_parser_err_cov1.d(33): Error: semicolon expected following auto declaration, not `auto`
|
||||
fail_compilation/misc_parser_err_cov1.d(33): Error: found `+` when expecting `(` following `mixin`
|
||||
fail_compilation/misc_parser_err_cov1.d(35): Error: `key:value` expected for associative array literal
|
||||
|
|
|
|||
|
|
@ -173,6 +173,39 @@ static assert(test7u() == 1);
|
|||
static assert(test7s() == -1);
|
||||
static assert(test7s2() == -2);
|
||||
|
||||
/******************************************/
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24257
|
||||
|
||||
struct S24257
|
||||
{
|
||||
uint : 15;
|
||||
bool done : 1;
|
||||
}
|
||||
|
||||
bool advance()
|
||||
{
|
||||
S24257 n;
|
||||
n.done = false;
|
||||
n.done = true;
|
||||
return n.done;
|
||||
}
|
||||
|
||||
bool retard()
|
||||
{
|
||||
S24257 n;
|
||||
n.done = true;
|
||||
n.done = false;
|
||||
return n.done;
|
||||
}
|
||||
|
||||
static assert(advance() == true);
|
||||
|
||||
void test24257()
|
||||
{
|
||||
assert(advance() == true);
|
||||
assert(retard() == false);
|
||||
}
|
||||
|
||||
/******************************************/
|
||||
|
||||
int main()
|
||||
|
|
@ -184,6 +217,7 @@ int main()
|
|||
test5();
|
||||
test6();
|
||||
test7();
|
||||
test24257();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
ff57fec51558013b25cadb7e83da9f4675915d56
|
||||
2bbf64907cbbb483d003e0a8fcf8b502e4883799
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
|||
|
|
@ -628,16 +628,17 @@ void getAMDcacheinfo()
|
|||
|
||||
if (max_extended_cpuid >= 0x8000_0006) {
|
||||
// AMD K6-III or K6-2+ or later.
|
||||
ubyte numcores = 1;
|
||||
uint numcores = 1;
|
||||
if (max_extended_cpuid >= 0x8000_0008) {
|
||||
// read the number of physical cores (minus 1) from the 8 lowest ECX bits
|
||||
version (GNU_OR_LDC) asm pure nothrow @nogc {
|
||||
"cpuid" : "=a" (dummy), "=c" (numcores) : "a" (0x8000_0008) : "ebx", "edx";
|
||||
} else asm pure nothrow @nogc {
|
||||
mov EAX, 0x8000_0008;
|
||||
cpuid;
|
||||
mov numcores, CL;
|
||||
mov numcores, ECX;
|
||||
}
|
||||
++numcores;
|
||||
numcores = (numcores & 0xFF) + 1;
|
||||
if (numcores>cpuFeatures.maxCores) cpuFeatures.maxCores = numcores;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
17bafda797296e04f40f16a9660e5a9685392db4
|
||||
b64bfbf911fcd1675ae9792545649c9d45bb907e
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/phobos repository.
|
||||
|
|
|
|||
|
|
@ -2895,94 +2895,100 @@ if (isForwardRange!R1 && ifTestable!(typeof(haystack.front), unaryFun!pred))
|
|||
assert(findSkip!isWhite(s) == 2);
|
||||
}
|
||||
|
||||
private struct FindSplitResult(ubyte emptyRangeIndex, Types...)
|
||||
{
|
||||
this(Types vals)
|
||||
{
|
||||
asTuple = typeof(asTuple)(vals);
|
||||
}
|
||||
void opAssign(typeof(asTuple) rhs)
|
||||
{
|
||||
asTuple = rhs;
|
||||
}
|
||||
Tuple!Types asTuple;
|
||||
alias asTuple this;
|
||||
|
||||
static if (hasConstEmptyMember!(typeof(asTuple[emptyRangeIndex])))
|
||||
{
|
||||
bool opCast(T : bool)() const => !asTuple[emptyRangeIndex].empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool opCast(T : bool)() => !asTuple[emptyRangeIndex].empty;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
These functions find the first occurrence of `needle` in `haystack` and then
|
||||
split `haystack` as follows.
|
||||
|
||||
`findSplit` returns a tuple `result` containing $(I three) ranges. `result[0]`
|
||||
is the portion of `haystack` before `needle`, `result[1]` is the portion of
|
||||
`haystack` that matches `needle`, and `result[2]` is the portion of `haystack`
|
||||
after the match. If `needle` was not found, `result[0]` comprehends `haystack`
|
||||
$(PANEL
|
||||
`findSplit` returns a tuple `result` containing $(I three) ranges.
|
||||
$(UL
|
||||
$(LI `result[0]` is the portion of `haystack` before `needle`)
|
||||
$(LI `result[1]` is the portion of
|
||||
`haystack` that matches `needle`)
|
||||
$(LI `result[2]` is the portion of `haystack`
|
||||
after the match.)
|
||||
)
|
||||
If `needle` was not found, `result[0]` comprehends `haystack`
|
||||
entirely and `result[1]` and `result[2]` are empty.
|
||||
|
||||
`findSplitBefore` returns a tuple `result` containing two ranges. `result[0]` is
|
||||
the portion of `haystack` before `needle`, and `result[1]` is the balance of
|
||||
`haystack` starting with the match. If `needle` was not found, `result[0]`
|
||||
`findSplitBefore` returns a tuple `result` containing two ranges.
|
||||
$(UL
|
||||
$(LI `result[0]` is the portion of `haystack` before `needle`)
|
||||
$(LI `result[1]` is the balance of `haystack` starting with the match.)
|
||||
)
|
||||
If `needle` was not found, `result[0]`
|
||||
comprehends `haystack` entirely and `result[1]` is empty.
|
||||
|
||||
`findSplitAfter` returns a tuple `result` containing two ranges.
|
||||
`result[0]` is the portion of `haystack` up to and including the
|
||||
match, and `result[1]` is the balance of `haystack` starting
|
||||
after the match. If `needle` was not found, `result[0]` is empty
|
||||
$(UL
|
||||
$(LI `result[0]` is the portion of `haystack` up to and including the
|
||||
match)
|
||||
$(LI `result[1]` is the balance of `haystack` starting
|
||||
after the match.)
|
||||
)
|
||||
If `needle` was not found, `result[0]` is empty
|
||||
and `result[1]` is `haystack`.
|
||||
|
||||
)
|
||||
$(P
|
||||
In all cases, the concatenation of the returned ranges spans the
|
||||
entire `haystack`.
|
||||
|
||||
If `haystack` is a random-access range, all three components of the tuple have
|
||||
the same type as `haystack`. Otherwise, `haystack` must be a
|
||||
$(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and
|
||||
the type of `result[0]` and `result[1]` is the same as $(REF takeExactly,
|
||||
std,range).
|
||||
the type of `result[0]` (and `result[1]` for `findSplit`) is the same as
|
||||
the result of $(REF takeExactly, std,range).
|
||||
|
||||
For more information about `pred` see $(LREF find).
|
||||
|
||||
)
|
||||
Params:
|
||||
pred = Predicate to use for comparing needle against haystack.
|
||||
haystack = The range to search.
|
||||
needle = What to look for.
|
||||
pred = Predicate to compare 2 elements.
|
||||
haystack = The forward range to search.
|
||||
needle = The forward range to look for.
|
||||
|
||||
Returns:
|
||||
|
||||
A sub-type of `Tuple!()` of the split portions of `haystack` (see above for
|
||||
details). This sub-type of `Tuple!()` has `opCast` defined for `bool`. This
|
||||
`opCast` returns `true` when the separating `needle` was found
|
||||
and `false` otherwise.
|
||||
A sub-type of $(REF Tuple, std, typecons) of the split portions of `haystack` (see above for
|
||||
details). This sub-type of `Tuple` defines `opCast!bool`, which
|
||||
returns `true` when the separating `needle` was found and `false` otherwise.
|
||||
|
||||
See_Also: $(LREF find)
|
||||
*/
|
||||
auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
|
||||
if (isForwardRange!R1 && isForwardRange!R2)
|
||||
{
|
||||
static struct Result(S1, S2) if (isForwardRange!S1 &&
|
||||
isForwardRange!S2)
|
||||
{
|
||||
this(S1 pre, S1 separator, S2 post)
|
||||
{
|
||||
asTuple = typeof(asTuple)(pre, separator, post);
|
||||
}
|
||||
void opAssign(typeof(asTuple) rhs)
|
||||
{
|
||||
asTuple = rhs;
|
||||
}
|
||||
Tuple!(S1, S1, S2) asTuple;
|
||||
static if (hasConstEmptyMember!(typeof(asTuple[1])))
|
||||
{
|
||||
bool opCast(T : bool)() const
|
||||
{
|
||||
return !asTuple[1].empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool opCast(T : bool)()
|
||||
{
|
||||
return !asTuple[1].empty;
|
||||
}
|
||||
}
|
||||
alias asTuple this;
|
||||
}
|
||||
|
||||
static if (isSomeString!R1 && isSomeString!R2
|
||||
|| (isRandomAccessRange!R1 && hasSlicing!R1 && hasLength!R1 && hasLength!R2))
|
||||
{
|
||||
auto balance = find!pred(haystack, needle);
|
||||
immutable pos1 = haystack.length - balance.length;
|
||||
immutable pos2 = balance.empty ? pos1 : pos1 + needle.length;
|
||||
return Result!(typeof(haystack[0 .. pos1]),
|
||||
typeof(haystack[pos2 .. haystack.length]))(haystack[0 .. pos1],
|
||||
haystack[pos1 .. pos2],
|
||||
haystack[pos2 .. haystack.length]);
|
||||
alias Slice = typeof(haystack[0 .. pos1]);
|
||||
return FindSplitResult!(1, Slice, Slice, Slice)(
|
||||
haystack[0 .. pos1], haystack[pos1 .. pos2], haystack[pos2 .. haystack.length]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3011,10 +3017,11 @@ if (isForwardRange!R1 && isForwardRange!R2)
|
|||
{
|
||||
pos1 = pos2;
|
||||
}
|
||||
return Result!(typeof(takeExactly(original, pos1)),
|
||||
typeof(h))(takeExactly(original, pos1),
|
||||
takeExactly(haystack, pos2 - pos1),
|
||||
h);
|
||||
return FindSplitResult!(1,
|
||||
typeof(takeExactly(original, pos1)),
|
||||
typeof(takeExactly(original, pos1)), typeof(h))(
|
||||
takeExactly(original, pos1),
|
||||
takeExactly(haystack, pos2 - pos1), h);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3022,43 +3029,14 @@ if (isForwardRange!R1 && isForwardRange!R2)
|
|||
auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
|
||||
if (isForwardRange!R1 && isForwardRange!R2)
|
||||
{
|
||||
static struct Result(S1, S2) if (isForwardRange!S1 &&
|
||||
isForwardRange!S2)
|
||||
{
|
||||
this(S1 pre, S2 post)
|
||||
{
|
||||
asTuple = typeof(asTuple)(pre, post);
|
||||
}
|
||||
void opAssign(typeof(asTuple) rhs)
|
||||
{
|
||||
asTuple = rhs;
|
||||
}
|
||||
Tuple!(S1, S2) asTuple;
|
||||
static if (hasConstEmptyMember!(typeof(asTuple[1])))
|
||||
{
|
||||
bool opCast(T : bool)() const
|
||||
{
|
||||
return !asTuple[1].empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool opCast(T : bool)()
|
||||
{
|
||||
return !asTuple[1].empty;
|
||||
}
|
||||
}
|
||||
alias asTuple this;
|
||||
}
|
||||
|
||||
static if (isSomeString!R1 && isSomeString!R2
|
||||
|| (isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2))
|
||||
{
|
||||
auto balance = find!pred(haystack, needle);
|
||||
immutable pos = haystack.length - balance.length;
|
||||
return Result!(typeof(haystack[0 .. pos]),
|
||||
typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos],
|
||||
haystack[pos .. haystack.length]);
|
||||
return FindSplitResult!(1,
|
||||
typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))(
|
||||
haystack[0 .. pos], haystack[pos .. haystack.length]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3088,9 +3066,9 @@ if (isForwardRange!R1 && isForwardRange!R2)
|
|||
pos1 = pos2;
|
||||
haystack = h;
|
||||
}
|
||||
return Result!(typeof(takeExactly(original, pos1)),
|
||||
typeof(haystack))(takeExactly(original, pos1),
|
||||
haystack);
|
||||
return FindSplitResult!(1,
|
||||
typeof(takeExactly(original, pos1)), typeof(haystack))(
|
||||
takeExactly(original, pos1), haystack);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3098,47 +3076,19 @@ if (isForwardRange!R1 && isForwardRange!R2)
|
|||
auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
|
||||
if (isForwardRange!R1 && isForwardRange!R2)
|
||||
{
|
||||
static struct Result(S1, S2) if (isForwardRange!S1 &&
|
||||
isForwardRange!S2)
|
||||
{
|
||||
this(S1 pre, S2 post)
|
||||
{
|
||||
asTuple = typeof(asTuple)(pre, post);
|
||||
}
|
||||
void opAssign(typeof(asTuple) rhs)
|
||||
{
|
||||
asTuple = rhs;
|
||||
}
|
||||
Tuple!(S1, S2) asTuple;
|
||||
static if (hasConstEmptyMember!(typeof(asTuple[1])))
|
||||
{
|
||||
bool opCast(T : bool)() const
|
||||
{
|
||||
return !asTuple[0].empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool opCast(T : bool)()
|
||||
{
|
||||
return !asTuple[0].empty;
|
||||
}
|
||||
}
|
||||
alias asTuple this;
|
||||
}
|
||||
|
||||
static if (isSomeString!R1 && isSomeString!R2
|
||||
|| isRandomAccessRange!R1 && hasLength!R1 && hasSlicing!R1 && hasLength!R2)
|
||||
{
|
||||
auto balance = find!pred(haystack, needle);
|
||||
immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length;
|
||||
return Result!(typeof(haystack[0 .. pos]),
|
||||
typeof(haystack[pos .. haystack.length]))(haystack[0 .. pos],
|
||||
haystack[pos .. haystack.length]);
|
||||
return FindSplitResult!(0,
|
||||
typeof(haystack[0 .. pos]), typeof(haystack[0 .. pos]))(
|
||||
haystack[0 .. pos], haystack[pos .. haystack.length]);
|
||||
}
|
||||
else
|
||||
{
|
||||
import std.range : takeExactly;
|
||||
alias Res = FindSplitResult!(0, typeof(takeExactly(haystack, 0)), typeof(haystack));
|
||||
auto original = haystack.save;
|
||||
auto h = haystack.save;
|
||||
auto n = needle.save;
|
||||
|
|
@ -3148,9 +3098,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
|
|||
if (h.empty)
|
||||
{
|
||||
// Failed search
|
||||
return Result!(typeof(takeExactly(original, 0)),
|
||||
typeof(original))(takeExactly(original, 0),
|
||||
original);
|
||||
return Res(takeExactly(original, 0), original);
|
||||
}
|
||||
if (binaryFun!pred(h.front, n.front))
|
||||
{
|
||||
|
|
@ -3166,9 +3114,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
|
|||
pos2 = ++pos1;
|
||||
}
|
||||
}
|
||||
return Result!(typeof(takeExactly(original, pos2)),
|
||||
typeof(h))(takeExactly(original, pos2),
|
||||
h);
|
||||
return Res(takeExactly(original, pos2), h);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3185,12 +3131,12 @@ if (isForwardRange!R1 && isForwardRange!R2)
|
|||
}
|
||||
else assert(0);
|
||||
|
||||
// works with const aswell
|
||||
if (const split = "dlang-rocks".findSplit("-"))
|
||||
// findSplitBefore returns 2 ranges
|
||||
if (const split = [2, 3, 2, 3, 4, 1].findSplitBefore!"a > b"([2, 2]))
|
||||
{
|
||||
assert(split[0] == "dlang");
|
||||
assert(split[1] == "-");
|
||||
assert(split[2] == "rocks");
|
||||
assert(split[0] == [2, 3, 2]);
|
||||
// [3, 4] each greater than [2, 2]
|
||||
assert(split[1] == [3, 4, 1]);
|
||||
}
|
||||
else assert(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4848,8 +4848,9 @@ private S textImpl(S, U...)(U args)
|
|||
static foreach (arg; args)
|
||||
{
|
||||
static if (
|
||||
isSomeChar!(typeof(arg)) || isSomeString!(typeof(arg)) ||
|
||||
( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
|
||||
isSomeChar!(typeof(arg))
|
||||
|| isSomeString!(typeof(arg))
|
||||
|| ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
|
||||
)
|
||||
app.put(arg);
|
||||
else static if (
|
||||
|
|
|
|||
|
|
@ -1025,7 +1025,18 @@ if (Ranges.length > 0 &&
|
|||
}
|
||||
else
|
||||
{
|
||||
@property bool empty() => frontIndex >= backIndex;
|
||||
@property bool empty()
|
||||
{
|
||||
if (frontIndex == 0)
|
||||
{
|
||||
// special handling: we might be in Range.init state!
|
||||
// For instance, `format!"%s"` uses Range.init to ensure
|
||||
// that formatting is possible.
|
||||
// In that case, we must still behave in an internally consistent way.
|
||||
return source[0].empty;
|
||||
}
|
||||
return frontIndex >= backIndex;
|
||||
}
|
||||
}
|
||||
|
||||
static if (allSatisfy!(isForwardRange, R))
|
||||
|
|
@ -1705,6 +1716,17 @@ pure @safe nothrow @nogc unittest
|
|||
}
|
||||
}
|
||||
|
||||
/// https://issues.dlang.org/show_bug.cgi?id=24243
|
||||
pure @safe nothrow unittest
|
||||
{
|
||||
import std.algorithm.iteration : filter;
|
||||
|
||||
auto range = chain([2], [3].filter!"a");
|
||||
|
||||
// This might happen in format!"%s"(range), for instance.
|
||||
assert(typeof(range).init.empty);
|
||||
}
|
||||
|
||||
/**
|
||||
Choose one of two ranges at runtime depending on a Boolean condition.
|
||||
|
||||
|
|
|
|||
|
|
@ -7706,6 +7706,12 @@ public:
|
|||
return this.tupleof == other.tupleof;
|
||||
}
|
||||
|
||||
// Define a default toHash to allow AA usage
|
||||
size_t toHash() const @trusted
|
||||
{
|
||||
return hashOf(slen_, hashOf(small_));
|
||||
}
|
||||
|
||||
/++
|
||||
True if this object contains valid extended grapheme cluster.
|
||||
Decoding primitives of this module always return a valid `Grapheme`.
|
||||
|
|
@ -7907,6 +7913,12 @@ static assert(Grapheme.sizeof == size_t.sizeof*4);
|
|||
assert(equal(h[], iota(cast(int)'A', cast(int)'Z'+1)));
|
||||
}
|
||||
|
||||
// ensure Grapheme can be used as an AA key.
|
||||
@safe unittest
|
||||
{
|
||||
int[Grapheme] aa;
|
||||
}
|
||||
|
||||
/++
|
||||
$(P Does basic case-insensitive comparison of `r1` and `r2`.
|
||||
This function uses simpler comparison rule thus achieving better performance
|
||||
|
|
|
|||
Loading…
Reference in New Issue