Merge dmd, druntime ceff48bf7d, phobos dcbfbd43a

D front-end changes:

	-   Import latest fixes from dmd v2.107.1-rc.1.

D runtime changes:

	-   Import latest fixes from druntime v2.107.1-rc.1.

Phobos changes:

	-   Import latest fixes from phobos v2.107.1-rc.1.

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd ceff48bf7d.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime ceff48bf7d.
	* libdruntime/Makefile.am (DRUNTIME_DSOURCES_FREEBSD): Add
	core/sys/freebsd/net/if_.d.
	* libdruntime/Makefile.in: Regenerate.
	* src/MERGE: Merge upstream phobos dcbfbd43a.
This commit is contained in:
Iain Buclaw 2024-02-24 10:26:09 +01:00
parent 3f58f96a4e
commit 94687d17ba
36 changed files with 1417 additions and 792 deletions

View file

@ -1,4 +1,4 @@
9471b25db9ed44d71e0e27956430c0c6a09c16db
ceff48bf7db05503117f54fdc0cefcb89b711136
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -22,7 +22,7 @@ import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
import dmd.funcsem;
import dmd.hdrgen;
import dmd.id;
import dmd.identifier;

View file

@ -10,7 +10,7 @@
#pragma once
#include "root/object.h"
#include "rootobject.h"
class Visitor;

View file

@ -16,24 +16,37 @@ 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, strlen;
import core.sys.windows.winbase;
import core.sys.windows.winnt;
import core.sys.posix.fcntl;
import core.sys.posix.unistd;
import core.stdc.stdlib;
import core.stdc.string : strerror, strlen, memcpy;
import dmd.common.smallbuffer;
nothrow:
version (Windows)
{
import core.sys.windows.winbase;
import core.sys.windows.winnls : CP_ACP;
import core.sys.windows.winnt;
// assume filenames encoded in system default Windows ANSI code page
enum CodePage = CP_ACP;
enum CodePage = CP_ACP; // assume filenames encoded in system default Windows ANSI code page
enum invalidHandle = INVALID_HANDLE_VALUE;
}
else version (Posix)
{
import core.sys.posix.fcntl;
import core.sys.posix.sys.mman;
import core.sys.posix.sys.stat;
import core.sys.posix.unistd;
import core.sys.posix.utime;
enum invalidHandle = -1;
}
else
static assert(0);
nothrow:
/**
Encapsulated management of a memory-mapped file.
@ -48,9 +61,6 @@ struct FileMapping(Datum)
static assert(__traits(isPOD, Datum) && Datum.sizeof == 1,
"Not tested with other data types yet. Add new types with care.");
version(Posix) enum invalidHandle = -1;
else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE;
// state {
/// Handle of underlying file
private auto handle = invalidHandle;
@ -82,9 +92,6 @@ struct FileMapping(Datum)
{
version (Posix)
{
import core.sys.posix.sys.mman;
import core.sys.posix.fcntl : open, O_CREAT, O_RDONLY, O_RDWR, S_IRGRP, S_IROTH, S_IRUSR, S_IWUSR;
handle = open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR),
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
@ -150,9 +157,6 @@ struct FileMapping(Datum)
// Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN.
// On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx.
// But just saving the name is simplest, fastest, and most portable...
import core.stdc.string : strlen;
import core.stdc.stdlib : malloc;
import core.stdc.string : memcpy;
const totalNameLength = filename.strlen() + 1;
auto namex = cast(char*) malloc(totalNameLength);
if (!namex)
@ -224,9 +228,6 @@ struct FileMapping(Datum)
fakePure({
version (Posix)
{
import core.sys.posix.sys.mman : munmap;
import core.sys.posix.unistd : close;
// Cannot call fprintf from inside a destructor, so exiting silently.
if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0)
@ -234,7 +235,7 @@ struct FileMapping(Datum)
exit(1);
}
data = null;
if (handle != invalidHandle && close(handle) != 0)
if (handle != invalidHandle && .close(handle) != 0)
{
exit(1);
}
@ -303,7 +304,6 @@ struct FileMapping(Datum)
// In-memory resource freed, now get rid of the underlying temp file.
version(Posix)
{
import core.sys.posix.unistd : unlink;
if (unlink(deleteme) != 0)
{
fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno));
@ -312,7 +312,6 @@ struct FileMapping(Datum)
}
else version(Windows)
{
import core.sys.windows.winbase;
if (deleteme[0 .. strlen(deleteme)].extendedPathThen!(p => DeleteFileW(p.ptr)) == 0)
{
fprintf(stderr, "DeleteFileW error %d\n", GetLastError());
@ -361,9 +360,6 @@ struct FileMapping(Datum)
fakePure({
version(Posix)
{
import core.sys.posix.unistd : ftruncate;
import core.sys.posix.sys.mman;
if (data.length)
{
assert(data.ptr, "Corrupt memory mapping");
@ -431,7 +427,6 @@ struct FileMapping(Datum)
// Fetch the name and then set it to `null` so it doesn't get deallocated
auto oldname = name;
import core.stdc.stdlib;
scope(exit) free(cast(void*) oldname);
name = null;
close();
@ -447,7 +442,6 @@ struct FileMapping(Datum)
}
else version(Windows)
{
import core.sys.windows.winbase;
auto r = oldname[0 .. strlen(oldname)].extendedPathThen!(
p1 => filename[0 .. strlen(filename)].extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING))
);
@ -527,8 +521,6 @@ bool touchFile(const char* namez)
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
import core.stdc.string : strlen;
// get handle to file
HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE,
@ -546,7 +538,6 @@ bool touchFile(const char* namez)
}
else version (Posix)
{
import core.sys.posix.utime;
return utime(namez, null) == 0;
}
else
@ -560,24 +551,28 @@ Params: fd = file handle
Returns: file size in bytes, or `ulong.max` on any error.
*/
version (Posix)
private ulong fileSize(int fd)
{
import core.sys.posix.sys.stat;
stat_t buf;
if (fstat(fd, &buf) == 0)
return buf.st_size;
return ulong.max;
private ulong fileSize(int fd)
{
stat_t buf;
if (fstat(fd, &buf) == 0)
return buf.st_size;
return ulong.max;
}
}
/// Ditto
version (Windows)
private ulong fileSize(HANDLE fd)
else version (Windows)
{
ulong result;
if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
return result;
return ulong.max;
/// Ditto
private ulong fileSize(HANDLE fd)
{
ulong result;
if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
return result;
return ulong.max;
}
}
else
static assert(0);
/**
Runs a non-pure function or delegate as pure code. Use with caution.

View file

@ -107,28 +107,30 @@ unittest
}
/**
(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.
* (Windows only) Converts a narrow string to a wide string using `buffer` as strorage.
* Params:
* narrow = string to be converted
* buffer = where to place the converted string
* Returns: a slice of `buffer` containing the converted string. A zero follows the slice.
*/
version(Windows) wchar[] toWStringz(scope const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow
{
import core.sys.windows.winnls : MultiByteToWideChar;
import dmd.common.file : CodePage;
if (narrow is null)
return null;
size_t length;
int i;
while (1)
size_t charsToWchars(scope const(char)[] narrow, scope wchar[] buffer)
{
// 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
import core.sys.windows.winnls : MultiByteToWideChar, CP_ACP;
return MultiByteToWideChar(CP_ACP, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
}
size_t length = charsToWchars(narrow, buffer[]);
if (length >= buffer.length) // not enough room in buffer[]
{
buffer.create(length + 1); // extend buffer length
length = charsToWchars(narrow, buffer[]); // try again
assert(length < buffer.length);
}
buffer[length] = 0;
return buffer[0 .. length];

View file

@ -1682,9 +1682,12 @@ final class CParser(AST) : Parser!AST
AST.ParameterList parameterList;
StorageClass stc = 0;
const loc = token.loc;
auto symbolsSave = symbols;
symbols = new AST.Dsymbols();
typedefTab.push(null);
auto fbody = cparseStatement(ParseStatementFlags.scope_);
typedefTab.pop(); // end of function scope
symbols = symbolsSave;
// Rewrite last ExpStatement (if there is one) as a ReturnStatement
auto ss = fbody.isScopeStatement();
@ -1693,8 +1696,11 @@ final class CParser(AST) : Parser!AST
if (const len = (*cs.statements).length)
{
auto s = (*cs.statements)[len - 1];
if (auto es = s.isExpStatement())
(*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
if (s) // error recovery should be with ErrorStatement, not null
{
if (auto es = s.isExpStatement())
(*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
}
}
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
@ -5520,7 +5526,7 @@ final class CParser(AST) : Parser!AST
defines.writeByte('#');
defines.writestring(n.ident.toString());
skipToNextLine(defines);
defines.writeByte('\n');
defines.writeByte(0); // each #define line is 0 terminated
return true;
}
else if (n.ident == Id.__pragma)
@ -5840,7 +5846,8 @@ final class CParser(AST) : Parser!AST
const length = buf.length;
buf.writeByte(0);
auto slice = buf.peekChars()[0 .. length];
resetDefineLines(slice); // reset lexer
auto scanlocSave = scanloc;
resetDefineLines(slice); // reset lexer
auto save = eSink;
auto eLatch = new ErrorSinkLatch();
eSink = eLatch;
@ -5865,12 +5872,14 @@ final class CParser(AST) : Parser!AST
(*symbols)[*pd] = s;
return;
}
assert(symbols, "symbols is null");
defineTab[cast(void*)s.ident] = symbols.length;
symbols.push(s);
}
while (p < endp)
{
//printf("|%s|\n", p);
if (p[0 .. 7] == "#define")
{
p += 7;
@ -5884,10 +5893,11 @@ final class CParser(AST) : Parser!AST
AST.Type t;
Lswitch:
switch (token.value)
{
case TOK.endOfLine: // #define identifier
nextDefineLine();
case TOK.endOfFile: // #define identifier
++p;
continue;
case TOK.int32Literal:
@ -5901,7 +5911,7 @@ final class CParser(AST) : Parser!AST
Linteger:
const intvalue = token.intvalue;
nextToken();
if (token.value == TOK.endOfLine)
if (token.value == TOK.endOfFile)
{
/* Declare manifest constant:
* enum id = intvalue;
@ -5909,7 +5919,7 @@ final class CParser(AST) : Parser!AST
AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
nextDefineLine();
++p;
continue;
}
break;
@ -5924,7 +5934,7 @@ final class CParser(AST) : Parser!AST
Lfloat:
const floatvalue = token.floatvalue;
nextToken();
if (token.value == TOK.endOfLine)
if (token.value == TOK.endOfFile)
{
/* Declare manifest constant:
* enum id = floatvalue;
@ -5932,7 +5942,7 @@ final class CParser(AST) : Parser!AST
AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
nextDefineLine();
++p;
continue;
}
break;
@ -5942,7 +5952,7 @@ final class CParser(AST) : Parser!AST
const len = token.len;
const postfix = token.postfix;
nextToken();
if (token.value == TOK.endOfLine)
if (token.value == TOK.endOfFile)
{
/* Declare manifest constant:
* enum id = "string";
@ -5950,19 +5960,20 @@ final class CParser(AST) : Parser!AST
AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
nextDefineLine();
++p;
continue;
}
break;
case TOK.leftParenthesis:
{
/* Look for:
* #define ID ( expression )
* and rewrite it to a template function:
* auto ID()() { return expression; }
*/
if (params)
break; // no parameters
goto caseFunctionLike; // version with parameters
nextToken();
eLatch.sawErrors = false;
auto exp = cparseExpression();
@ -5971,7 +5982,7 @@ final class CParser(AST) : Parser!AST
if (token.value != TOK.rightParenthesis)
break;
nextToken();
if (token.value != TOK.endOfLine)
if (token.value != TOK.endOfFile)
break;
auto ret = new AST.ReturnStatement(exp.loc, exp);
auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
@ -5985,26 +5996,115 @@ final class CParser(AST) : Parser!AST
AST.Expression constraint = null;
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
addVar(tempdecl);
nextDefineLine();
++p;
continue;
}
caseFunctionLike:
{
/* Parse `( a, b ) expression`
* Create template function:
* auto id(__MP1, __MP2)(__MP1 a, __MP1 b) { return expression; }
*/
//printf("functionlike %s\n", id.toChars());
// Capture the parameter list
VarArg varargs = VarArg.none;
auto parameters = new AST.Parameters();
nextToken(); // skip past `(`
Lwhile:
while (1)
{
if (token.value == TOK.rightParenthesis)
break;
if (token.value == TOK.dotDotDot)
{
static if (0) // variadic macros not supported yet
{
varargs = AST.VarArg.variadic; // C-style variadics
nextToken();
if (token.value == TOK.rightParenthesis)
break Lwhile;
}
break Lswitch;
}
if (token.value != TOK.identifier)
break Lswitch;
auto param = new AST.Parameter(token.loc, 0, null, token.ident, null, null);
parameters.push(param);
nextToken();
if (token.value == TOK.comma)
{
nextToken();
continue;
}
break;
}
if (token.value != TOK.rightParenthesis)
break;
//auto pstart = p;
nextToken();
auto parameterList = AST.ParameterList(parameters, varargs, 0);
/* Create a type for each parameter. Add it to the template parameter list,
* and the parameter list.
*/
auto tpl = new AST.TemplateParameters();
foreach (param; (*parameters)[])
{
auto idtype = Identifier.generateId("__MP");
auto loc = param.loc;
auto tp = new AST.TemplateTypeParameter(loc, idtype, null, null);
tpl.push(tp);
auto at = new AST.TypeIdentifier(loc, idtype);
param.type = at;
}
eLatch.sawErrors = false;
auto exp = cparseExpression();
//printf("exp: %s tok: %s\n", exp.toChars(), Token.toChars(token.value));
//printf("parsed: '%.*s'\n", cast(int)(p - pstart), pstart);
assert(symbols);
if (eLatch.sawErrors) // parsing errors
break; // abandon this #define
if (token.value != TOK.endOfFile) // did not consume the entire line
break;
// Generate function
auto ret = new AST.ReturnStatement(exp.loc, exp);
StorageClass stc = STC.auto_;
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
fd.fbody = ret;
// Wrap it in an eponymous template
AST.Dsymbols* decldefs = new AST.Dsymbols();
decldefs.push(fd);
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
addVar(tempdecl);
++p;
continue;
}
default:
break;
}
}
skipToNextLine();
}
else
{
scan(&token);
if (token.value != TOK.endOfLine)
{
skipToNextLine();
}
}
nextDefineLine();
// scan to end of line
while (*p)
++p;
++p; // advance to start of next line
scanloc.linnum = scanloc.linnum + 1;
}
scanloc = scanlocSave;
eSink = save;
defines = buf;
}

