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:
Iain Buclaw 2023-12-07 11:55:12 +01:00
parent 63194a0e8e
commit f9b4dbb8ac
45 changed files with 579 additions and 518 deletions

View File

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

View File

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

View File

@ -1 +1 @@
v2.106.0-rc.1
v2.106.0

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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[];

View File

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

View File

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

View File

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

View File

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

View File

@ -169,3 +169,4 @@ struct ModuleDeclaration
};
extern void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses);
FuncDeclaration *findGetMembers(ScopeDsymbol *dsym);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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