View file

@ -12,21 +12,13 @@
module dmd.dimport;
import dmd.arraytypes;
import dmd.astenums;
import dmd.declaration;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.errors;
import dmd.expression;
import dmd.globals;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.visitor;
import core.stdc.stdio;
/***********************************************************
*/
extern (C++) final class Import : Dsymbol
@ -76,6 +68,8 @@ extern (C++) final class Import : Dsymbol
assert(id);
version (none)
{
import core.stdc.stdio;
printf("Import::Import(");
foreach (id; packages)
{
@ -123,105 +117,6 @@ extern (C++) final class Import : Dsymbol
return si;
}
/*******************************
* Load this module.
* Returns:
* true for errors, false for success
*/
extern (D) bool load(Scope* sc)
{
//printf("Import::load('%s') %p\n", toPrettyChars(), this);
// See if existing module
const errors = global.errors;
DsymbolTable dst = Package.resolve(packages, null, &pkg);
version (none)
{
if (pkg && pkg.isModule())
{
.error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars());
mod = pkg.isModule(); // Error recovery - treat as import of that module
return true;
}
}
Dsymbol s = dst.lookup(id);
if (s)
{
if (s.isModule())
mod = cast(Module)s;
else
{
if (s.isAliasDeclaration())
{
.error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars());
}
else if (Package p = s.isPackage())
{
if (p.isPkgMod == PKG.unknown)
{
uint preverrors = global.errors;
mod = Module.load(loc, packages, id);
if (!mod)
p.isPkgMod = PKG.package_;
else
{
// mod is a package.d, or a normal module which conflicts with the package name.
if (mod.isPackageFile)
mod.tag = p.tag; // reuse the same package tag
else
{
// show error if Module.load does not
if (preverrors == global.errors)
.error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars());
return true;
}
}
}
else
{
mod = p.isPackageMod();
}
if (!mod)
{
.error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars());
}
}
else if (pkg)
{
.error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars());
}
else
{
.error(loc, "can only import from a module, not from package `%s`", id.toChars());
}
}
}
if (!mod)
{
// Load module
mod = Module.load(loc, packages, id);
if (mod)
{
// id may be different from mod.ident, if so then insert alias
dst.insert(id, mod);
}
}
if (mod && !mod.importedFrom)
mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule;
if (!pkg)
{
if (mod && mod.isPackageFile)
{
// one level depth package.d file (import pkg; ./pkg/package.d)
// it's necessary to use the wrapping Package already created
pkg = mod.pkg;
}
else
pkg = mod;
}
//printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
return global.errors != errors;
}
/*******************************
* Mark the imported packages as accessible from the current
* scope. This access check is necessary when using FQN b/c

View file

@ -16,12 +16,14 @@ module dmd.dmodule;
import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astcodegen;
import dmd.astenums;
import dmd.common.outbuffer;
import dmd.compiler;
import dmd.gluelayer;
import dmd.cparse;
import dmd.dimport;
import dmd.dmacro;
import dmd.doc;
@ -35,25 +37,37 @@ import dmd.expressionsem;
import dmd.file_manager;
import dmd.func;
import dmd.globals;
import dmd.gluelayer;
import dmd.id;
import dmd.identifier;
import dmd.location;
import dmd.parse;
import dmd.cparse;
import dmd.root.array;
import dmd.root.file;
import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.port;
import dmd.root.rmem;
import dmd.rootobject;
import dmd.root.string;
import dmd.rootobject;
import dmd.semantic2;
import dmd.semantic3;
import dmd.target;
import dmd.utils;
import dmd.visitor;
version (Windows)
{
import core.sys.windows.winbase : getpid = GetCurrentProcessId;
enum PathSeparator = '\\';
}
else version (Posix)
{
import core.sys.posix.unistd : getpid;
enum PathSeparator = '/';
}
else
static assert(0);
version (IN_GCC) {}
else version (IN_LLVM) {}
else version = MARS;
@ -141,11 +155,7 @@ private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothr
buf.writestring(p);
if (modAliases.length)
checkModFileAlias(p);
version (Windows)
enum FileSeparator = '\\';
else
enum FileSeparator = '/';
buf.writeByte(FileSeparator);
buf.writeByte(PathSeparator);
}
buf.writestring(filename);
if (modAliases.length)
@ -558,10 +568,6 @@ extern (C++) final class Module : Package
OutBuffer buf;
if (arg == "__stdin.d")
{
version (Posix)
import core.sys.posix.unistd : getpid;
else version (Windows)
import core.sys.windows.winbase : getpid = GetCurrentProcessId;
buf.printf("__stdin_%d.d", getpid());
arg = buf[];
}

View file

@ -6916,6 +6916,103 @@ extern(C++) class ImportAllVisitor : Visitor
override void visit(StaticForeachDeclaration _) {}
}
/*******************************
* Load module.
* Returns:
* true for errors, false for success
*/
extern (D) bool load(Import imp, Scope* sc)
{
// See if existing module
const errors = global.errors;
DsymbolTable dst = Package.resolve(imp.packages, null, &imp.pkg);
version (none)
{
if (pkg && pkg.isModule())
{
.error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars());
mod = pkg.isModule(); // Error recovery - treat as import of that module
return true;
}
}
Dsymbol s = dst.lookup(imp.id);
if (s)
{
if (s.isModule())
imp.mod = cast(Module)s;
else
{
if (s.isAliasDeclaration())
{
.error(imp.loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), imp.id.toChars());
}
else if (Package p = s.isPackage())
{
if (p.isPkgMod == PKG.unknown)
{
uint preverrors = global.errors;
imp.mod = Module.load(imp.loc, imp.packages, imp.id);
if (!imp.mod)
p.isPkgMod = PKG.package_;
else
{
// imp.mod is a package.d, or a normal module which conflicts with the package name.
if (imp.mod.isPackageFile)
imp.mod.tag = p.tag; // reuse the same package tag
else
{
// show error if Module.load does not
if (preverrors == global.errors)
.error(imp.loc, "%s `%s` from file %s conflicts with %s `%s`", imp.mod.kind(), imp.mod.toPrettyChars(), imp.mod.srcfile.toChars, p.kind(), p.toPrettyChars());
return true;
}
}
}
else
{
imp.mod = p.isPackageMod();
}
if (!imp.mod)
{
.error(imp.loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), imp.id.toChars());
}
}
else if (imp.pkg)
{
.error(imp.loc, "can only import from a module, not from package `%s.%s`", imp.pkg.toPrettyChars(), imp.id.toChars());
}
else
{
.error(imp.loc, "can only import from a module, not from package `%s`", imp.id.toChars());
}
}
}
if (!imp.mod)
{
// Load module
imp.mod = Module.load(imp.loc, imp.packages, imp.id);
if (imp.mod)
{
// imp.id may be different from mod.ident, if so then insert alias
dst.insert(imp.id, imp.mod);
}
}
if (imp.mod && !imp.mod.importedFrom)
imp.mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule;
if (!imp.pkg)
{
if (imp.mod && imp.mod.isPackageFile)
{
// one level depth package.d file (import pkg; ./pkg/package.d)
// it's necessary to use the wrapping Package already created
imp.pkg = imp.mod.pkg;
}
else
imp.pkg = imp.mod;
}
return global.errors != errors;
}
void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion)
{
scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion);

View file

@ -314,6 +314,7 @@ extern (C++) abstract class Expression : ASTNode
Type type; // !=null means that semantic() has been run
Loc loc; // file location
const EXP op; // to minimize use of dynamic_cast
bool parens; // if this is a parenthesized expression
extern (D) this(const ref Loc loc, EXP op) scope @safe
{
@ -1310,7 +1311,6 @@ extern (C++) final class ComplexExp : Expression
extern (C++) class IdentifierExp : Expression
{
Identifier ident;
bool parens; // if it appears as (identifier)
extern (D) this(const ref Loc loc, Identifier ident) scope @safe
{
@ -2432,8 +2432,6 @@ extern (C++) final class CompoundLiteralExp : Expression
*/
extern (C++) final class TypeExp : Expression
{
bool parens; // if this is a parenthesized expression
extern (D) this(const ref Loc loc, Type type) @safe
{
super(loc, EXP.type);

View file

@ -90,6 +90,7 @@ public:
Type *type; // !=NULL means that semantic() has been run
Loc loc; // file location
EXP op; // to minimize use of dynamic_cast
d_bool parens; // if this is a parenthesized expression
size_t size() const;
static void _init();
@ -300,7 +301,6 @@ class IdentifierExp : public Expression
{
public:
Identifier *ident;
d_bool parens;
static IdentifierExp *create(const Loc &loc, Identifier *ident);
bool isLvalue() override final;

View file

@ -16628,3 +16628,100 @@ Expression toBoolean(Expression exp, Scope* sc)
return e;
}
}
/********************************************
* Semantically analyze and then evaluate a static condition at compile time.
* This is special because short circuit operators &&, || and ?: at the top
* level are not semantically analyzed if the result of the expression is not
* necessary.
* Params:
* sc = instantiating scope
* original = original expression, for error messages
* e = resulting expression
* errors = set to `true` if errors occurred
* negatives = array to store negative clauses
* Returns:
* true if evaluates to true
*/
bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null)
{
if (negatives)
negatives.setDim(0);
bool impl(Expression e)
{
if (e.isNotExp())
{
NotExp ne = cast(NotExp)e;
return !impl(ne.e1);
}
if (e.op == EXP.andAnd || e.op == EXP.orOr)
{
LogicalExp aae = cast(LogicalExp)e;
bool result = impl(aae.e1);
if (errors)
return false;
if (e.op == EXP.andAnd)
{
if (!result)
return false;
}
else
{
if (result)
return true;
}
result = impl(aae.e2);
return !errors && result;
}
if (e.op == EXP.question)
{
CondExp ce = cast(CondExp)e;
bool result = impl(ce.econd);
if (errors)
return false;
Expression leg = result ? ce.e1 : ce.e2;
result = impl(leg);
return !errors && result;
}
Expression before = e;
const uint nerrors = global.errors;
sc = sc.startCTFE();
sc.flags |= SCOPE.condition;
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
e = e.toBoolean(sc);
sc = sc.endCTFE();
e = e.optimize(WANTvalue);
if (nerrors != global.errors ||
e.isErrorExp() ||
e.type.toBasetype() == Type.terror)
{
errors = true;
return false;
}
e = e.ctfeInterpret();
const opt = e.toBool();
if (opt.isEmpty())
{
if (!e.type.isTypeError())
error(e.loc, "expression `%s` is not constant", e.toChars());
errors = true;
return false;
}
if (negatives && !opt.get())
negatives.push(before);
return opt.get();
}
return impl(e);
}

View file

@ -58,7 +58,6 @@ import dmd.semantic3;
import dmd.statement_rewrite_walker;
import dmd.statement;
import dmd.statementsem;
import dmd.templatesem;
import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
@ -2925,395 +2924,6 @@ unittest
assert(mismatches.isMutable);
}
/// Flag used by $(LREF resolveFuncCall).
enum FuncResolveFlag : ubyte
{
standard = 0, /// issue error messages, solve the call.
quiet = 1, /// do not issue error message on no match, just return `null`.
overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
/// matches and need explicit this.
ufcs = 4, /// trying to resolve UFCS call
}
/*******************************************
* Given a symbol that could be either a FuncDeclaration or
* a function template, resolve it to a function symbol.
* Params:
* loc = instantiation location
* sc = instantiation scope
* s = instantiation symbol
* tiargs = initial list of template arguments
* tthis = if !NULL, the `this` argument type
* argumentList = arguments to function
* flags = see $(LREF FuncResolveFlag).
* Returns:
* if match is found, then function symbol, else null
*/
FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
{
auto fargs = argumentList.arguments;
if (!s)
return null; // no match
version (none)
{
printf("resolveFuncCall('%s')\n", s.toChars());
if (tthis)
printf("\tthis: %s\n", tthis.toChars());
if (fargs)
{
for (size_t i = 0; i < fargs.length; i++)
{
Expression arg = (*fargs)[i];
assert(arg.type);
printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
}
}
printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
}
if (tiargs && arrayObjectIsError(*tiargs))
return null;
if (fargs !is null)
foreach (arg; *fargs)
if (isError(arg))
return null;
MatchAccumulator m;
functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
auto orig_s = s;
if (m.last > MATCH.nomatch && m.lastf)
{
if (m.count == 1) // exactly one match
{
if (!(flags & FuncResolveFlag.quiet))
functionSemantic(m.lastf);
return m.lastf;
}
if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
{
return m.lastf;
}
}
/* Failed to find a best match.
* Do nothing or print error.
*/
if (m.last == MATCH.nomatch)
{
// error was caused on matched function, not on the matching itself,
// so return the function to produce a better diagnostic
if (m.count == 1)
return m.lastf;
}
// We are done at this point, as the rest of this function generate
// a diagnostic on invalid match
if (flags & FuncResolveFlag.quiet)
return null;
auto fd = s.isFuncDeclaration();
auto od = s.isOverDeclaration();
auto td = s.isTemplateDeclaration();
if (td && td.funcroot)
s = fd = td.funcroot;
OutBuffer tiargsBuf;
arrayObjectsToBuffer(tiargsBuf, tiargs);
OutBuffer fargsBuf;
fargsBuf.writeByte('(');
argExpTypesToCBuffer(fargsBuf, fargs);
fargsBuf.writeByte(')');
if (tthis)
tthis.modToBuffer(fargsBuf);
// The call is ambiguous
if (m.lastf && m.nextf)
{
TypeFunction tf1 = m.lastf.type.toTypeFunction();
TypeFunction tf2 = m.nextf.type.toTypeFunction();
const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
.error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
s.parent.toPrettyChars(), s.ident.toChars(),
fargsBuf.peekChars(),
m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
return null;
}
// no match, generate an error messages
if (flags & FuncResolveFlag.ufcs)
{
auto arg = (*fargs)[0];
.error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
.errorSupplemental(loc, "the following error occured while looking for a UFCS match");
}
if (!fd)
{
// all of overloads are templates
if (td)
{
if (!od && !td.overnext)
{
.error(loc, "%s `%s` is not callable using argument types `!(%s)%s`",
td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
}
else
{
.error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
tiargsBuf.peekChars(), fargsBuf.peekChars());
}
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, td, sc.isDeprecated());
return null;
}
/* This case used to happen when several ctors are mixed in an agregate.
A (bad) error message is already generated in overloadApply().
see https://issues.dlang.org/show_bug.cgi?id=19729
and https://issues.dlang.org/show_bug.cgi?id=17259
*/
if (!od)
return null;
}
if (od)
{
.error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
return null;
}
// remove when deprecation period of class allocators and deallocators is over
if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
return null;
bool hasOverloads = fd.overnext !is null;
auto tf = fd.type.isTypeFunction();
// if type is an error, the original type should be there for better diagnostics
if (!tf)
tf = fd.originalType.toTypeFunction();
// modifier mismatch
if (tthis && (fd.isCtorDeclaration() ?
!MODimplicitConv(tf.mod, tthis.mod) :
!MODimplicitConv(tthis.mod, tf.mod)))
{
OutBuffer thisBuf, funcBuf;
MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
if (hasOverloads)
{
OutBuffer buf;
buf.argExpTypesToCBuffer(fargs);
if (fd.isCtorDeclaration())
.error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
fd.toChars(), thisBuf.peekChars(), buf.peekChars());
else
.error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
fd.toChars(), thisBuf.peekChars(), buf.peekChars());
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, fd, sc.isDeprecated());
return null;
}
bool calledHelper;
void errorHelper(const(char)* failMessage) scope
{
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
tf.modToChars(), fargsBuf.peekChars());
errorSupplemental(loc, failMessage);
calledHelper = true;
}
functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper);
if (calledHelper)
return null;
if (fd.isCtorDeclaration())
.error(loc, "%s%s `%s` cannot construct a %sobject",
funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
else
.error(loc, "%smethod `%s` is not callable using a %sobject",
funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
if (mismatches.isNotShared)
.errorSupplemental(fd.loc, "Consider adding `shared` here");
else if (mismatches.isMutable)
.errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
return null;
}
//printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
if (hasOverloads)
{
.error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
fd.toChars(), fargsBuf.peekChars());
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, fd, sc.isDeprecated());
return null;
}
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
tf.modToChars(), fargsBuf.peekChars());
// re-resolve to check for supplemental message
if (!global.gag || global.params.v.showGaggedErrors)
{
if (tthis)
{
if (auto classType = tthis.isTypeClass())
{
if (auto baseClass = classType.sym.baseClass)
{
if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
{
MatchAccumulator mErr;
functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
if (mErr.last > MATCH.nomatch && mErr.lastf)
{
errorSupplemental(loc, "%s `%s` hides base class function `%s`",
fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
return null;
}
}
}
}
}
void errorHelper2(const(char)* failMessage) scope
{
errorSupplemental(loc, failMessage);
}
functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
}
return null;
}
/*******************************************
* Prints template and function overload candidates as supplemental errors.
* Params:
* loc = instantiation location
* declaration = the declaration to print overload candidates for
* showDeprecated = If `false`, `deprecated` function won't be shown
*/
private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
{
// max num of overloads to print (-v or -verror-supplements overrides this).
const uint DisplayLimit = global.params.v.errorSupplementCount();
const(char)* constraintsTip;
// determine if the first candidate was printed
int printed;
bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
{
if (auto fd = s.isFuncDeclaration())
{
// Don't print overloads which have errors.
// Not that if the whole overload set has errors, we'll never reach
// this point so there's no risk of printing no candidate
if (fd.errors || fd.type.ty == Terror)
return false;
// Don't print disabled functions, or `deprecated` outside of deprecated scope
if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
return false;
if (!print)
return true;
auto tf = cast(TypeFunction) fd.type;
OutBuffer buf;
buf.writestring(fd.toPrettyChars());
buf.writestring(parametersTypeToChars(tf.parameterList));
if (tf.mod)
{
buf.writeByte(' ');
buf.MODtoBuffer(tf.mod);
}
.errorSupplemental(fd.loc,
printed ? " `%s`" :
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
}
else if (auto td = s.isTemplateDeclaration())
{
import dmd.staticcond;
if (!print)
return true;
OutBuffer buf;
HdrGenState hgs;
hgs.skipConstraints = true;
toCharsMaybeConstraints(td, buf, hgs);
const tmsg = buf.peekChars();
const cmsg = td.getConstraintEvalError(constraintsTip);
// add blank space if there are multiple candidates
// the length of the blank space is `strlen("Candidates are: ")`
if (cmsg)
{
.errorSupplemental(td.loc,
printed ? " `%s`\n%s" :
single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
tmsg, cmsg);
}
else
{
.errorSupplemental(td.loc,
printed ? " `%s`" :
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
tmsg);
}
}
return true;
}
// determine if there's > 1 candidate
int count = 0;
overloadApply(declaration, (s) {
if (matchSymbol(s, false))
count++;
return count > 1;
});
int skipped = 0;
overloadApply(declaration, (s) {
if (global.params.v.verbose || printed < DisplayLimit)
{
if (matchSymbol(s, true, count == 1))
printed++;
}
else
{
// Too many overloads to sensibly display.
// Just show count of remaining overloads.
if (matchSymbol(s, false))
skipped++;
}
return 0;
});
if (skipped > 0)
.errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
// Nothing was displayed, all overloads are either disabled or deprecated
if (!printed)
.errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
// should be only in verbose mode
if (constraintsTip)
.tip(constraintsTip);
}
/**************************************
* Returns an indirect type one step from t.
*/
@ -4336,9 +3946,9 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)
return false;
if (sc.func.isSafeBypassingInference())
{
if (!gag)
if (!gag && !sc.isDeprecated())
{
warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
}
}
else if (!sc.func.safetyViolation)

View file

@ -60,6 +60,7 @@ import dmd.statement_rewrite_walker;
import dmd.statement;
import dmd.statementsem;
import dmd.target;
import dmd.templatesem;
import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
@ -1365,3 +1366,392 @@ BaseClass* overrideInterface(FuncDeclaration fd)
}
return null;
}
/// Flag used by $(LREF resolveFuncCall).
enum FuncResolveFlag : ubyte
{
standard = 0, /// issue error messages, solve the call.
quiet = 1, /// do not issue error message on no match, just return `null`.
overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
/// matches and need explicit this.
ufcs = 4, /// trying to resolve UFCS call
}
/*******************************************
* Given a symbol that could be either a FuncDeclaration or
* a function template, resolve it to a function symbol.
* Params:
* loc = instantiation location
* sc = instantiation scope
* s = instantiation symbol
* tiargs = initial list of template arguments
* tthis = if !NULL, the `this` argument type
* argumentList = arguments to function
* flags = see $(LREF FuncResolveFlag).
* Returns:
* if match is found, then function symbol, else null
*/
FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
{
auto fargs = argumentList.arguments;
if (!s)
return null; // no match
version (none)
{
printf("resolveFuncCall('%s')\n", s.toChars());
if (tthis)
printf("\tthis: %s\n", tthis.toChars());
if (fargs)
{
for (size_t i = 0; i < fargs.length; i++)
{
Expression arg = (*fargs)[i];
assert(arg.type);
printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
}
}
printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
}
if (tiargs && arrayObjectIsError(*tiargs))
return null;
if (fargs !is null)
foreach (arg; *fargs)
if (isError(arg))
return null;
MatchAccumulator m;
functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
auto orig_s = s;
if (m.last > MATCH.nomatch && m.lastf)
{
if (m.count == 1) // exactly one match
{
if (!(flags & FuncResolveFlag.quiet))
functionSemantic(m.lastf);
return m.lastf;
}
if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
{
return m.lastf;
}
}
/* Failed to find a best match.
* Do nothing or print error.
*/
if (m.last == MATCH.nomatch)
{
// error was caused on matched function, not on the matching itself,
// so return the function to produce a better diagnostic
if (m.count == 1)
return m.lastf;
}
// We are done at this point, as the rest of this function generate
// a diagnostic on invalid match
if (flags & FuncResolveFlag.quiet)
return null;
auto fd = s.isFuncDeclaration();
auto od = s.isOverDeclaration();
auto td = s.isTemplateDeclaration();
if (td && td.funcroot)
s = fd = td.funcroot;
OutBuffer tiargsBuf;
arrayObjectsToBuffer(tiargsBuf, tiargs);
OutBuffer fargsBuf;
fargsBuf.writeByte('(');
argExpTypesToCBuffer(fargsBuf, fargs);
fargsBuf.writeByte(')');
if (tthis)
tthis.modToBuffer(fargsBuf);
// The call is ambiguous
if (m.lastf && m.nextf)
{
TypeFunction tf1 = m.lastf.type.toTypeFunction();
TypeFunction tf2 = m.nextf.type.toTypeFunction();
const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
.error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
s.parent.toPrettyChars(), s.ident.toChars(),
fargsBuf.peekChars(),
m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
return null;
}
// no match, generate an error messages
if (flags & FuncResolveFlag.ufcs)
{
auto arg = (*fargs)[0];
.error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
.errorSupplemental(loc, "the following error occured while looking for a UFCS match");
}
if (!fd)
{
// all of overloads are templates
if (td)
{
if (!od && !td.overnext)
{
.error(loc, "%s `%s` is not callable using argument types `!(%s)%s`",
td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
}
else
{
.error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
tiargsBuf.peekChars(), fargsBuf.peekChars());
}
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, td, sc.isDeprecated());
return null;
}
/* This case used to happen when several ctors are mixed in an agregate.
A (bad) error message is already generated in overloadApply().
see https://issues.dlang.org/show_bug.cgi?id=19729
and https://issues.dlang.org/show_bug.cgi?id=17259
*/
if (!od)
return null;
}
if (od)
{
.error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
return null;
}
// remove when deprecation period of class allocators and deallocators is over
if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
return null;
bool hasOverloads = fd.overnext !is null;
auto tf = fd.type.isTypeFunction();
// if type is an error, the original type should be there for better diagnostics
if (!tf)
tf = fd.originalType.toTypeFunction();
// modifier mismatch
if (tthis && (fd.isCtorDeclaration() ?
!MODimplicitConv(tf.mod, tthis.mod) :
!MODimplicitConv(tthis.mod, tf.mod)))
{
OutBuffer thisBuf, funcBuf;
MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
if (hasOverloads)
{
OutBuffer buf;
buf.argExpTypesToCBuffer(fargs);
if (fd.isCtorDeclaration())
.error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
fd.toChars(), thisBuf.peekChars(), buf.peekChars());
else
.error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
fd.toChars(), thisBuf.peekChars(), buf.peekChars());
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, fd, sc.isDeprecated());
return null;
}
bool calledHelper;
void errorHelper(const(char)* failMessage) scope
{
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
tf.modToChars(), fargsBuf.peekChars());
errorSupplemental(loc, failMessage);
calledHelper = true;
}
functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper);
if (calledHelper)
return null;
if (fd.isCtorDeclaration())
.error(loc, "%s%s `%s` cannot construct a %sobject",
funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
else
.error(loc, "%smethod `%s` is not callable using a %sobject",
funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
if (mismatches.isNotShared)
.errorSupplemental(fd.loc, "Consider adding `shared` here");
else if (mismatches.isMutable)
.errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
return null;
}
//printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
if (hasOverloads)
{
.error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
fd.toChars(), fargsBuf.peekChars());
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, fd, sc.isDeprecated());
return null;
}
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
tf.modToChars(), fargsBuf.peekChars());
// re-resolve to check for supplemental message
if (!global.gag || global.params.v.showGaggedErrors)
{
if (tthis)
{
if (auto classType = tthis.isTypeClass())
{
if (auto baseClass = classType.sym.baseClass)
{
if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
{
MatchAccumulator mErr;
functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
if (mErr.last > MATCH.nomatch && mErr.lastf)
{
errorSupplemental(loc, "%s `%s` hides base class function `%s`",
fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
return null;
}
}
}
}
}
void errorHelper2(const(char)* failMessage) scope
{
errorSupplemental(loc, failMessage);
}
functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
}
return null;
}
/*******************************************
* Prints template and function overload candidates as supplemental errors.
* Params:
* loc = instantiation location
* declaration = the declaration to print overload candidates for
* showDeprecated = If `false`, `deprecated` function won't be shown
*/
private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
{
// max num of overloads to print (-v or -verror-supplements overrides this).
const uint DisplayLimit = global.params.v.errorSupplementCount();
const(char)* constraintsTip;
// determine if the first candidate was printed
int printed;
bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
{
if (auto fd = s.isFuncDeclaration())
{
// Don't print overloads which have errors.
// Not that if the whole overload set has errors, we'll never reach
// this point so there's no risk of printing no candidate
if (fd.errors || fd.type.ty == Terror)
return false;
// Don't print disabled functions, or `deprecated` outside of deprecated scope
if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
return false;
if (!print)
return true;
auto tf = cast(TypeFunction) fd.type;
OutBuffer buf;
buf.writestring(fd.toPrettyChars());
buf.writestring(parametersTypeToChars(tf.parameterList));
if (tf.mod)
{
buf.writeByte(' ');
buf.MODtoBuffer(tf.mod);
}
.errorSupplemental(fd.loc,
printed ? " `%s`" :
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
}
else if (auto td = s.isTemplateDeclaration())
{
import dmd.staticcond;
if (!print)
return true;
OutBuffer buf;
HdrGenState hgs;
hgs.skipConstraints = true;
toCharsMaybeConstraints(td, buf, hgs);
const tmsg = buf.peekChars();
const cmsg = td.getConstraintEvalError(constraintsTip);
// add blank space if there are multiple candidates
// the length of the blank space is `strlen("Candidates are: ")`
if (cmsg)
{
.errorSupplemental(td.loc,
printed ? " `%s`\n%s" :
single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
tmsg, cmsg);
}
else
{
.errorSupplemental(td.loc,
printed ? " `%s`" :
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
tmsg);
}
}
return true;
}
// determine if there's > 1 candidate
int count = 0;
overloadApply(declaration, (s) {
if (matchSymbol(s, false))
count++;
return count > 1;
});
int skipped = 0;
overloadApply(declaration, (s) {
if (global.params.v.verbose || printed < DisplayLimit)
{
if (matchSymbol(s, true, count == 1))
printed++;
}
else
{
// Too many overloads to sensibly display.
// Just show count of remaining overloads.
if (matchSymbol(s, false))
skipped++;
}
return 0;
});
if (skipped > 0)
.errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
// Nothing was displayed, all overloads are either disabled or deprecated
if (!printed)
.errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
// should be only in verbose mode
if (constraintsTip)
.tip(constraintsTip);
}

View file

@ -11,7 +11,7 @@
#pragma once
#include "root/dcompat.h"
#include "root/object.h"
#include "rootobject.h"
class Identifier final : public RootObject
{

View file

@ -243,16 +243,15 @@ Expression castCallAmbiguity(Expression e, Scope* sc)
case EXP.call:
auto ce = (*pe).isCallExp();
auto ie = ce.e1.isIdentifierExp();
if (ie && ie.parens)
if (ce.e1.parens)
{
ce.e1 = expressionSemantic(ie, sc);
ce.e1 = expressionSemantic(ce.e1, sc);
if (ce.e1.op == EXP.type)
{
const numArgs = ce.arguments ? ce.arguments.length : 0;
if (numArgs >= 1)
{
ie.parens = false;
ce.e1.parens = false;
Expression arg;
foreach (a; (*ce.arguments)[])
{

View file

@ -30,7 +30,6 @@ import dmd.dtemplate;
import dmd.enumsem;
import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;

View file

@ -7130,7 +7130,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
private void checkParens(TOK value, AST.Expression e)
{
if (precedence[e.op] == PREC.rel)
if (precedence[e.op] == PREC.rel && !e.parens)
error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value));
}
@ -8550,6 +8550,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
// ( expression )
nextToken();
e = parseExpression();
e.parens = true;
check(loc, TOK.rightParenthesis);
break;
}
@ -8874,9 +8875,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
return AST.ErrorExp.get();
}
auto te = new AST.TypeExp(loc, t);
te.parens = true;
e = parsePostExp(te);
e = new AST.TypeExp(loc, t);
e.parens = true;
e = parsePostExp(e);
}
else if (token.value == TOK.leftParenthesis ||
token.value == TOK.plusPlus || token.value == TOK.minusMinus)
@ -9193,18 +9194,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
private AST.Expression parseAndExp()
{
Loc loc = token.loc;
bool parens = token.value == TOK.leftParenthesis;
auto e = parseCmpExp();
while (token.value == TOK.and)
{
if (!parens)
checkParens(TOK.and, e);
parens = nextToken() == TOK.leftParenthesis;
checkParens(TOK.and, e);
nextToken();
auto e2 = parseCmpExp();
if (!parens)
checkParens(TOK.and, e2);
checkParens(TOK.and, e2);
e = new AST.AndExp(loc, e, e2);
parens = true; // don't call checkParens() for And
loc = token.loc;
}
return e;
@ -9212,42 +9209,32 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
private AST.Expression parseXorExp()
{
Loc loc = token.loc;
const loc = token.loc;
bool parens = token.value == TOK.leftParenthesis;
auto e = parseAndExp();
while (token.value == TOK.xor)
{
if (!parens)
checkParens(TOK.xor, e);
parens = nextToken() == TOK.leftParenthesis;
checkParens(TOK.xor, e);
nextToken();
auto e2 = parseAndExp();
if (!parens)
checkParens(TOK.xor, e2);
checkParens(TOK.xor, e2);
e = new AST.XorExp(loc, e, e2);
parens = true;
loc = token.loc;
}
return e;
}
private AST.Expression parseOrExp()
{
Loc loc = token.loc;
const loc = token.loc;
bool parens = token.value == TOK.leftParenthesis;
auto e = parseXorExp();
while (token.value == TOK.or)
{
if (!parens)
checkParens(TOK.or, e);
parens = nextToken() == TOK.leftParenthesis;
checkParens(TOK.or, e);
nextToken();
auto e2 = parseXorExp();
if (!parens)
checkParens(TOK.or, e2);
checkParens(TOK.or, e2);
e = new AST.OrExp(loc, e, e2);
parens = true;
loc = token.loc;
}
return e;
}
@ -9298,7 +9285,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Expression parseAssignExp()
{
bool parens = token.value == TOK.leftParenthesis;
AST.Expression e;
e = parseCondExp();
if (e is null)
@ -9307,7 +9293,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
// require parens for e.g. `t ? a = 1 : b = 2`
void checkRequiredParens()
{
if (e.op == EXP.question && !parens)
if (e.op == EXP.question && !e.parens)
eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
e.toChars(), Token.toChars(token.value));
}

View file

@ -9,7 +9,6 @@
#pragma once
#include "dsystem.h"
#include "object.h"
#include "rmem.h"
template <typename TYPE>
@ -44,7 +43,7 @@ struct Array
d_size_t len = 2;
for (d_size_t u = 0; u < length; u++)
{
buf[u] = ((RootObject *)data.ptr[u])->toChars();
buf[u] = ((TYPE)data.ptr[u])->toChars();
len += strlen(buf[u]) + 1;
}
char *str = (char *)mem.xmalloc(len);

View file

@ -9,7 +9,6 @@
#pragma once
#include "dsystem.h"
#include "object.h"
#include "rmem.h"
struct BitArray

View file

@ -4,13 +4,13 @@
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* https://www.boost.org/LICENSE_1_0.txt
* https://github.com/dlang/dmd/blob/master/src/dmd/root/object.h
* https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.h
*/
#pragma once
#include "dsystem.h"
#include "dcompat.h"
#include "root/dsystem.h"
#include "root/dcompat.h"
typedef size_t hash_t;

View file

@ -1196,7 +1196,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
case Taarray:
if (fs.op == TOK.foreach_reverse_)
warning(fs.loc, "cannot use `foreach_reverse` with an associative array");
error(fs.loc, "cannot use `foreach_reverse` with an associative array");
if (checkForArgTypes(fs))
return retError();

View file

@ -11,120 +11,13 @@
module dmd.staticcond;
import dmd.arraytypes;
import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.globals;
import dmd.identifier;
import dmd.mtype;
import dmd.optimize;
import dmd.root.array;
import dmd.common.outbuffer;
import dmd.tokens;
/********************************************
* Semantically analyze and then evaluate a static condition at compile time.
* This is special because short circuit operators &&, || and ?: at the top
* level are not semantically analyzed if the result of the expression is not
* necessary.
* Params:
* sc = instantiating scope
* original = original expression, for error messages
* e = resulting expression
* errors = set to `true` if errors occurred
* negatives = array to store negative clauses
* Returns:
* true if evaluates to true
*/
bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null)
{
if (negatives)
negatives.setDim(0);
bool impl(Expression e)
{
if (e.isNotExp())
{
NotExp ne = cast(NotExp)e;
return !impl(ne.e1);
}
if (e.op == EXP.andAnd || e.op == EXP.orOr)
{
LogicalExp aae = cast(LogicalExp)e;
bool result = impl(aae.e1);
if (errors)
return false;
if (e.op == EXP.andAnd)
{
if (!result)
return false;
}
else
{
if (result)
return true;
}
result = impl(aae.e2);
return !errors && result;
}
if (e.op == EXP.question)
{
CondExp ce = cast(CondExp)e;
bool result = impl(ce.econd);
if (errors)
return false;
Expression leg = result ? ce.e1 : ce.e2;
result = impl(leg);
return !errors && result;
}
Expression before = e;
const uint nerrors = global.errors;
sc = sc.startCTFE();
sc.flags |= SCOPE.condition;
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
e = e.toBoolean(sc);
sc = sc.endCTFE();
e = e.optimize(WANTvalue);
if (nerrors != global.errors ||
e.isErrorExp() ||
e.type.toBasetype() == Type.terror)
{
errors = true;
return false;
}
e = e.ctfeInterpret();
const opt = e.toBool();
if (opt.isEmpty())
{
if (!e.type.isTypeError())
error(e.loc, "expression `%s` is not constant", e.toChars());
errors = true;
return false;
}
if (negatives && !opt.get())
negatives.push(before);
return opt.get();
}
return impl(e);
}
/********************************************
* Format a static condition as a tree-like structure, marking failed and

View file

@ -36,7 +36,7 @@ public:
// kludge for template.isType()
DYNCAST dyncast() const override { return DYNCAST_TUPLE; }
const char *toChars() const override { return objects.toChars(); }
const char *toChars() const override;
};
struct TemplatePrevious

View file

@ -30,3 +30,28 @@ _Static_assert(SSS[0] == 'h', "10");
#define ABC 12
#define GHI (size) abbadabba
#define DEF (ABC + 5)
#define ADD(a, b) a + b
#define SUB() 3 - 2
#define NO_BODY()
#define NO_BODY_PARAMS(a, b)
#define DO_WHILE() do { } while(0)
#define pr16199_trigger(cond,func,args) _Generic (cond, default: func args)
#define pr16199_skipped1(a) (1)
#define pr16199_skipped2(b) (2)
#define pr16199_ice 0x3
#define M16199Ea(TYPE) (TYPE __x;)
#define M16199E(X,S,M) ({ M16199Ea(S *); })
#define M16199Da(TYPE,VAR) ((TYPE)(VAR))
#define M16199D(X,S,M) ({ int *__x = (X); M16199Da(S *, __x); })
int pr16199d() { return 7; }
#define M16199C(X,S,M) ({ int __x; })
int pr16199c()
{
return 8;
}

View file

@ -15,3 +15,13 @@ static assert(SSS == "hello");
static assert(ABC == 12);
static assert(DEF == 17);
static assert(ADD(3, 4) == 7);
static assert(SUB() == 1);
static assert(pr16199_skipped1(5) == 1);
static assert(pr16199_skipped2(6) == 2);
static assert(pr16199_ice == 3);
static assert(pr16199d() == 7);
static assert(pr16199c() == 8);

View file

@ -3,9 +3,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/warn13679.d(15): Warning: cannot use `foreach_reverse` with an associative array
Error: warnings are treated as errors
Use -wi if you wish to treat warnings only as informational.
fail_compilation/warn13679.d(13): Error: cannot use `foreach_reverse` with an associative array
---
*/

View file

@ -1,4 +1,4 @@
9471b25db9ed44d71e0e27956430c0c6a09c16db
ceff48bf7db05503117f54fdc0cefcb89b711136
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -266,17 +266,17 @@ DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
core/sys/freebsd/sys/elf.d core/sys/freebsd/sys/elf32.d \
core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
core/sys/freebsd/unistd.d
core/sys/freebsd/net/if_.d core/sys/freebsd/net/if_dl.d \
core/sys/freebsd/netinet/in_.d core/sys/freebsd/pthread_np.d \
core/sys/freebsd/stdlib.d core/sys/freebsd/string.d \
core/sys/freebsd/sys/_bitset.d core/sys/freebsd/sys/_cpuset.d \
core/sys/freebsd/sys/cdefs.d core/sys/freebsd/sys/elf.d \
core/sys/freebsd/sys/elf32.d core/sys/freebsd/sys/elf64.d \
core/sys/freebsd/sys/elf_common.d core/sys/freebsd/sys/event.d \
core/sys/freebsd/sys/link_elf.d core/sys/freebsd/sys/mman.d \
core/sys/freebsd/sys/mount.d core/sys/freebsd/sys/socket.d \
core/sys/freebsd/sys/sysctl.d core/sys/freebsd/sys/types.d \
core/sys/freebsd/time.d core/sys/freebsd/unistd.d
DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \

View file

@ -329,10 +329,10 @@ am__objects_11 = core/sys/bionic/err.lo core/sys/bionic/fcntl.lo \
@DRUNTIME_OS_ANDROID_TRUE@am__objects_12 = $(am__objects_11)
am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \
core/sys/freebsd/err.lo core/sys/freebsd/execinfo.lo \
core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_dl.lo \
core/sys/freebsd/netinet/in_.lo core/sys/freebsd/pthread_np.lo \
core/sys/freebsd/stdlib.lo core/sys/freebsd/string.lo \
core/sys/freebsd/sys/_bitset.lo \
core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_.lo \
core/sys/freebsd/net/if_dl.lo core/sys/freebsd/netinet/in_.lo \
core/sys/freebsd/pthread_np.lo core/sys/freebsd/stdlib.lo \
core/sys/freebsd/string.lo core/sys/freebsd/sys/_bitset.lo \
core/sys/freebsd/sys/_cpuset.lo core/sys/freebsd/sys/cdefs.lo \
core/sys/freebsd/sys/elf.lo core/sys/freebsd/sys/elf32.lo \
core/sys/freebsd/sys/elf64.lo \
@ -943,17 +943,17 @@ DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
core/sys/freebsd/sys/elf.d core/sys/freebsd/sys/elf32.d \
core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
core/sys/freebsd/unistd.d
core/sys/freebsd/net/if_.d core/sys/freebsd/net/if_dl.d \
core/sys/freebsd/netinet/in_.d core/sys/freebsd/pthread_np.d \
core/sys/freebsd/stdlib.d core/sys/freebsd/string.d \
core/sys/freebsd/sys/_bitset.d core/sys/freebsd/sys/_cpuset.d \
core/sys/freebsd/sys/cdefs.d core/sys/freebsd/sys/elf.d \
core/sys/freebsd/sys/elf32.d core/sys/freebsd/sys/elf64.d \
core/sys/freebsd/sys/elf_common.d core/sys/freebsd/sys/event.d \
core/sys/freebsd/sys/link_elf.d core/sys/freebsd/sys/mman.d \
core/sys/freebsd/sys/mount.d core/sys/freebsd/sys/socket.d \
core/sys/freebsd/sys/sysctl.d core/sys/freebsd/sys/types.d \
core/sys/freebsd/time.d core/sys/freebsd/unistd.d
DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \
@ -1613,6 +1613,7 @@ core/sys/freebsd/ifaddrs.lo: core/sys/freebsd/$(am__dirstamp)
core/sys/freebsd/net/$(am__dirstamp):
@$(MKDIR_P) core/sys/freebsd/net
@: > core/sys/freebsd/net/$(am__dirstamp)
core/sys/freebsd/net/if_.lo: core/sys/freebsd/net/$(am__dirstamp)
core/sys/freebsd/net/if_dl.lo: core/sys/freebsd/net/$(am__dirstamp)
core/sys/freebsd/netinet/$(am__dirstamp):
@$(MKDIR_P) core/sys/freebsd/netinet

View file

@ -3,7 +3,7 @@
/++
D header file for FreeBSD's ifaddrs.h.
Copyright: Copyright 2023
Copyright: Copyright 2023 - 2024
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: $(HTTP jmdavisprog.com, Jonathan M Davis)
+/
@ -23,6 +23,7 @@ struct ifaddrs
uint ifa_flags;
sockaddr* ifa_addr;
sockaddr* ifa_netmask;
alias ifa_broadaddr = ifa_dstaddr;
sockaddr* ifa_dstaddr;
void* ifa_data;
}

View file

@ -0,0 +1,493 @@
//Written in the D programming language
/++
D header file for FreeBSD's net/if.h.
Copyright: Copyright 2024
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: $(HTTP jmdavisprog.com, Jonathan M Davis)
+/
module core.sys.freebsd.net.if_;
public import core.sys.posix.net.if_;
version (FreeBSD):
extern(C):
@nogc:
nothrow:
import core.stdc.config;
import core.sys.freebsd.sys.types : caddr_t;
import core.sys.posix.sys.socket : sockaddr;
import core.sys.posix.sys.time : time_t, timeval;
enum IF_MAXUNIT = 0x7fff;
struct if_clonereq
{
int ifcr_total;
int ifcr_count;
ubyte* ifcr_buffer;
}
struct if_data
{
ubyte ifi_type;
ubyte ifi_physical;
ubyte ifi_addrlen;
ubyte ifi_hdrlen;
ubyte ifi_link_state;
ubyte ifi_vhid;
ushort ifi_datalen;
uint ifi_mtu;
uint ifi_metric;
ulong ifi_baudrate;
ulong ifi_ipackets;
ulong ifi_ierrors;
ulong ifi_opackets;
ulong ifi_oerrors;
ulong ifi_collisions;
ulong ifi_ibytes;
ulong ifi_obytes;
ulong ifi_imcasts;
ulong ifi_omcasts;
ulong ifi_iqdrops;
ulong ifi_oqdrops;
ulong ifi_noproto;
ulong ifi_hwassist;
union
{
time_t ifi_epoch;
private ulong ph;
}
union
{
timeval ifi_lastchange;
struct
{
private ulong ph1;
private ulong ph2;
}
}
}
enum IFF_UP = 0x1;
enum IFF_BROADCAST = 0x2;
enum IFF_DEBUG = 0x4;
enum IFF_LOOPBACK = 0x8;
enum IFF_POINTOPOINT = 0x10;
enum IFF_NEEDSEPOCH = 0x20;
enum IFF_DRV_RUNNING = 0x40;
enum IFF_NOARP = 0x80;
enum IFF_PROMISC = 0x100;
enum IFF_ALLMULTI = 0x200;
enum IFF_DRV_OACTIVE = 0x400;
enum IFF_SIMPLEX = 0x800;
enum IFF_LINK0 = 0x1000;
enum IFF_LINK1 = 0x2000;
enum IFF_LINK2 = 0x4000;
enum IFF_ALTPHYS = IFF_LINK2;
enum IFF_MULTICAST = 0x8000;
enum IFF_CANTCONFIG = 0x10000;
enum IFF_PPROMISC = 0x20000;
enum IFF_MONITOR = 0x40000;
enum IFF_STATICARP = 0x80000;
enum IFF_STICKYARP = 0x100000;
enum IFF_DYING = 0x200000;
enum IFF_RENAMING = 0x400000;
enum IFF_SPARE = 0x800000;
enum IFF_NETLINK_1 = 0x1000000;
enum IFF_RUNNING = IFF_DRV_RUNNING;
enum IFF_OACTIVE = IFF_DRV_OACTIVE;
enum IFF_CANTCHANGE = IFF_BROADCAST |
IFF_POINTOPOINT |
IFF_DRV_RUNNING |
IFF_DRV_OACTIVE |
IFF_SIMPLEX |
IFF_MULTICAST |
IFF_ALLMULTI |
IFF_PROMISC |
IFF_DYING |
IFF_CANTCONFIG |
IFF_NEEDSEPOCH;
enum LINK_STATE_UNKNOWN = 0;
enum LINK_STATE_DOWN = 1;
enum LINK_STATE_UP = 2;
auto IF_Kbps(T)(T x) { return uintmax_t(x) * 1000; }
auto IF_Mbps(T)(T x) { return IF_Kbps(x * 1000); }
auto IF_Gbps(T)(T x) { return IF_Mbps(x * 1000); }
enum IFCAP_B_RXCSUM = 0;
enum IFCAP_B_TXCSUM = 1;
enum IFCAP_B_NETCONS = 2;
enum IFCAP_B_VLAN_MTU = 3;
enum IFCAP_B_VLAN_HWTAGGING = 4;
enum IFCAP_B_JUMBO_MTU = 5;
enum IFCAP_B_POLLING = 6;
enum IFCAP_B_VLAN_HWCSUM = 7;
enum IFCAP_B_TSO4 = 8;
enum IFCAP_B_TSO6 = 9;
enum IFCAP_B_LRO = 10;
enum IFCAP_B_WOL_UCAST = 11;
enum IFCAP_B_WOL_MCAST = 12;
enum IFCAP_B_WOL_MAGIC = 13;
enum IFCAP_B_TOE4 = 14;
enum IFCAP_B_TOE6 = 15;
enum IFCAP_B_VLAN_HWFILTER = 16;
enum IFCAP_B_NV = 17;
enum IFCAP_B_VLAN_HWTSO = 18;
enum IFCAP_B_LINKSTATE = 19;
enum IFCAP_B_NETMAP = 20;
enum IFCAP_B_RXCSUM_IPV6 = 21;
enum IFCAP_B_TXCSUM_IPV6 = 22;
enum IFCAP_B_HWSTATS = 23;
enum IFCAP_B_TXRTLMT = 24;
enum IFCAP_B_HWRXTSTMP = 25;
enum IFCAP_B_MEXTPG = 26;
enum IFCAP_B_TXTLS4 = 27;
enum IFCAP_B_TXTLS6 = 28;
enum IFCAP_B_VXLAN_HWCSUM = 29;
enum IFCAP_B_VXLAN_HWTSO = 30;
enum IFCAP_B_TXTLS_RTLMT = 31;
enum IFCAP_B_RXTLS4 = 32;
enum IFCAP_B_RXTLS6 = 33;
enum __IFCAP_B_SIZE = 34;
// IFCAP_B_MAX is defined in net/if.h, but __IFCAP_B_MAX doesn't seem to be defined anywhere.
// enum IFCAP_B_MAX = __IFCAP_B_MAX - 1;
enum IFCAP_B_SIZE = __IFCAP_B_SIZE;
auto IFCAP_BIT(T)(T x) { return 1 << x; }
enum IFCAP_RXCSUM = IFCAP_BIT(IFCAP_B_RXCSUM);
enum IFCAP_TXCSUM = IFCAP_BIT(IFCAP_B_TXCSUM);
enum IFCAP_NETCONS = IFCAP_BIT(IFCAP_B_NETCONS);
enum IFCAP_VLAN_MTU = IFCAP_BIT(IFCAP_B_VLAN_MTU);
enum IFCAP_VLAN_HWTAGGING = IFCAP_BIT(IFCAP_B_VLAN_HWTAGGING);
enum IFCAP_JUMBO_MTU = IFCAP_BIT(IFCAP_B_JUMBO_MTU);
enum IFCAP_POLLING = IFCAP_BIT(IFCAP_B_POLLING);
enum IFCAP_VLAN_HWCSUM = IFCAP_BIT(IFCAP_B_VLAN_HWCSUM);
enum IFCAP_TSO4 = IFCAP_BIT(IFCAP_B_TSO4);
enum IFCAP_TSO6 = IFCAP_BIT(IFCAP_B_TSO6);
enum IFCAP_LRO = IFCAP_BIT(IFCAP_B_LRO);
enum IFCAP_WOL_UCAST = IFCAP_BIT(IFCAP_B_WOL_UCAST);
enum IFCAP_WOL_MCAST = IFCAP_BIT(IFCAP_B_WOL_MCAST);
enum IFCAP_WOL_MAGIC = IFCAP_BIT(IFCAP_B_WOL_MAGIC);
enum IFCAP_TOE4 = IFCAP_BIT(IFCAP_B_TOE4);
enum IFCAP_TOE6 = IFCAP_BIT(IFCAP_B_TOE6);
enum IFCAP_VLAN_HWFILTER = IFCAP_BIT(IFCAP_B_VLAN_HWFILTER);
enum IFCAP_NV = IFCAP_BIT(IFCAP_B_NV);
enum IFCAP_VLAN_HWTSO = IFCAP_BIT(IFCAP_B_VLAN_HWTSO);
enum IFCAP_LINKSTATE = IFCAP_BIT(IFCAP_B_LINKSTATE);
enum IFCAP_NETMAP = IFCAP_BIT(IFCAP_B_NETMAP);
enum IFCAP_RXCSUM_IPV6 = IFCAP_BIT(IFCAP_B_RXCSUM_IPV6);
enum IFCAP_TXCSUM_IPV6 = IFCAP_BIT(IFCAP_B_TXCSUM_IPV6);
enum IFCAP_HWSTATS = IFCAP_BIT(IFCAP_B_HWSTATS);
enum IFCAP_TXRTLMT = IFCAP_BIT(IFCAP_B_TXRTLMT);
enum IFCAP_HWRXTSTMP = IFCAP_BIT(IFCAP_B_HWRXTSTMP);
enum IFCAP_MEXTPG = IFCAP_BIT(IFCAP_B_MEXTPG);
enum IFCAP_TXTLS4 = IFCAP_BIT(IFCAP_B_TXTLS4);
enum IFCAP_TXTLS6 = IFCAP_BIT(IFCAP_B_TXTLS6);
enum IFCAP_VXLAN_HWCSUM = IFCAP_BIT(IFCAP_B_VXLAN_HWCSUM);
enum IFCAP_VXLAN_HWTSO = IFCAP_BIT(IFCAP_B_VXLAN_HWTSO);
enum IFCAP_TXTLS_RTLMT = IFCAP_BIT(IFCAP_B_TXTLS_RTLMT);
enum IFCAP2_RXTLS4 = IFCAP_B_RXTLS4 - 32;
enum IFCAP2_RXTLS6 = IFCAP_B_RXTLS6 - 32;
auto IFCAP2_BIT(T)(T x) { return 1UL << x; }
enum IFCAP_HWCSUM_IPV6 = IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6;
enum IFCAP_HWCSUM = IFCAP_RXCSUM | IFCAP_TXCSUM;
enum IFCAP_TSO = IFCAP_TSO4 | IFCAP_TSO6;
enum IFCAP_WOL = IFCAP_WOL_UCAST | IFCAP_WOL_MCAST | IFCAP_WOL_MAGIC;
enum IFCAP_TOE = IFCAP_TOE4 | IFCAP_TOE6;
enum IFCAP_TXTLS = IFCAP_TXTLS4 | IFCAP_TXTLS6;
enum IFCAP_CANTCHANGE = IFCAP_NETMAP | IFCAP_NV;
enum IFCAP_ALLCAPS = 0xffffffff;
enum IFQ_MAXLEN = 50;
enum IFNET_SLOWHZ = 1;
struct if_msghdr
{
ushort ifm_msglen;
ubyte ifm_version;
ubyte ifm_type;
int ifm_addrs;
int ifm_flags;
ushort ifm_index;
ushort _ifm_spare1;
if_data ifm_data;
}
auto IF_MSGHDRL_IFM_DATA(T)(T _l) { return cast(if_data*) (cast(ubyte*) _l + _l.ifm_data_off); }
auto IF_MSGHDRL_RTA(T)(T_l) { return cast(void*) (cast(uintptr_t) _l + _l.ifm_len); }
struct if_msghdrl
{
ushort ifm_msglen;
ubyte ifm_version;
ubyte ifm_type;
int ifm_addrs;
int ifm_flags;
ushort ifm_index;
ushort _ifm_spare1;
ushort ifm_len;
ushort ifm_data_off;
int _ifm_spare2;
if_data ifm_data;
}
struct ifa_msghdr
{
ushort ifam_msglen;
ubyte ifam_version;
ubyte ifam_type;
int ifam_addrs;
int ifam_flags;
ushort ifam_index;
ushort _ifam_spare1;
int ifam_metric;
}
auto IFA_MSGHDRL_IFAM_DATA(T)(T _l) { return cast(if_data*) (cast(ubyte*) _l + _l.ifam_data_off); }
auto IFA_MSGHDRL_RTA(T)(T _l) { return cast(void*) (cast(uintptr_t) _l + _l.ifam_len); }
struct ifa_msghdrl
{
ushort ifam_msglen;
ubyte ifam_version;
ubyte ifam_type;
int ifam_addrs;
int ifam_flags;
ushort ifam_index;
ushort _ifam_spare1;
ushort ifam_len;
ushort ifam_data_off;
int ifam_metric;
if_data ifam_data;
}
struct ifma_msghdr
{
ushort ifmam_msglen;
ubyte ifmam_version;
ubyte ifmam_type;
int ifmam_addrs;
int ifmam_flags;
ushort ifmam_index;
ushort _ifmam_spare1;
}
struct if_announcemsghdr
{
ushort ifan_msglen;
ubyte ifan_version;
ubyte ifan_type;
ushort ifan_index;
char[IF_NAMESIZE] ifan_name;
ushort ifan_what;
}
enum IFAN_ARRIVAL = 0;
enum IFAN_DEPARTURE = 1;
struct ifreq_buffer
{
size_t length;
void* buffer;
}
struct ifreq_nv_req
{
uint buf_length;
uint length;
void* buffer;
}
enum IFR_CAP_NV_MAXBUFSIZE = 2 * 1024 * 1024;
struct ifreq
{
char[IF_NAMESIZE] ifr_name;
union
{
sockaddr ifr_addr;
sockaddr ifr_dstaddr;
sockaddr ifr_broadaddr;
ifreq_buffer ifr_buffer;
private short[2] ifru_flags;
short ifr_index;
int ifr_jid;
int ifr_metric;
int ifr_mtu;
int ifr_phys;
int ifr_media;
caddr_t ifr_data;
private int[2] ifru_cap;
uint ifr_fib;
ubyte ifr_vlan_pcp;
ifreq_nv_req ifr_cap_nv;
}
@property ref ifr_flags() { return ifru_flags[0]; }
@property ref ifr_flagshigh() { return ifru_flags[1]; }
@property ref ifr_reqcap() { return ifru_cap[0]; }
@property ref ifr_curcap() { return ifru_cap[1]; }
alias ifr_lan_pcp = ifr_vlan_pcp;
}
auto _SIZEOF_ADDR_IFREQ(T)(T ifr) { return ifr.ifr_addr.sa_len > sockaddr.sizeof ?
ifreq.sizeof - sockaddr.sizeof + ifr.ifr_addr.sa_len :
ifreq.sizeof; }
struct ifaliasreq
{
char[IF_NAMESIZE] ifra_name;
sockaddr ifra_addr;
sockaddr ifra_broadaddr;
sockaddr ifra_mask;
int ifra_vhid;
}
struct oifaliasreq
{
char[IF_NAMESIZE] ifra_name;
sockaddr ifra_addr;
sockaddr ifra_broadaddr;
sockaddr ifra_mask;
}
struct ifmediareq
{
char[IF_NAMESIZE] ifm_name;
int ifm_current;
int ifm_mask;
int ifm_status;
int ifm_active;
int ifm_count;
int* ifm_ulist;
}
struct ifdrv
{
char[IF_NAMESIZE] ifd_name;
c_ulong ifd_cmd;
size_t ifd_len;
void* ifd_data;
}
enum IFSTATMAX = 800;
struct ifstat
{
char[IF_NAMESIZE] ifs_name;
char[IFSTATMAX + 1] ascii;
}
struct ifconf
{
int ifc_len;
union
{
caddr_t ifc_buf;
ifreq* ifc_req;
}
}
enum IFG_ALL = "all";
enum IFG_EGRESS = "egress";
struct ifg_req
{
union
{
char[IF_NAMESIZE] ifgrq_group;
char[IF_NAMESIZE] ifgrq_member;
}
}
struct ifgroupreq
{
char[IF_NAMESIZE] ifgr_name;
uint ifgr_len;
union
{
char[IF_NAMESIZE] ifgr_group;
ifg_req* ifgr_groups;
}
}
struct ifi2creq
{
ubyte dev_addr;
ubyte offset;
ubyte len;
ubyte spare0;
uint spare1;
ubyte[8] data;
}
enum RSS_FUNC_NONE = 0;
enum RSS_FUNC_PRIVATE = 1;
enum RSS_FUNC_TOEPLITZ = 2;
enum RSS_TYPE_IPV4 = 0x00000001;
enum RSS_TYPE_TCP_IPV4 = 0x00000002;
enum RSS_TYPE_IPV6 = 0x00000004;
enum RSS_TYPE_IPV6_EX = 0x00000008;
enum RSS_TYPE_TCP_IPV6 = 0x00000010;
enum RSS_TYPE_TCP_IPV6_EX = 0x00000020;
enum RSS_TYPE_UDP_IPV4 = 0x00000040;
enum RSS_TYPE_UDP_IPV6 = 0x00000080;
enum RSS_TYPE_UDP_IPV6_EX = 0x00000100;
enum RSS_KEYLEN = 128;
struct ifrsskey
{
char[IF_NAMESIZE] ifrk_name;
ubyte ifrk_func;
ubyte ifrk_spare0;
ushort ifrk_keylen;
ubyte[RSS_KEYLEN] ifrk_key;
}
struct ifrsshash
{
char[IF_NAMESIZE] ifrh_name;
ubyte ifrh_func;
ubyte ifrh_spare0;
ushort ifrh_spare1;
uint ifrh_types;
}
enum IFNET_PCP_NONE = 0xff;
enum IFDR_MSG_SIZE = 64;
enum IFDR_REASON_MSG = 1;
enum IFDR_REASON_VENDOR = 2;
struct ifdownreason
{
char[IF_NAMESIZE] ifdr_name;
uint ifdr_reason;
uint ifdr_vendor;
char[IFDR_MSG_SIZE] ifdr_msg;
}
// FIXME It's not clear where ifnet is supposed to be coming from, so this is
// commented out for now.
//alias if_t = ifnet*;

View file

@ -71,7 +71,6 @@ enum
AF_BRIDGE = PF_BRIDGE,
AF_ATMPVC = PF_ATMPVC,
AF_X25 = PF_X25,
AF_INET6 = PF_INET6,
AF_ROSE = PF_ROSE,
AF_DECnet = PF_DECnet,
AF_NETBEUI = PF_NETBEUI,

View file

@ -1393,7 +1393,7 @@ private:
// At present, it is not safe to migrate fibers between threads, but if that
// changes, then updating the value of R13 will also need to be handled.
version (PPC64)
*cast(size_t*)(pstack + wsize) = cast(size_t) Thread.getThis().m_addr;
*cast(size_t*)(pstack + wsize) = cast(size_t) ThreadBase.getThis().m_addr;
assert( (cast(size_t) pstack & 0x0f) == 0 );
}
else version (AsmMIPS_O32_Posix)

View file

@ -1,4 +1,4 @@
5478868465ae1ad743ff76ac5bb92691463ffec5
dcbfbd43ac321e81af60afd795bd0f3c3f47cfa0
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.

View file

@ -3276,7 +3276,9 @@ struct Nullable(T)
{
if (!_isNull)
{
destroy(_value.payload);
import std.traits : Unqual;
auto ptr = () @trusted { return cast(Unqual!T*) &_value.payload; }();
destroy!false(*ptr);
}
}
}
@ -4319,6 +4321,37 @@ auto nullable(T)(T t)
assert(b.empty);
}
// https://issues.dlang.org/show_bug.cgi?id=24403
@safe unittest
{
static bool destroyed;
static struct S { ~this() { destroyed = true; } }
{
Nullable!S s = S.init;
destroyed = false;
}
assert(destroyed);
{
Nullable!(const S) s = S.init;
destroyed = false;
}
assert(destroyed);
{
Nullable!(immutable S) s = S.init;
destroyed = false;
}
assert(destroyed);
{
Nullable!(shared S) s = S.init;
destroyed = false;
}
assert(destroyed);
}
/**
Just like `Nullable!T`, except that the null state is defined as a
particular value. For example, $(D Nullable!(uint, uint.max)) is an