d: Merge upstream dmd 4d1bfcf14, druntime 9ba9a6ae, phobos c0cc5e917.
D front-end changes: - Import dmd v2.099.1. - Added `@mustuse' attribute, implmenting DIP 1038. - Added `.tupleof` property for static arrays D runtime changes: - Import druntime v2.099.1. Phobos changes: - Import phobos v2.099.1. - Zlib bindings have been updated to 1.2.12. gcc/d/ChangeLog: * Make-lang.in (D_FRONTEND_OBJS): Add d/common-bitfields.o, d/mustuse.o. * d-ctfloat.cc (CTFloat::isIdentical): Don't treat NaN values as identical. * dmd/MERGE: Merge upstream dmd 4d1bfcf14. * expr.cc (ExprVisitor::visit (VoidInitExp *)): New. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 9ba9a6ae. * src/MERGE: Merge upstream phobos c0cc5e917.
This commit is contained in:
parent
ca145c6306
commit
31350635bf
93 changed files with 1780 additions and 663 deletions
|
@ -89,6 +89,7 @@ D_FRONTEND_OBJS = \
|
|||
d/canthrow.o \
|
||||
d/chkformat.o \
|
||||
d/clone.o \
|
||||
d/common-bitfields.o \
|
||||
d/common-file.o \
|
||||
d/common-outbuffer.o \
|
||||
d/common-string.o \
|
||||
|
@ -143,6 +144,7 @@ D_FRONTEND_OBJS = \
|
|||
d/lambdacomp.o \
|
||||
d/lexer.o \
|
||||
d/mtype.o \
|
||||
d/mustuse.o \
|
||||
d/nogc.o \
|
||||
d/nspace.o \
|
||||
d/ob.o \
|
||||
|
|
|
@ -55,8 +55,7 @@ CTFloat::isIdentical (real_t x, real_t y)
|
|||
{
|
||||
real_value rx = x.rv ();
|
||||
real_value ry = y.rv ();
|
||||
return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
|
||||
|| real_identical (&rx, &ry);
|
||||
return real_identical (&rx, &ry);
|
||||
}
|
||||
|
||||
/* Return true if real_t value R is NaN. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
47871363d804f54b29ccfd444b082c19716c2301
|
||||
4d1bfcf142928cf1c097b0a2689485c1b14f4f53
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -130,6 +130,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
|
|||
| [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d) | Define an implicit conversion table for basic types |
|
||||
| [importc.d](https://github.com/dlang/dmd/blob/master/src/dmd/importc.d) | Helpers specific to ImportC |
|
||||
| [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings. |
|
||||
| [mustuse.d](https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d) | Helpers related to the `@mustuse` attribute |
|
||||
|
||||
|
||||
**Compile Time Function Execution (CTFE)**
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
v2.099.1-beta.1
|
||||
v2.099.1
|
||||
|
|
|
@ -158,7 +158,7 @@ Expression arrayOp(BinExp e, Scope* sc)
|
|||
/// ditto
|
||||
Expression arrayOp(BinAssignExp e, Scope* sc)
|
||||
{
|
||||
//printf("BinAssignExp.arrayOp() %s\n", toChars());
|
||||
//printf("BinAssignExp.arrayOp() %s\n", e.toChars());
|
||||
|
||||
/* Check that the elements of e1 can be assigned to
|
||||
*/
|
||||
|
|
|
@ -44,7 +44,6 @@ import dmd.mtype;
|
|||
import dmd.objc; // for objc.addSymbols
|
||||
import dmd.common.outbuffer;
|
||||
import dmd.root.array; // for each
|
||||
import dmd.target; // for target.systemLinkage
|
||||
import dmd.tokens;
|
||||
import dmd.visitor;
|
||||
|
||||
|
@ -399,7 +398,7 @@ extern (C++) final class LinkDeclaration : AttribDeclaration
|
|||
{
|
||||
super(loc, null, decl);
|
||||
//printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
|
||||
this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage;
|
||||
this.linkage = linkage;
|
||||
}
|
||||
|
||||
static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl)
|
||||
|
@ -994,7 +993,7 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
|
|||
// Decide if 'then' or 'else' code should be included
|
||||
override Dsymbols* include(Scope* sc)
|
||||
{
|
||||
//printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope);
|
||||
//printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
|
||||
|
||||
if (errors)
|
||||
return null;
|
||||
|
@ -1057,7 +1056,7 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
|
|||
*/
|
||||
override Dsymbols* include(Scope* sc)
|
||||
{
|
||||
//printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope);
|
||||
//printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
|
||||
|
||||
if (errors || onStack)
|
||||
return null;
|
||||
|
@ -1496,12 +1495,7 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
|
|||
if (global.params.cplusplus < CppStdRevision.cpp11)
|
||||
return;
|
||||
|
||||
// Avoid `if` at the call site
|
||||
if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
|
||||
return;
|
||||
|
||||
foreach (exp; *sym.userAttribDecl.atts)
|
||||
{
|
||||
foreachUdaNoSemantic(sym, (exp) {
|
||||
if (isGNUABITag(exp))
|
||||
{
|
||||
if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
|
||||
|
@ -1515,9 +1509,10 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
|
|||
sym.errors = true;
|
||||
}
|
||||
// Only one `@gnuAbiTag` is allowed by semantic2
|
||||
return;
|
||||
return 1; // break
|
||||
}
|
||||
}
|
||||
return 0; // continue
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1544,14 +1539,14 @@ bool isCoreUda(Dsymbol sym, Identifier ident)
|
|||
/**
|
||||
* Iterates the UDAs attached to the given symbol.
|
||||
*
|
||||
* If `dg` returns `!= 0`, it will stop the iteration and return that
|
||||
* value, otherwise it will return 0.
|
||||
*
|
||||
* Params:
|
||||
* sym = the symbol to get the UDAs from
|
||||
* sc = scope to use for semantic analysis of UDAs
|
||||
* dg = called once for each UDA. If `dg` returns `!= 0`, it will stop the
|
||||
* iteration and return that value, otherwise it will return `0`.
|
||||
* dg = called once for each UDA
|
||||
*
|
||||
* Returns:
|
||||
* If `dg` returns `!= 0`, stops the iteration and returns that value.
|
||||
* Otherwise, returns 0.
|
||||
*/
|
||||
int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
|
||||
{
|
||||
|
@ -1577,3 +1572,32 @@ int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates the UDAs attached to the given symbol, without performing semantic
|
||||
* analysis.
|
||||
*
|
||||
* Use this function instead of `foreachUda` if semantic analysis of `sym` is
|
||||
* still in progress.
|
||||
*
|
||||
* Params:
|
||||
* sym = the symbol to get the UDAs from
|
||||
* dg = called once for each UDA
|
||||
*
|
||||
* Returns:
|
||||
* If `dg` returns `!= 0`, stops the iteration and returns that value.
|
||||
* Otherwise, returns 0.
|
||||
*/
|
||||
int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
|
||||
{
|
||||
if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
|
||||
return 0;
|
||||
|
||||
foreach (exp; *sym.userAttribDecl.atts)
|
||||
{
|
||||
if (auto result = dg(exp))
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
| File | Purpose |
|
||||
|------------------------------------------------------------------------------------|-----------------------------------------------------------------|
|
||||
| [bitfields.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields |
|
||||
| [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management |
|
||||
| [outbuffer.d](https://github.com/dlang/dmd/blob/master/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/src/dmd/common/string.d) | Common string functions including filename manipulation |
|
||||
|
|
70
gcc/d/dmd/common/bitfields.d
Normal file
70
gcc/d/dmd/common/bitfields.d
Normal file
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* A library bitfields utility
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
|
||||
* Authors: Dennis Korpel
|
||||
* 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/bitfields.d, common/bitfields.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_common_bitfields.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/bitfields.d
|
||||
*/
|
||||
module dmd.common.bitfields;
|
||||
|
||||
/**
|
||||
* Generate code for bit fields inside a struct/class body
|
||||
* Params:
|
||||
* S = type of a struct with only boolean fields, which should become bit fields
|
||||
* T = type of bit fields variable, must have enough bits to store all booleans
|
||||
* Returns: D code with a bit fields variable and getter / setter functions
|
||||
*/
|
||||
extern (D) string generateBitFields(S, T)()
|
||||
if (__traits(isUnsigned, T))
|
||||
{
|
||||
string result = "extern (C++) pure nothrow @nogc @safe final {";
|
||||
enum structName = __traits(identifier, S);
|
||||
|
||||
foreach (size_t i, mem; __traits(allMembers, S))
|
||||
{
|
||||
static assert(is(typeof(__traits(getMember, S, mem)) == bool));
|
||||
static assert(i < T.sizeof * 8, "too many fields for bit field storage of type `"~T.stringof~"`");
|
||||
enum mask = "(1 << "~i.stringof~")";
|
||||
result ~= "
|
||||
/// set or get the corresponding "~structName~" member
|
||||
bool "~mem~"() const { return !!(bitFields & "~mask~"); }
|
||||
/// ditto
|
||||
bool "~mem~"(bool v)
|
||||
{
|
||||
v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
|
||||
return v;
|
||||
}";
|
||||
}
|
||||
return result ~ "}\n private "~T.stringof~" bitFields;\n";
|
||||
}
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
static struct B
|
||||
{
|
||||
bool x;
|
||||
bool y;
|
||||
bool z;
|
||||
}
|
||||
|
||||
static struct S
|
||||
{
|
||||
mixin(generateBitFields!(B, ubyte));
|
||||
}
|
||||
|
||||
S s;
|
||||
assert(!s.x);
|
||||
s.x = true;
|
||||
assert(s.x);
|
||||
s.x = false;
|
||||
assert(!s.x);
|
||||
|
||||
s.y = true;
|
||||
assert(s.y);
|
||||
assert(!s.x);
|
||||
assert(!s.z);
|
||||
}
|
|
@ -25,6 +25,8 @@ import core.sys.posix.unistd;
|
|||
|
||||
import dmd.common.string;
|
||||
|
||||
nothrow:
|
||||
|
||||
/**
|
||||
Encapsulated management of a memory-mapped file.
|
||||
|
||||
|
@ -52,6 +54,8 @@ struct FileMapping(Datum)
|
|||
private const(char)* name;
|
||||
// state }
|
||||
|
||||
nothrow:
|
||||
|
||||
/**
|
||||
Open `filename` and map it in memory. If `Datum` is `const`, opens for
|
||||
read-only and maps the content in memory; no error is issued if the file
|
||||
|
|
|
@ -16,6 +16,8 @@ import core.stdc.stdio;
|
|||
import core.stdc.string;
|
||||
import core.stdc.stdlib;
|
||||
|
||||
nothrow:
|
||||
|
||||
// In theory these functions should also restore errno, but we don't care because
|
||||
// we abort application on error anyway.
|
||||
extern (C) private pure @system @nogc nothrow
|
||||
|
@ -54,6 +56,8 @@ struct OutBuffer
|
|||
int level;
|
||||
// state }
|
||||
|
||||
nothrow:
|
||||
|
||||
/**
|
||||
Construct given size.
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
*/
|
||||
module dmd.common.string;
|
||||
|
||||
nothrow:
|
||||
|
||||
/**
|
||||
Defines a temporary array using a fixed-length buffer as back store. If the length
|
||||
of the buffer suffices, it is readily used. Otherwise, `malloc` is used to
|
||||
|
@ -26,6 +28,8 @@ struct SmallBuffer(T)
|
|||
private T[] _extent;
|
||||
private bool needsFree;
|
||||
|
||||
nothrow:
|
||||
|
||||
@disable this(); // no default ctor
|
||||
@disable this(ref const SmallBuffer!T); // noncopyable, nonassignable
|
||||
|
||||
|
|
|
@ -936,7 +936,7 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
|
|||
{
|
||||
if (e1.type.isreal())
|
||||
{
|
||||
cmp = RealIdentical(e1.toReal(), e2.toReal());
|
||||
cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
|
||||
}
|
||||
else if (e1.type.isimaginary())
|
||||
{
|
||||
|
|
|
@ -1269,7 +1269,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
|||
real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
|
||||
real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
|
||||
if (identity)
|
||||
return !RealIdentical(r1, r2);
|
||||
return !CTFloat.isIdentical(r1, r2);
|
||||
if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
|
||||
{
|
||||
return 1; // they are not equal
|
||||
|
@ -1399,7 +1399,7 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
|
|||
cmp = (es1.var == es2.var && es1.offset == es2.offset);
|
||||
}
|
||||
else if (e1.type.isreal())
|
||||
cmp = RealIdentical(e1.toReal(), e2.toReal());
|
||||
cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
|
||||
else if (e1.type.isimaginary())
|
||||
cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
|
||||
else if (e1.type.iscomplex())
|
||||
|
|
|
@ -432,7 +432,7 @@ MATCH implicitConvTo(Expression e, Type t)
|
|||
return MATCH.nomatch;
|
||||
goto case Tuns8;
|
||||
case Tuns8:
|
||||
//printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
|
||||
//printf("value = %llu %llu\n", cast(dinteger_t)cast(ubyte)value, value);
|
||||
if (cast(ubyte)value != value)
|
||||
return MATCH.nomatch;
|
||||
break;
|
||||
|
@ -492,8 +492,8 @@ MATCH implicitConvTo(Expression e, Type t)
|
|||
break;
|
||||
|
||||
case Tpointer:
|
||||
//printf("type = %s\n", type.toBasetype()->toChars());
|
||||
//printf("t = %s\n", t.toBasetype()->toChars());
|
||||
//printf("type = %s\n", type.toBasetype().toChars());
|
||||
//printf("t = %s\n", t.toBasetype().toChars());
|
||||
if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty)
|
||||
{
|
||||
/* Allow things like:
|
||||
|
@ -1107,6 +1107,10 @@ MATCH implicitConvTo(Expression e, Type t)
|
|||
|
||||
MATCH visitCond(CondExp e)
|
||||
{
|
||||
auto result = visit(e);
|
||||
if (result != MATCH.nomatch)
|
||||
return result;
|
||||
|
||||
MATCH m1 = e.e1.implicitConvTo(t);
|
||||
MATCH m2 = e.e2.implicitConvTo(t);
|
||||
//printf("CondExp: m1 %d m2 %d\n", m1, m2);
|
||||
|
@ -2077,7 +2081,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
|
|||
if (auto tsa = tb.isTypeSArray())
|
||||
{
|
||||
size_t dim2 = cast(size_t)tsa.dim.toInteger();
|
||||
//printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2);
|
||||
//printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
|
||||
|
||||
// Changing dimensions
|
||||
if (dim2 != se.len)
|
||||
|
|
|
@ -1083,29 +1083,12 @@ extern (C++) class VarDeclaration : Declaration
|
|||
bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument
|
||||
}
|
||||
|
||||
private ushort bitFields; // stores multiple booleans for BitFields
|
||||
import dmd.common.bitfields : generateBitFields;
|
||||
mixin(generateBitFields!(BitFields, ushort));
|
||||
|
||||
byte canassign; // it can be assigned to
|
||||
ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false
|
||||
|
||||
// Generate getter and setter functions for `bitFields`
|
||||
extern (D) mixin(() {
|
||||
string result = "extern (C++) pure nothrow @nogc @safe final {";
|
||||
foreach (size_t i, mem; __traits(allMembers, BitFields))
|
||||
{
|
||||
result ~= "
|
||||
/// set or get the corresponding BitFields member
|
||||
bool "~mem~"() const { return !!(bitFields & (1 << "~i.stringof~")); }
|
||||
/// ditto
|
||||
bool "~mem~"(bool v)
|
||||
{
|
||||
v ? (bitFields |= (1 << "~i.stringof~")) : (bitFields &= ~(1 << "~i.stringof~"));
|
||||
return v;
|
||||
}";
|
||||
}
|
||||
return result ~ "}";
|
||||
}());
|
||||
|
||||
|
||||
final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
|
||||
in
|
||||
{
|
||||
|
|
|
@ -340,7 +340,6 @@ public:
|
|||
final switch (t.linkage)
|
||||
{
|
||||
case LINK.default_:
|
||||
case LINK.system:
|
||||
case LINK.d:
|
||||
mc = 'F';
|
||||
break;
|
||||
|
@ -356,6 +355,8 @@ public:
|
|||
case LINK.objc:
|
||||
mc = 'Y';
|
||||
break;
|
||||
case LINK.system:
|
||||
assert(0);
|
||||
}
|
||||
buf.writeByte(mc);
|
||||
|
||||
|
@ -1340,7 +1341,9 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
|
|||
{
|
||||
if (d.linkage != LINK.d && d.localNum)
|
||||
d.error("the same declaration cannot be in multiple scopes with non-D linkage");
|
||||
final switch (d.linkage)
|
||||
|
||||
const l = d.linkage == LINK.system ? target.systemLinkage() : d.linkage;
|
||||
final switch (l)
|
||||
{
|
||||
case LINK.d:
|
||||
break;
|
||||
|
@ -1354,9 +1357,10 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
|
|||
return p.toDString();
|
||||
}
|
||||
case LINK.default_:
|
||||
case LINK.system:
|
||||
d.error("forward declaration");
|
||||
return d.ident.toString();
|
||||
case LINK.system:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -69,7 +69,7 @@ void semantic3OnDependencies(Module m)
|
|||
/**
|
||||
* Remove generated .di files on error and exit
|
||||
*/
|
||||
void removeHdrFilesAndFail(ref Param params, ref Modules modules)
|
||||
void removeHdrFilesAndFail(ref Param params, ref Modules modules) nothrow
|
||||
{
|
||||
if (params.doHdrGeneration)
|
||||
{
|
||||
|
@ -94,7 +94,7 @@ void removeHdrFilesAndFail(ref Param params, ref Modules modules)
|
|||
* Returns:
|
||||
* the filename of the child package or module
|
||||
*/
|
||||
private const(char)[] getFilename(Identifier[] packages, Identifier ident)
|
||||
private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothrow
|
||||
{
|
||||
const(char)[] filename = ident.toString();
|
||||
|
||||
|
@ -157,14 +157,14 @@ extern (C++) class Package : ScopeDsymbol
|
|||
uint tag; // auto incremented tag, used to mask package tree in scopes
|
||||
Module mod; // !=null if isPkgMod == PKG.module_
|
||||
|
||||
final extern (D) this(const ref Loc loc, Identifier ident)
|
||||
final extern (D) this(const ref Loc loc, Identifier ident) nothrow
|
||||
{
|
||||
super(loc, ident);
|
||||
__gshared uint packageTag;
|
||||
this.tag = packageTag++;
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
override const(char)* kind() const nothrow
|
||||
{
|
||||
return "package";
|
||||
}
|
||||
|
@ -664,7 +664,7 @@ extern (C++) final class Module : Package
|
|||
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
|
||||
if (auto result = global.fileManager.lookup(srcfile))
|
||||
{
|
||||
this.src = result.data;
|
||||
this.src = result;
|
||||
if (global.params.emitMakeDeps)
|
||||
global.params.makeDeps.push(srcfile.toChars());
|
||||
return true;
|
||||
|
@ -1380,7 +1380,7 @@ extern (C++) final class Module : Package
|
|||
a.setDim(0);
|
||||
}
|
||||
|
||||
extern (D) static void clearCache()
|
||||
extern (D) static void clearCache() nothrow
|
||||
{
|
||||
foreach (Module m; amodules)
|
||||
m.searchCacheIdent = null;
|
||||
|
@ -1391,7 +1391,7 @@ extern (C++) final class Module : Package
|
|||
* return true if it imports m.
|
||||
* Can be used to detect circular imports.
|
||||
*/
|
||||
int imports(Module m)
|
||||
int imports(Module m) nothrow
|
||||
{
|
||||
//printf("%s Module::imports(%s)\n", toChars(), m.toChars());
|
||||
version (none)
|
||||
|
@ -1414,14 +1414,14 @@ extern (C++) final class Module : Package
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isRoot()
|
||||
bool isRoot() nothrow
|
||||
{
|
||||
return this.importedFrom == this;
|
||||
}
|
||||
|
||||
// true if the module source file is directly
|
||||
// listed in command line.
|
||||
bool isCoreModule(Identifier ident)
|
||||
bool isCoreModule(Identifier ident) nothrow
|
||||
{
|
||||
return this.ident == ident && parent && parent.ident == Id.core && !parent.parent;
|
||||
}
|
||||
|
@ -1440,7 +1440,7 @@ extern (C++) final class Module : Package
|
|||
|
||||
uint[uint] ctfe_cov; /// coverage information from ctfe execution_count[line]
|
||||
|
||||
override inout(Module) isModule() inout
|
||||
override inout(Module) isModule() inout nothrow
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
@ -1455,7 +1455,7 @@ extern (C++) final class Module : Package
|
|||
* Params:
|
||||
* buf = The buffer to write to
|
||||
*/
|
||||
void fullyQualifiedName(ref OutBuffer buf)
|
||||
void fullyQualifiedName(ref OutBuffer buf) nothrow
|
||||
{
|
||||
buf.writestring(ident.toString());
|
||||
|
||||
|
@ -1469,7 +1469,7 @@ extern (C++) final class Module : Package
|
|||
/** Lazily initializes and returns the escape table.
|
||||
Turns out it eats a lot of memory.
|
||||
*/
|
||||
extern(D) Escape* escapetable()
|
||||
extern(D) Escape* escapetable() nothrow
|
||||
{
|
||||
if (!_escapetable)
|
||||
_escapetable = new Escape();
|
||||
|
|
|
@ -112,12 +112,12 @@ struct Ungag
|
|||
{
|
||||
uint oldgag;
|
||||
|
||||
extern (D) this(uint old)
|
||||
extern (D) this(uint old) nothrow
|
||||
{
|
||||
this.oldgag = old;
|
||||
}
|
||||
|
||||
extern (C++) ~this()
|
||||
extern (C++) ~this() nothrow
|
||||
{
|
||||
global.gag = oldgag;
|
||||
}
|
||||
|
@ -255,27 +255,27 @@ extern (C++) class Dsymbol : ASTNode
|
|||
DeprecatedDeclaration depdecl; // customized deprecation message
|
||||
UserAttributeDeclaration userAttribDecl; // user defined attributes
|
||||
|
||||
final extern (D) this()
|
||||
final extern (D) this() nothrow
|
||||
{
|
||||
//printf("Dsymbol::Dsymbol(%p)\n", this);
|
||||
loc = Loc(null, 0, 0);
|
||||
}
|
||||
|
||||
final extern (D) this(Identifier ident)
|
||||
final extern (D) this(Identifier ident) nothrow
|
||||
{
|
||||
//printf("Dsymbol::Dsymbol(%p, ident)\n", this);
|
||||
this.loc = Loc(null, 0, 0);
|
||||
this.ident = ident;
|
||||
}
|
||||
|
||||
final extern (D) this(const ref Loc loc, Identifier ident)
|
||||
final extern (D) this(const ref Loc loc, Identifier ident) nothrow
|
||||
{
|
||||
//printf("Dsymbol::Dsymbol(%p, ident)\n", this);
|
||||
this.loc = loc;
|
||||
this.ident = ident;
|
||||
}
|
||||
|
||||
static Dsymbol create(Identifier ident)
|
||||
static Dsymbol create(Identifier ident) nothrow
|
||||
{
|
||||
return new Dsymbol(ident);
|
||||
}
|
||||
|
@ -800,6 +800,22 @@ extern (C++) class Dsymbol : ASTNode
|
|||
if (isAliasDeclaration() && !_scope)
|
||||
setScope(sc);
|
||||
Dsymbol s2 = sds.symtabLookup(this,ident);
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=17434
|
||||
*
|
||||
* If we are trying to add an import to the symbol table
|
||||
* that has already been introduced, then keep the one with
|
||||
* larger visibility. This is fine for imports because if
|
||||
* we have multiple imports of the same file, if a single one
|
||||
* is public then the symbol is reachable.
|
||||
*/
|
||||
if (auto i1 = isImport())
|
||||
{
|
||||
if (auto i2 = s2.isImport())
|
||||
{
|
||||
if (sc.explicitVisibility && sc.visibility > i2.visibility)
|
||||
sds.symtab.update(this);
|
||||
}
|
||||
}
|
||||
|
||||
// If using C tag/prototype/forward declaration rules
|
||||
if (sc.flags & SCOPE.Cfile && !this.isImport())
|
||||
|
@ -933,14 +949,7 @@ extern (C++) class Dsymbol : ASTNode
|
|||
TemplateInstance ti = st.isTemplateInstance();
|
||||
sm = s.search(loc, ti.name);
|
||||
if (!sm)
|
||||
{
|
||||
sm = s.search_correct(ti.name);
|
||||
if (sm)
|
||||
.error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?", ti.name.toChars(), s.kind(), s.toPrettyChars(), sm.kind(), sm.toChars());
|
||||
else
|
||||
.error(loc, "template identifier `%s` is not a member of %s `%s`", ti.name.toChars(), s.kind(), s.toPrettyChars());
|
||||
return null;
|
||||
}
|
||||
sm = sm.toAlias();
|
||||
TemplateDeclaration td = sm.isTemplateDeclaration();
|
||||
if (!td)
|
||||
|
@ -1381,16 +1390,16 @@ private:
|
|||
BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
|
||||
|
||||
public:
|
||||
final extern (D) this()
|
||||
final extern (D) this() nothrow
|
||||
{
|
||||
}
|
||||
|
||||
final extern (D) this(Identifier ident)
|
||||
final extern (D) this(Identifier ident) nothrow
|
||||
{
|
||||
super(ident);
|
||||
}
|
||||
|
||||
final extern (D) this(const ref Loc loc, Identifier ident)
|
||||
final extern (D) this(const ref Loc loc, Identifier ident) nothrow
|
||||
{
|
||||
super(loc, ident);
|
||||
}
|
||||
|
@ -1604,7 +1613,7 @@ public:
|
|||
return os;
|
||||
}
|
||||
|
||||
void importScope(Dsymbol s, Visibility visibility)
|
||||
void importScope(Dsymbol s, Visibility visibility) nothrow
|
||||
{
|
||||
//printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
|
||||
// No circular or redundant import's
|
||||
|
@ -1631,7 +1640,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
extern (D) final void addAccessiblePackage(Package p, Visibility visibility)
|
||||
extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow
|
||||
{
|
||||
auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
|
||||
if (pary.length <= p.tag)
|
||||
|
@ -1639,7 +1648,7 @@ public:
|
|||
(*pary)[p.tag] = true;
|
||||
}
|
||||
|
||||
bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
|
||||
bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
|
||||
{
|
||||
if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
|
||||
visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
|
||||
|
@ -1654,7 +1663,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
override final bool isforwardRef()
|
||||
override final bool isforwardRef() nothrow
|
||||
{
|
||||
return (members is null);
|
||||
}
|
||||
|
@ -1742,7 +1751,7 @@ public:
|
|||
* Returns:
|
||||
* null if already in table, `s` if inserted
|
||||
*/
|
||||
Dsymbol symtabInsert(Dsymbol s)
|
||||
Dsymbol symtabInsert(Dsymbol s) nothrow
|
||||
{
|
||||
return symtab.insert(s);
|
||||
}
|
||||
|
@ -1755,7 +1764,7 @@ public:
|
|||
* Returns:
|
||||
* Dsymbol if found, null if not
|
||||
*/
|
||||
Dsymbol symtabLookup(Dsymbol s, Identifier id)
|
||||
Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
|
||||
{
|
||||
return symtab.lookup(id);
|
||||
}
|
||||
|
@ -1838,7 +1847,7 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
|
|||
{
|
||||
WithStatement withstate;
|
||||
|
||||
extern (D) this(WithStatement withstate)
|
||||
extern (D) this(WithStatement withstate) nothrow
|
||||
{
|
||||
this.withstate = withstate;
|
||||
}
|
||||
|
@ -1898,7 +1907,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
|
|||
private RootObject arrayContent;
|
||||
Scope* sc;
|
||||
|
||||
extern (D) this(Scope* sc, Expression exp)
|
||||
extern (D) this(Scope* sc, Expression exp) nothrow
|
||||
{
|
||||
super(exp.loc, null);
|
||||
assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
|
||||
|
@ -1906,13 +1915,13 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
|
|||
this.arrayContent = exp;
|
||||
}
|
||||
|
||||
extern (D) this(Scope* sc, TypeTuple type)
|
||||
extern (D) this(Scope* sc, TypeTuple type) nothrow
|
||||
{
|
||||
this.sc = sc;
|
||||
this.arrayContent = type;
|
||||
}
|
||||
|
||||
extern (D) this(Scope* sc, TupleDeclaration td)
|
||||
extern (D) this(Scope* sc, TupleDeclaration td) nothrow
|
||||
{
|
||||
this.sc = sc;
|
||||
this.arrayContent = td;
|
||||
|
@ -2109,7 +2118,7 @@ extern (C++) final class OverloadSet : Dsymbol
|
|||
{
|
||||
Dsymbols a; // array of Dsymbols
|
||||
|
||||
extern (D) this(Identifier ident, OverloadSet os = null)
|
||||
extern (D) this(Identifier ident, OverloadSet os = null) nothrow
|
||||
{
|
||||
super(ident);
|
||||
if (os)
|
||||
|
@ -2118,7 +2127,7 @@ extern (C++) final class OverloadSet : Dsymbol
|
|||
}
|
||||
}
|
||||
|
||||
void push(Dsymbol s)
|
||||
void push(Dsymbol s) nothrow
|
||||
{
|
||||
a.push(s);
|
||||
}
|
||||
|
@ -2152,12 +2161,13 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
|
|||
* Can be `null` before being lazily initialized.
|
||||
*/
|
||||
ScopeDsymbol forward;
|
||||
extern (D) this(ScopeDsymbol forward)
|
||||
extern (D) this(ScopeDsymbol forward) nothrow
|
||||
{
|
||||
super(null);
|
||||
this.forward = forward;
|
||||
}
|
||||
override Dsymbol symtabInsert(Dsymbol s)
|
||||
|
||||
override Dsymbol symtabInsert(Dsymbol s) nothrow
|
||||
{
|
||||
assert(forward);
|
||||
if (auto d = s.isDeclaration())
|
||||
|
@ -2188,7 +2198,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
|
|||
* and
|
||||
* static foreach (i; [0]) { enum i = 2; }
|
||||
*/
|
||||
override Dsymbol symtabLookup(Dsymbol s, Identifier id)
|
||||
override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
|
||||
{
|
||||
assert(forward);
|
||||
// correctly diagnose clashing foreach loop variables.
|
||||
|
@ -2219,7 +2229,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
|
|||
|
||||
override const(char)* kind()const{ return "local scope"; }
|
||||
|
||||
override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout
|
||||
override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
@ -2234,13 +2244,13 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
|
|||
extern (C++) final class ExpressionDsymbol : Dsymbol
|
||||
{
|
||||
Expression exp;
|
||||
this(Expression exp)
|
||||
this(Expression exp) nothrow
|
||||
{
|
||||
super();
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
override inout(ExpressionDsymbol) isExpressionDsymbol() inout
|
||||
override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
@ -2259,7 +2269,7 @@ extern (C++) final class AliasAssign : Dsymbol
|
|||
Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
|
||||
/// only one of type and aliassym can be != null
|
||||
|
||||
extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym)
|
||||
extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow
|
||||
{
|
||||
super(loc, null);
|
||||
this.ident = ident;
|
||||
|
@ -2299,6 +2309,8 @@ extern (C++) final class DsymbolTable : RootObject
|
|||
{
|
||||
AssocArray!(Identifier, Dsymbol) tab;
|
||||
|
||||
nothrow:
|
||||
|
||||
/***************************
|
||||
* Look up Identifier in symbol table
|
||||
* Params:
|
||||
|
|
|
@ -51,6 +51,7 @@ import dmd.init;
|
|||
import dmd.initsem;
|
||||
import dmd.hdrgen;
|
||||
import dmd.mtype;
|
||||
import dmd.mustuse;
|
||||
import dmd.nogc;
|
||||
import dmd.nspace;
|
||||
import dmd.objc;
|
||||
|
@ -542,7 +543,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
Parameter arg = Parameter.getNth(tt.arguments, pos);
|
||||
arg.type = arg.type.typeSemantic(dsym.loc, sc);
|
||||
//printf("[%d] iexps.dim = %d, ", pos, iexps.dim);
|
||||
//printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
|
||||
//printf("e = (%s %s, %s), ", Token.tochars[e.op], e.toChars(), e.type.toChars());
|
||||
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
|
||||
|
||||
if (e != ie)
|
||||
|
@ -581,7 +582,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
arg = Parameter.getNth(tt.arguments, pos + u);
|
||||
arg.type = arg.type.typeSemantic(dsym.loc, sc);
|
||||
//printf("[%d+%d] exps.dim = %d, ", pos, u, exps.dim);
|
||||
//printf("ee = (%s %s, %s), ", Token::tochars[ee.op], ee.toChars(), ee.type.toChars());
|
||||
//printf("ee = (%s %s, %s), ", Token.tochars[ee.op], ee.toChars(), ee.type.toChars());
|
||||
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
|
||||
|
||||
size_t iexps_dim = iexps.dim - 1 + exps.dim;
|
||||
|
@ -2046,6 +2047,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
|
||||
ed.semanticRun = PASS.semantic;
|
||||
UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
|
||||
checkMustUseReserved(ed);
|
||||
|
||||
if (!ed.members && !ed.memtype) // enum ident;
|
||||
{
|
||||
|
@ -3017,7 +3019,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested()))
|
||||
funcdecl.storage_class &= ~STC.TYPECTOR;
|
||||
|
||||
//printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration::isFinal());
|
||||
//printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal());
|
||||
|
||||
if (sc.flags & SCOPE.compile)
|
||||
funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function
|
||||
|
@ -3056,6 +3058,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
funcdecl.visibility = sc.visibility;
|
||||
funcdecl.userAttribDecl = sc.userAttribDecl;
|
||||
UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl.linkage);
|
||||
checkMustUseReserved(funcdecl);
|
||||
|
||||
if (!funcdecl.originalType)
|
||||
funcdecl.originalType = funcdecl.type.syntaxCopy();
|
||||
|
@ -4092,7 +4095,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
override void visit(PostBlitDeclaration pbd)
|
||||
{
|
||||
//printf("PostBlitDeclaration::semantic() %s\n", toChars());
|
||||
//printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
|
||||
//printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor);
|
||||
//printf("stc = x%llx\n", sc.stc);
|
||||
if (pbd.semanticRun >= PASS.semanticdone)
|
||||
return;
|
||||
|
@ -4129,7 +4132,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
override void visit(DtorDeclaration dd)
|
||||
{
|
||||
//printf("DtorDeclaration::semantic() %s\n", toChars());
|
||||
//printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
|
||||
//printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor);
|
||||
if (dd.semanticRun >= PASS.semanticdone)
|
||||
return;
|
||||
if (dd._scope)
|
||||
|
@ -4770,6 +4773,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
}
|
||||
cldec.semanticRun = PASS.semantic;
|
||||
UserAttributeDeclaration.checkGNUABITag(cldec, sc.linkage);
|
||||
checkMustUseReserved(cldec);
|
||||
|
||||
if (cldec.baseok < Baseok.done)
|
||||
{
|
||||
|
@ -5475,6 +5479,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
idec.classKind = ClassKind.cpp;
|
||||
idec.cppnamespace = sc.namespace;
|
||||
UserAttributeDeclaration.checkGNUABITag(idec, sc.linkage);
|
||||
checkMustUseReserved(idec);
|
||||
|
||||
if (sc.linkage == LINK.objc)
|
||||
objc.setObjc(idec);
|
||||
|
|
|
@ -2626,7 +2626,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
|||
printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
|
||||
//printf("\tty = %d\n", arg.type.ty);
|
||||
}
|
||||
//printf("stc = %llx\n", dstart.scope.stc);
|
||||
//printf("stc = %llx\n", dstart._scope.stc);
|
||||
//printf("match:t/f = %d/%d\n", ta_last, m.last);
|
||||
}
|
||||
|
||||
|
@ -4332,7 +4332,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
|
|||
{
|
||||
TypeStruct tp = cast(TypeStruct)tparam;
|
||||
|
||||
//printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
|
||||
//printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
|
||||
if (wm && t.deduceWild(tparam, false))
|
||||
{
|
||||
result = MATCH.constant;
|
||||
|
@ -4513,7 +4513,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
|
|||
{
|
||||
TypeClass tp = cast(TypeClass)tparam;
|
||||
|
||||
//printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
|
||||
//printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
|
||||
if (wm && t.deduceWild(tparam, false))
|
||||
{
|
||||
result = MATCH.constant;
|
||||
|
|
|
@ -440,22 +440,33 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
|
|||
* sc = used to determine current function and module
|
||||
* firstArg = `ref` argument through which `arg` may be assigned
|
||||
* arg = initializer for parameter
|
||||
* param = parameter declaration corresponding to `arg`
|
||||
* gag = do not print error messages
|
||||
* Returns:
|
||||
* `true` if assignment to `firstArg` would cause an error
|
||||
*/
|
||||
bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, bool gag)
|
||||
bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Parameter param, bool gag)
|
||||
{
|
||||
enum log = false;
|
||||
if (log) printf("checkParamArgumentReturn(firstArg: %s arg: %s)\n",
|
||||
firstArg.toChars(), arg.toChars());
|
||||
//printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers());
|
||||
|
||||
if (!arg.type.hasPointers())
|
||||
if (!(param.storageClass & STC.return_))
|
||||
return false;
|
||||
|
||||
if (!arg.type.hasPointers() && !param.isReference())
|
||||
return false;
|
||||
|
||||
// `byRef` needed for `assign(ref int* x, ref int i) {x = &i};`
|
||||
// Note: taking address of scope pointer is not allowed
|
||||
// `assign(ref int** x, return ref scope int* i) {x = &i};`
|
||||
// Thus no return ref/return scope ambiguity here
|
||||
const byRef = param.isReference() && !(param.storageClass & STC.scope_)
|
||||
&& !(param.storageClass & STC.returnScope); // fixme: it's possible to infer returnScope without scope with vaIsFirstRef
|
||||
|
||||
scope e = new AssignExp(arg.loc, firstArg, arg);
|
||||
return checkAssignEscape(sc, e, gag);
|
||||
return checkAssignEscape(sc, e, gag, byRef);
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
|
@ -496,23 +507,13 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
|
|||
foreach (const i; 0 .. n)
|
||||
{
|
||||
Expression arg = (*ce.arguments)[i];
|
||||
if (!arg.type.hasPointers())
|
||||
continue;
|
||||
|
||||
//printf("\targ[%d]: %s\n", i, arg.toChars());
|
||||
|
||||
if (i - j < nparams && i >= j)
|
||||
{
|
||||
Parameter p = tf.parameterList[i - j];
|
||||
|
||||
if (p.storageClass & STC.return_)
|
||||
{
|
||||
/* Fake `dve.e1 = arg;` and look for scope violations
|
||||
*/
|
||||
scope e = new AssignExp(arg.loc, dve.e1, arg);
|
||||
if (checkAssignEscape(sc, e, gag))
|
||||
return true;
|
||||
}
|
||||
if (checkParamArgumentReturn(sc, dve.e1, arg, p, gag))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,13 +530,14 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
|
|||
* sc = used to determine current function and module
|
||||
* e = `AssignExp` or `CatAssignExp` to check for any pointers to the stack
|
||||
* gag = do not print error messages
|
||||
* byRef = set to `true` if `e1` of `e` gets assigned a reference to `e2`
|
||||
* Returns:
|
||||
* `true` if pointers to the stack can escape via assignment
|
||||
*/
|
||||
bool checkAssignEscape(Scope* sc, Expression e, bool gag)
|
||||
bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
|
||||
{
|
||||
enum log = false;
|
||||
if (log) printf("checkAssignEscape(e: %s)\n", e.toChars());
|
||||
if (log) printf("checkAssignEscape(e: %s, byRef: %d)\n", e.toChars(), byRef);
|
||||
if (e.op != EXP.assign && e.op != EXP.blit && e.op != EXP.construct &&
|
||||
e.op != EXP.concatenateAssign && e.op != EXP.concatenateElemAssign && e.op != EXP.concatenateDcharAssign)
|
||||
return false;
|
||||
|
@ -561,7 +563,10 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
|
|||
|
||||
EscapeByResults er;
|
||||
|
||||
escapeByValue(e2, &er);
|
||||
if (byRef)
|
||||
escapeByRef(e2, &er);
|
||||
else
|
||||
escapeByValue(e2, &er);
|
||||
|
||||
if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
|
||||
return false;
|
||||
|
@ -789,8 +794,18 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
|
|||
|
||||
Dsymbol p = v.toParent2();
|
||||
|
||||
if (vaIsFirstRef && v.isParameter() &&
|
||||
!(v.storage_class & STC.return_) &&
|
||||
fd.flags & FUNCFLAG.returnInprocess &&
|
||||
p == fd)
|
||||
{
|
||||
//if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
|
||||
inferReturn(fd, v, /*returnScope:*/ false);
|
||||
}
|
||||
|
||||
// If va's lifetime encloses v's, then error
|
||||
if (va &&
|
||||
!(vaIsFirstRef && (v.storage_class & STC.return_)) &&
|
||||
(va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
|
||||
fd.setUnsafe())
|
||||
{
|
||||
|
|
|
@ -1660,6 +1660,7 @@ extern (C++) abstract class Expression : ASTNode
|
|||
inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
|
||||
inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
|
||||
inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
|
||||
inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
|
||||
inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
|
||||
inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
|
||||
inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
|
||||
|
@ -2684,7 +2685,7 @@ extern (C++) final class StringExp : Expression
|
|||
const len2 = se2.len;
|
||||
|
||||
assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
|
||||
//printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
|
||||
//printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
|
||||
if (len1 == len2)
|
||||
{
|
||||
switch (sz)
|
||||
|
|
|
@ -56,6 +56,7 @@ import dmd.initsem;
|
|||
import dmd.inline;
|
||||
import dmd.intrange;
|
||||
import dmd.mtype;
|
||||
import dmd.mustuse;
|
||||
import dmd.nspace;
|
||||
import dmd.opover;
|
||||
import dmd.optimize;
|
||||
|
@ -713,7 +714,7 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2
|
|||
*/
|
||||
Expression resolvePropertiesOnly(Scope* sc, Expression e1)
|
||||
{
|
||||
//printf("e1 = %s %s\n", Token::toChars(e1.op), e1.toChars());
|
||||
//printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
|
||||
|
||||
Expression handleOverloadSet(OverloadSet os)
|
||||
{
|
||||
|
@ -2033,7 +2034,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
|||
* Check arg to see if it matters.
|
||||
*/
|
||||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
err |= checkParamArgumentReturn(sc, firstArg, arg, false);
|
||||
err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
|
||||
}
|
||||
else if (tf.parameterEscapes(tthis, p))
|
||||
{
|
||||
|
@ -3261,7 +3262,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
// printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
|
||||
e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
|
||||
}
|
||||
//printf("e = %s %s\n", Token::toChars(e.op), e.toChars());
|
||||
//printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
|
||||
e = e.expressionSemantic(sc);
|
||||
}
|
||||
else if (t)
|
||||
|
@ -6032,7 +6033,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
auto fileName = FileName(name.toDString);
|
||||
if (auto fmResult = global.fileManager.lookup(fileName))
|
||||
{
|
||||
se = new StringExp(e.loc, fmResult.data);
|
||||
se = new StringExp(e.loc, fmResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6047,9 +6048,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
// take ownership of buffer (probably leaking)
|
||||
auto data = readResult.extractSlice();
|
||||
se = new StringExp(e.loc, data);
|
||||
|
||||
FileBuffer* fileBuffer = new FileBuffer(data);
|
||||
global.fileManager.add(fileName, fileBuffer);
|
||||
global.fileManager.add(fileName, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6388,7 +6387,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
static if (LOGSEMANTIC)
|
||||
{
|
||||
printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
|
||||
//printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op));
|
||||
//printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
|
||||
}
|
||||
|
||||
if (sc.flags & SCOPE.Cfile)
|
||||
|
@ -8177,7 +8176,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
return;
|
||||
|
||||
if (e.type is Type.tvoid)
|
||||
{
|
||||
checkMustUse(e.e1, sc);
|
||||
discardValue(e.e1);
|
||||
}
|
||||
else if (!e.allowCommaExp && !e.isGenerated)
|
||||
e.error("Using the result of a comma expression is not allowed");
|
||||
}
|
||||
|
@ -8956,7 +8958,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
Parameter arg = Parameter.getNth(tt.arguments, u);
|
||||
//printf("[%d] iexps.dim = %d, ", u, iexps.dim);
|
||||
//printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
|
||||
//printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
|
||||
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
|
||||
|
||||
if (!arg || !e.type.implicitConvTo(arg.type))
|
||||
|
@ -9849,7 +9851,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
* `reorderSettingAAElem` creates a tree of comma expressions, however,
|
||||
* `checkAssignExp` expects only AssignExps.
|
||||
*/
|
||||
checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
|
||||
checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false);
|
||||
|
||||
if (auto ae = res.isConstructExp())
|
||||
{
|
||||
|
@ -10124,7 +10126,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
*/
|
||||
if (isRecursiveAliasThis(exp.att1, exp.e1.type))
|
||||
return null;
|
||||
//printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
|
||||
//printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
|
||||
Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
|
||||
BinExp be = cast(BinExp)exp.copy();
|
||||
be.e1 = e1;
|
||||
|
@ -10142,7 +10144,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
*/
|
||||
if (isRecursiveAliasThis(exp.att2, exp.e2.type))
|
||||
return null;
|
||||
//printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
|
||||
//printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
|
||||
Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
|
||||
BinExp be = cast(BinExp)exp.copy();
|
||||
be.e2 = e2;
|
||||
|
@ -10169,7 +10171,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
auto res = exp.reorderSettingAAElem(sc);
|
||||
if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) &&
|
||||
global.params.useDIP1000 == FeatureState.enabled)
|
||||
checkAssignEscape(sc, res, false);
|
||||
checkAssignEscape(sc, res, false, false);
|
||||
result = res;
|
||||
}
|
||||
|
||||
|
@ -12803,129 +12805,125 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
|
|||
return false;
|
||||
}
|
||||
|
||||
//printf("checkSharedAccess() %s\n", e.toChars());
|
||||
//printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
|
||||
|
||||
static extern(C++) final class SharedCheckVisitor : SemanticTimeTransitiveVisitor
|
||||
/* In case we don't know which expression triggered it,
|
||||
* e.g. for `visit(Type)` overload
|
||||
*/
|
||||
Expression original = e;
|
||||
|
||||
bool check(Expression e, bool allowRef)
|
||||
{
|
||||
/// In case we don't know which expression triggered it,
|
||||
/// e.g. for `visit(Type)` overload
|
||||
Expression original;
|
||||
/// Where the result is stored (`true` == error)
|
||||
bool result;
|
||||
/// Whether we should allow one level of dereferencing
|
||||
bool allowRef;
|
||||
|
||||
/// Ctor
|
||||
this(Expression oe, bool allowRef_)
|
||||
{
|
||||
this.original = oe;
|
||||
this.allowRef = allowRef_;
|
||||
}
|
||||
|
||||
void sharedError(Expression e)
|
||||
bool sharedError(Expression e)
|
||||
{
|
||||
// https://dlang.org/phobos/core_atomic.html
|
||||
e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
|
||||
this.result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Introduce base class overrides
|
||||
alias visit = SemanticTimeTransitiveVisitor.visit;
|
||||
|
||||
// Error by default
|
||||
override void visit(Expression e)
|
||||
bool visit(Expression e)
|
||||
{
|
||||
if (e.type.isShared())
|
||||
this.sharedError(e);
|
||||
return sharedError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
override void visit(Type t)
|
||||
bool visitNew(NewExp e)
|
||||
{
|
||||
if (e.thisexp)
|
||||
check(e.thisexp, false);
|
||||
// Note: This handles things like `new shared(Throwable).msg`,
|
||||
// where accessing `msg` would violate `shared`.
|
||||
if (t.isShared())
|
||||
this.sharedError(this.original);
|
||||
if (e.newtype.isShared())
|
||||
return sharedError(original);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Those have no indirections / can be ignored
|
||||
override void visit(ErrorExp e) {}
|
||||
override void visit(ComplexExp e) {}
|
||||
override void visit(IntegerExp e) {}
|
||||
override void visit(NullExp e) {}
|
||||
|
||||
override void visit(VarExp e)
|
||||
bool visitVar(VarExp e)
|
||||
{
|
||||
if (!this.allowRef && e.var.type.isShared())
|
||||
this.sharedError(e);
|
||||
if (!allowRef && e.var.type.isShared())
|
||||
return sharedError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
override void visit(AddrExp e)
|
||||
bool visitAddr(AddrExp e)
|
||||
{
|
||||
this.allowRef = true;
|
||||
e.e1.accept(this);
|
||||
return check(e.e1, true);
|
||||
}
|
||||
|
||||
override void visit(PtrExp e)
|
||||
bool visitPtr(PtrExp e)
|
||||
{
|
||||
if (!this.allowRef && e.type.isShared())
|
||||
return this.sharedError(e);
|
||||
if (!allowRef && e.type.isShared())
|
||||
return sharedError(e);
|
||||
|
||||
if (e.e1.type.isShared())
|
||||
return this.sharedError(e);
|
||||
return sharedError(e);
|
||||
|
||||
this.allowRef = false;
|
||||
e.e1.accept(this);
|
||||
return check(e.e1, false);
|
||||
}
|
||||
|
||||
override void visit(DotVarExp e)
|
||||
bool visitDotVar(DotVarExp e)
|
||||
{
|
||||
auto fd = e.var.isFuncDeclaration();
|
||||
const sharedFunc = fd && fd.type.isShared;
|
||||
|
||||
if (!this.allowRef && e.type.isShared() && !sharedFunc)
|
||||
return this.sharedError(e);
|
||||
if (!allowRef && e.type.isShared() && !sharedFunc)
|
||||
return sharedError(e);
|
||||
|
||||
// Allow to use `DotVarExp` within value types
|
||||
if (e.e1.type.ty == Tsarray || e.e1.type.ty == Tstruct)
|
||||
return e.e1.accept(this);
|
||||
// Allow using `DotVarExp` within value types
|
||||
if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
|
||||
return check(e.e1, allowRef);
|
||||
|
||||
// If we end up with a single `VarExp`, it might be a `ref` param
|
||||
// `shared ref T` param == `shared(T)*`.
|
||||
if (auto ve = e.e1.isVarExp())
|
||||
{
|
||||
this.allowRef = this.allowRef && (ve.var.storage_class & STC.ref_);
|
||||
return e.e1.accept(this);
|
||||
return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
|
||||
}
|
||||
|
||||
this.allowRef = false;
|
||||
return e.e1.accept(this);
|
||||
return check(e.e1, false);
|
||||
}
|
||||
|
||||
override void visit(IndexExp e)
|
||||
bool visitIndex(IndexExp e)
|
||||
{
|
||||
if (!this.allowRef && e.type.isShared())
|
||||
return this.sharedError(e);
|
||||
if (!allowRef && e.type.isShared())
|
||||
return sharedError(e);
|
||||
|
||||
if (e.e1.type.isShared())
|
||||
return this.sharedError(e);
|
||||
return sharedError(e);
|
||||
|
||||
this.allowRef = false;
|
||||
e.e1.accept(this);
|
||||
return check(e.e1, false);
|
||||
}
|
||||
|
||||
override void visit(CommaExp e)
|
||||
bool visitComma(CommaExp e)
|
||||
{
|
||||
// Cannot be `return ref` since we can't use the return,
|
||||
// but it's better to show that error than an unrelated `shared` one
|
||||
this.allowRef = true;
|
||||
e.e2.accept(this);
|
||||
return check(e.e2, true);
|
||||
}
|
||||
|
||||
switch (e.op)
|
||||
{
|
||||
default: return visit(e);
|
||||
|
||||
// Those have no indirections / can be ignored
|
||||
case EXP.call:
|
||||
case EXP.error:
|
||||
case EXP.complex80:
|
||||
case EXP.int64:
|
||||
case EXP.null_: return false;
|
||||
|
||||
case EXP.variable: return visitVar(e.isVarExp());
|
||||
case EXP.new_: return visitNew(e.isNewExp());
|
||||
case EXP.address: return visitAddr(e.isAddrExp());
|
||||
case EXP.star: return visitPtr(e.isPtrExp());
|
||||
case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
|
||||
case EXP.index: return visitIndex(e.isIndexExp());
|
||||
}
|
||||
}
|
||||
|
||||
scope visitor = new SharedCheckVisitor(e, returnRef);
|
||||
e.accept(visitor);
|
||||
return visitor.result;
|
||||
return check(e, returnRef);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
module dmd.file_manager;
|
||||
|
||||
import dmd.root.stringtable : StringTable;
|
||||
import dmd.root.file : File, FileBuffer;
|
||||
import dmd.root.file : File, Buffer;
|
||||
import dmd.root.filename : FileName;
|
||||
import dmd.root.string : toDString;
|
||||
import dmd.globals;
|
||||
|
@ -22,7 +22,7 @@ enum package_di = "package." ~ hdr_ext;
|
|||
|
||||
final class FileManager
|
||||
{
|
||||
private StringTable!(FileBuffer*) files;
|
||||
private StringTable!(const(ubyte)[]) files;
|
||||
|
||||
///
|
||||
public this () nothrow
|
||||
|
@ -146,7 +146,7 @@ nothrow:
|
|||
* Returns: the loaded source file if it was found in memory,
|
||||
* otherwise `null`
|
||||
*/
|
||||
const(FileBuffer)* lookup(FileName filename)
|
||||
const(ubyte)[] lookup(FileName filename)
|
||||
{
|
||||
const name = filename.toString;
|
||||
if (auto val = files.lookup(name))
|
||||
|
@ -154,7 +154,7 @@ nothrow:
|
|||
|
||||
if (name == "__stdin.d")
|
||||
{
|
||||
auto buffer = new FileBuffer(readFromStdin().extractSlice());
|
||||
auto buffer = readFromStdin().extractSlice();
|
||||
if (this.files.insert(name, buffer) is null)
|
||||
assert(0, "stdin: Insert after lookup failure should never return `null`");
|
||||
return buffer;
|
||||
|
@ -167,7 +167,7 @@ nothrow:
|
|||
if (!readResult.success)
|
||||
return null;
|
||||
|
||||
FileBuffer* fb = new FileBuffer(readResult.extractSlice());
|
||||
auto fb = readResult.extractSlice();
|
||||
if (files.insert(name, fb) is null)
|
||||
assert(0, "Insert after lookup failure should never return `null`");
|
||||
|
||||
|
@ -187,17 +187,17 @@ nothrow:
|
|||
const(char)[][] lines;
|
||||
if (const buffer = lookup(file))
|
||||
{
|
||||
const slice = buffer.data[0 .. buffer.data.length];
|
||||
const slice = buffer;
|
||||
size_t start, end;
|
||||
ubyte c;
|
||||
for (auto i = 0; i < slice.length; i++)
|
||||
{
|
||||
c = slice[i];
|
||||
const c = slice[i];
|
||||
if (c == '\n' || c == '\r')
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
end = i;
|
||||
// Appending lines one at a time will certainly be slow
|
||||
lines ~= cast(const(char)[])slice[start .. end];
|
||||
}
|
||||
// Check for Windows-style CRLF newlines
|
||||
|
@ -234,18 +234,21 @@ nothrow:
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a FileBuffer to the table.
|
||||
*
|
||||
* Returns: The FileBuffer added, or null
|
||||
* Adds the contents of a file to the table.
|
||||
* Params:
|
||||
* filename = name of the file
|
||||
* buffer = contents of the file
|
||||
* Returns:
|
||||
* the buffer added, or null
|
||||
*/
|
||||
FileBuffer* add(FileName filename, FileBuffer* filebuffer)
|
||||
const(ubyte)[] add(FileName filename, const(ubyte)[] buffer)
|
||||
{
|
||||
auto val = files.insert(filename.toString, filebuffer);
|
||||
auto val = files.insert(filename.toString, buffer);
|
||||
return val == null ? null : val.value;
|
||||
}
|
||||
}
|
||||
|
||||
private FileBuffer readFromStdin() nothrow
|
||||
private Buffer readFromStdin() nothrow
|
||||
{
|
||||
import core.stdc.stdio;
|
||||
import dmd.errors;
|
||||
|
@ -277,7 +280,7 @@ private FileBuffer readFromStdin() nothrow
|
|||
// We're done
|
||||
assert(pos < sz + 2);
|
||||
buffer[pos .. pos + 4] = '\0';
|
||||
return FileBuffer(buffer[0 .. pos]);
|
||||
return Buffer(buffer[0 .. pos]);
|
||||
}
|
||||
} while (pos < sz);
|
||||
|
||||
|
|
|
@ -1538,6 +1538,13 @@ public:
|
|||
}
|
||||
else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions)
|
||||
{
|
||||
if (!f.fbody)
|
||||
{
|
||||
// this can happen on interfaces / abstract functions, see `allowsContractWithoutBody`
|
||||
if (f.fensures || f.frequires)
|
||||
buf.writenl();
|
||||
contractsToBuffer(f);
|
||||
}
|
||||
buf.writeByte(';');
|
||||
buf.writenl();
|
||||
}
|
||||
|
@ -1548,19 +1555,9 @@ public:
|
|||
bodyToBuffer(f);
|
||||
}
|
||||
|
||||
void bodyToBuffer(FuncDeclaration f)
|
||||
/// Returns: whether `do` is needed to write the function body
|
||||
bool contractsToBuffer(FuncDeclaration f)
|
||||
{
|
||||
if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
|
||||
{
|
||||
buf.writeByte(';');
|
||||
buf.writenl();
|
||||
return;
|
||||
}
|
||||
const savetlpt = hgs.tpltMember;
|
||||
const saveauto = hgs.autoMember;
|
||||
hgs.tpltMember = 0;
|
||||
hgs.autoMember = 0;
|
||||
buf.writenl();
|
||||
bool requireDo = false;
|
||||
// in{}
|
||||
if (f.frequires)
|
||||
|
@ -1619,6 +1616,29 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
return requireDo;
|
||||
}
|
||||
|
||||
void bodyToBuffer(FuncDeclaration f)
|
||||
{
|
||||
if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
|
||||
{
|
||||
if (!f.fbody && (f.fensures || f.frequires))
|
||||
{
|
||||
buf.writenl();
|
||||
contractsToBuffer(f);
|
||||
}
|
||||
buf.writeByte(';');
|
||||
buf.writenl();
|
||||
return;
|
||||
}
|
||||
const savetlpt = hgs.tpltMember;
|
||||
const saveauto = hgs.autoMember;
|
||||
hgs.tpltMember = 0;
|
||||
hgs.autoMember = 0;
|
||||
buf.writenl();
|
||||
bool requireDo = contractsToBuffer(f);
|
||||
|
||||
if (requireDo)
|
||||
{
|
||||
buf.writestring("do");
|
||||
|
@ -1788,26 +1808,17 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
private extern (C++) final class ExpressionPrettyPrintVisitor : Visitor
|
||||
/*********************************************
|
||||
* Print expression to buffer.
|
||||
*/
|
||||
private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hgs)
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
public:
|
||||
OutBuffer* buf;
|
||||
HdrGenState* hgs;
|
||||
|
||||
extern (D) this(OutBuffer* buf, HdrGenState* hgs)
|
||||
{
|
||||
this.buf = buf;
|
||||
this.hgs = hgs;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
override void visit(Expression e)
|
||||
void visit(Expression e)
|
||||
{
|
||||
buf.writestring(EXPtoString(e.op));
|
||||
}
|
||||
|
||||
override void visit(IntegerExp e)
|
||||
void visitInteger(IntegerExp e)
|
||||
{
|
||||
const dinteger_t v = e.toInteger();
|
||||
if (e.type)
|
||||
|
@ -1907,12 +1918,12 @@ public:
|
|||
buf.print(v);
|
||||
}
|
||||
|
||||
override void visit(ErrorExp e)
|
||||
void visitError(ErrorExp e)
|
||||
{
|
||||
buf.writestring("__error");
|
||||
}
|
||||
|
||||
override void visit(VoidInitExp e)
|
||||
void visitVoidInit(VoidInitExp e)
|
||||
{
|
||||
buf.writestring("__void");
|
||||
}
|
||||
|
@ -1922,12 +1933,12 @@ public:
|
|||
.floatToBuffer(type, value, buf, hgs.hdrgen);
|
||||
}
|
||||
|
||||
override void visit(RealExp e)
|
||||
void visitReal(RealExp e)
|
||||
{
|
||||
floatToBuffer(e.type, e.value);
|
||||
}
|
||||
|
||||
override void visit(ComplexExp e)
|
||||
void visitComplex(ComplexExp e)
|
||||
{
|
||||
/* Print as:
|
||||
* (re+imi)
|
||||
|
@ -1939,7 +1950,7 @@ public:
|
|||
buf.writestring("i)");
|
||||
}
|
||||
|
||||
override void visit(IdentifierExp e)
|
||||
void visitIdentifier(IdentifierExp e)
|
||||
{
|
||||
if (hgs.hdrgen || hgs.ddoc)
|
||||
buf.writestring(e.ident.toHChars2());
|
||||
|
@ -1947,27 +1958,27 @@ public:
|
|||
buf.writestring(e.ident.toString());
|
||||
}
|
||||
|
||||
override void visit(DsymbolExp e)
|
||||
void visitDsymbol(DsymbolExp e)
|
||||
{
|
||||
buf.writestring(e.s.toChars());
|
||||
}
|
||||
|
||||
override void visit(ThisExp e)
|
||||
void visitThis(ThisExp e)
|
||||
{
|
||||
buf.writestring("this");
|
||||
}
|
||||
|
||||
override void visit(SuperExp e)
|
||||
void visitSuper(SuperExp e)
|
||||
{
|
||||
buf.writestring("super");
|
||||
}
|
||||
|
||||
override void visit(NullExp e)
|
||||
void visitNull(NullExp e)
|
||||
{
|
||||
buf.writestring("null");
|
||||
}
|
||||
|
||||
override void visit(StringExp e)
|
||||
void visitString(StringExp e)
|
||||
{
|
||||
buf.writeByte('"');
|
||||
const o = buf.length;
|
||||
|
@ -1982,14 +1993,14 @@ public:
|
|||
buf.writeByte(e.postfix);
|
||||
}
|
||||
|
||||
override void visit(ArrayLiteralExp e)
|
||||
void visitArrayLiteral(ArrayLiteralExp e)
|
||||
{
|
||||
buf.writeByte('[');
|
||||
argsToBuffer(e.elements, buf, hgs, e.basis);
|
||||
buf.writeByte(']');
|
||||
}
|
||||
|
||||
override void visit(AssocArrayLiteralExp e)
|
||||
void visitAssocArrayLiteral(AssocArrayLiteralExp e)
|
||||
{
|
||||
buf.writeByte('[');
|
||||
foreach (i, key; *e.keys)
|
||||
|
@ -2004,7 +2015,7 @@ public:
|
|||
buf.writeByte(']');
|
||||
}
|
||||
|
||||
override void visit(StructLiteralExp e)
|
||||
void visitStructLiteral(StructLiteralExp e)
|
||||
{
|
||||
buf.writestring(e.sd.toChars());
|
||||
buf.writeByte('(');
|
||||
|
@ -2024,7 +2035,7 @@ public:
|
|||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(CompoundLiteralExp e)
|
||||
void visitCompoundLiteral(CompoundLiteralExp e)
|
||||
{
|
||||
buf.writeByte('(');
|
||||
typeToBuffer(e.type, null, buf, hgs);
|
||||
|
@ -2032,12 +2043,12 @@ public:
|
|||
e.initializer.initializerToBuffer(buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(TypeExp e)
|
||||
void visitType(TypeExp e)
|
||||
{
|
||||
typeToBuffer(e.type, null, buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(ScopeExp e)
|
||||
void visitScope(ScopeExp e)
|
||||
{
|
||||
if (e.sds.isTemplateInstance())
|
||||
{
|
||||
|
@ -2059,12 +2070,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
override void visit(TemplateExp e)
|
||||
void visitTemplate(TemplateExp e)
|
||||
{
|
||||
buf.writestring(e.td.toChars());
|
||||
}
|
||||
|
||||
override void visit(NewExp e)
|
||||
void visitNew(NewExp e)
|
||||
{
|
||||
if (e.thisexp)
|
||||
{
|
||||
|
@ -2081,7 +2092,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
override void visit(NewAnonClassExp e)
|
||||
void visitNewAnonClass(NewAnonClassExp e)
|
||||
{
|
||||
if (e.thisexp)
|
||||
{
|
||||
|
@ -2100,7 +2111,7 @@ public:
|
|||
e.cd.dsymbolToBuffer(buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(SymOffExp e)
|
||||
void visitSymOff(SymOffExp e)
|
||||
{
|
||||
if (e.offset)
|
||||
buf.printf("(& %s%+lld)", e.var.toChars(), e.offset);
|
||||
|
@ -2110,22 +2121,22 @@ public:
|
|||
buf.printf("& %s", e.var.toChars());
|
||||
}
|
||||
|
||||
override void visit(VarExp e)
|
||||
void visitVar(VarExp e)
|
||||
{
|
||||
buf.writestring(e.var.toChars());
|
||||
}
|
||||
|
||||
override void visit(OverExp e)
|
||||
void visitOver(OverExp e)
|
||||
{
|
||||
buf.writestring(e.vars.ident.toString());
|
||||
}
|
||||
|
||||
override void visit(TupleExp e)
|
||||
void visitTuple(TupleExp e)
|
||||
{
|
||||
if (e.e0)
|
||||
{
|
||||
buf.writeByte('(');
|
||||
e.e0.accept(this);
|
||||
e.e0.expressionPrettyPrint(buf, hgs);
|
||||
buf.writestring(", tuple(");
|
||||
argsToBuffer(e.exps, buf, hgs);
|
||||
buf.writestring("))");
|
||||
|
@ -2138,13 +2149,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
override void visit(FuncExp e)
|
||||
void visitFunc(FuncExp e)
|
||||
{
|
||||
e.fd.dsymbolToBuffer(buf, hgs);
|
||||
//buf.writestring(e.fd.toChars());
|
||||
}
|
||||
|
||||
override void visit(DeclarationExp e)
|
||||
void visitDeclaration(DeclarationExp e)
|
||||
{
|
||||
/* Normal dmd execution won't reach here - regular variable declarations
|
||||
* are handled in visit(ExpStatement), so here would be used only when
|
||||
|
@ -2170,14 +2181,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
override void visit(TypeidExp e)
|
||||
void visitTypeid(TypeidExp e)
|
||||
{
|
||||
buf.writestring("typeid(");
|
||||
objectToBuffer(e.obj, buf, hgs);
|
||||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(TraitsExp e)
|
||||
void visitTraits(TraitsExp e)
|
||||
{
|
||||
buf.writestring("__traits(");
|
||||
if (e.ident)
|
||||
|
@ -2193,12 +2204,12 @@ public:
|
|||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(HaltExp e)
|
||||
void visitHalt(HaltExp e)
|
||||
{
|
||||
buf.writestring("halt");
|
||||
}
|
||||
|
||||
override void visit(IsExp e)
|
||||
void visitIs(IsExp e)
|
||||
{
|
||||
buf.writestring("is(");
|
||||
typeToBuffer(e.targ, e.id, buf, hgs);
|
||||
|
@ -2223,13 +2234,13 @@ public:
|
|||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(UnaExp e)
|
||||
void visitUna(UnaExp e)
|
||||
{
|
||||
buf.writestring(EXPtoString(e.op));
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(BinExp e)
|
||||
void visitBin(BinExp e)
|
||||
{
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
buf.writeByte(' ');
|
||||
|
@ -2238,7 +2249,7 @@ public:
|
|||
expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(CommaExp e)
|
||||
void visitComma(CommaExp e)
|
||||
{
|
||||
// CommaExp is generated by the compiler so it shouldn't
|
||||
// appear in error messages or header files.
|
||||
|
@ -2251,7 +2262,7 @@ public:
|
|||
// the old path
|
||||
if (!ve || !(ve.var.storage_class & STC.temp))
|
||||
{
|
||||
visit(cast(BinExp)e);
|
||||
visitBin(cast(BinExp)e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2281,25 +2292,25 @@ public:
|
|||
}
|
||||
|
||||
// not one of the known cases, go on the old path
|
||||
visit(cast(BinExp)e);
|
||||
visitBin(cast(BinExp)e);
|
||||
return;
|
||||
}
|
||||
|
||||
override void visit(MixinExp e)
|
||||
void visitMixin(MixinExp e)
|
||||
{
|
||||
buf.writestring("mixin(");
|
||||
argsToBuffer(e.exps, buf, hgs, null);
|
||||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(ImportExp e)
|
||||
void visitImport(ImportExp e)
|
||||
{
|
||||
buf.writestring("import(");
|
||||
expToBuffer(e.e1, PREC.assign, buf, hgs);
|
||||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(AssertExp e)
|
||||
void visitAssert(AssertExp e)
|
||||
{
|
||||
buf.writestring("assert(");
|
||||
expToBuffer(e.e1, PREC.assign, buf, hgs);
|
||||
|
@ -2311,13 +2322,13 @@ public:
|
|||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(ThrowExp e)
|
||||
void visitThrow(ThrowExp e)
|
||||
{
|
||||
buf.writestring("throw ");
|
||||
expToBuffer(e.e1, PREC.unary, buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(DotIdExp e)
|
||||
void visitDotId(DotIdExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
if (e.arrow)
|
||||
|
@ -2327,28 +2338,28 @@ public:
|
|||
buf.writestring(e.ident.toString());
|
||||
}
|
||||
|
||||
override void visit(DotTemplateExp e)
|
||||
void visitDotTemplate(DotTemplateExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writeByte('.');
|
||||
buf.writestring(e.td.toChars());
|
||||
}
|
||||
|
||||
override void visit(DotVarExp e)
|
||||
void visitDotVar(DotVarExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writeByte('.');
|
||||
buf.writestring(e.var.toChars());
|
||||
}
|
||||
|
||||
override void visit(DotTemplateInstanceExp e)
|
||||
void visitDotTemplateInstance(DotTemplateInstanceExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writeByte('.');
|
||||
e.ti.dsymbolToBuffer(buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(DelegateExp e)
|
||||
void visitDelegate(DelegateExp e)
|
||||
{
|
||||
buf.writeByte('&');
|
||||
if (!e.func.isNested() || e.func.needThis())
|
||||
|
@ -2359,14 +2370,14 @@ public:
|
|||
buf.writestring(e.func.toChars());
|
||||
}
|
||||
|
||||
override void visit(DotTypeExp e)
|
||||
void visitDotType(DotTypeExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writeByte('.');
|
||||
buf.writestring(e.sym.toChars());
|
||||
}
|
||||
|
||||
override void visit(CallExp e)
|
||||
void visitCall(CallExp e)
|
||||
{
|
||||
if (e.e1.op == EXP.type)
|
||||
{
|
||||
|
@ -2375,7 +2386,7 @@ public:
|
|||
* This is ok since types in constructor calls
|
||||
* can never depend on parens anyway
|
||||
*/
|
||||
e.e1.accept(this);
|
||||
e.e1.expressionPrettyPrint(buf, hgs);
|
||||
}
|
||||
else
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
|
@ -2384,19 +2395,19 @@ public:
|
|||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(PtrExp e)
|
||||
void visitPtr(PtrExp e)
|
||||
{
|
||||
buf.writeByte('*');
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(DeleteExp e)
|
||||
void visitDelete(DeleteExp e)
|
||||
{
|
||||
buf.writestring("delete ");
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(CastExp e)
|
||||
void visitCast(CastExp e)
|
||||
{
|
||||
buf.writestring("cast(");
|
||||
if (e.to)
|
||||
|
@ -2409,7 +2420,7 @@ public:
|
|||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(VectorExp e)
|
||||
void visitVector(VectorExp e)
|
||||
{
|
||||
buf.writestring("cast(");
|
||||
typeToBuffer(e.to, null, buf, hgs);
|
||||
|
@ -2417,13 +2428,13 @@ public:
|
|||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(VectorArrayExp e)
|
||||
void visitVectorArray(VectorArrayExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writestring(".array");
|
||||
}
|
||||
|
||||
override void visit(SliceExp e)
|
||||
void visitSlice(SliceExp e)
|
||||
{
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
buf.writeByte('[');
|
||||
|
@ -2442,32 +2453,32 @@ public:
|
|||
buf.writeByte(']');
|
||||
}
|
||||
|
||||
override void visit(ArrayLengthExp e)
|
||||
void visitArrayLength(ArrayLengthExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writestring(".length");
|
||||
}
|
||||
|
||||
override void visit(IntervalExp e)
|
||||
void visitInterval(IntervalExp e)
|
||||
{
|
||||
expToBuffer(e.lwr, PREC.assign, buf, hgs);
|
||||
buf.writestring("..");
|
||||
expToBuffer(e.upr, PREC.assign, buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(DelegatePtrExp e)
|
||||
void visitDelegatePtr(DelegatePtrExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writestring(".ptr");
|
||||
}
|
||||
|
||||
override void visit(DelegateFuncptrExp e)
|
||||
void visitDelegateFuncptr(DelegateFuncptrExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writestring(".funcptr");
|
||||
}
|
||||
|
||||
override void visit(ArrayExp e)
|
||||
void visitArray(ArrayExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writeByte('[');
|
||||
|
@ -2475,14 +2486,14 @@ public:
|
|||
buf.writeByte(']');
|
||||
}
|
||||
|
||||
override void visit(DotExp e)
|
||||
void visitDot(DotExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writeByte('.');
|
||||
expToBuffer(e.e2, PREC.primary, buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(IndexExp e)
|
||||
void visitIndex(IndexExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writeByte('[');
|
||||
|
@ -2490,19 +2501,19 @@ public:
|
|||
buf.writeByte(']');
|
||||
}
|
||||
|
||||
override void visit(PostExp e)
|
||||
void visitPost(PostExp e)
|
||||
{
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
buf.writestring(EXPtoString(e.op));
|
||||
}
|
||||
|
||||
override void visit(PreExp e)
|
||||
void visitPre(PreExp e)
|
||||
{
|
||||
buf.writestring(EXPtoString(e.op));
|
||||
expToBuffer(e.e1, precedence[e.op], buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(RemoveExp e)
|
||||
void visitRemove(RemoveExp e)
|
||||
{
|
||||
expToBuffer(e.e1, PREC.primary, buf, hgs);
|
||||
buf.writestring(".remove(");
|
||||
|
@ -2510,7 +2521,7 @@ public:
|
|||
buf.writeByte(')');
|
||||
}
|
||||
|
||||
override void visit(CondExp e)
|
||||
void visitCond(CondExp e)
|
||||
{
|
||||
expToBuffer(e.econd, PREC.oror, buf, hgs);
|
||||
buf.writestring(" ? ");
|
||||
|
@ -2519,15 +2530,90 @@ public:
|
|||
expToBuffer(e.e2, PREC.cond, buf, hgs);
|
||||
}
|
||||
|
||||
override void visit(DefaultInitExp e)
|
||||
void visitDefaultInit(DefaultInitExp e)
|
||||
{
|
||||
buf.writestring(EXPtoString(e.op));
|
||||
}
|
||||
|
||||
override void visit(ClassReferenceExp e)
|
||||
void visitClassReference(ClassReferenceExp e)
|
||||
{
|
||||
buf.writestring(e.value.toChars());
|
||||
}
|
||||
|
||||
switch (e.op)
|
||||
{
|
||||
default:
|
||||
if (auto be = e.isBinExp())
|
||||
return visitBin(be);
|
||||
else if (auto ue = e.isUnaExp())
|
||||
return visitUna(ue);
|
||||
else if (auto de = e.isDefaultInitExp())
|
||||
return visitDefaultInit(e.isDefaultInitExp());
|
||||
return visit(e);
|
||||
|
||||
case EXP.int64: return visitInteger(e.isIntegerExp());
|
||||
case EXP.error: return visitError(e.isErrorExp());
|
||||
case EXP.void_: return visitVoidInit(e.isVoidInitExp());
|
||||
case EXP.float64: return visitReal(e.isRealExp());
|
||||
case EXP.complex80: return visitComplex(e.isComplexExp());
|
||||
case EXP.identifier: return visitIdentifier(e.isIdentifierExp());
|
||||
case EXP.dSymbol: return visitDsymbol(e.isDsymbolExp());
|
||||
case EXP.this_: return visitThis(e.isThisExp());
|
||||
case EXP.super_: return visitSuper(e.isSuperExp());
|
||||
case EXP.null_: return visitNull(e.isNullExp());
|
||||
case EXP.string_: return visitString(e.isStringExp());
|
||||
case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp());
|
||||
case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
|
||||
case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
|
||||
case EXP.compoundLiteral: return visitCompoundLiteral(e.isCompoundLiteralExp());
|
||||
case EXP.type: return visitType(e.isTypeExp());
|
||||
case EXP.scope_: return visitScope(e.isScopeExp());
|
||||
case EXP.template_: return visitTemplate(e.isTemplateExp());
|
||||
case EXP.new_: return visitNew(e.isNewExp());
|
||||
case EXP.newAnonymousClass: return visitNewAnonClass(e.isNewAnonClassExp());
|
||||
case EXP.symbolOffset: return visitSymOff(e.isSymOffExp());
|
||||
case EXP.variable: return visitVar(e.isVarExp());
|
||||
case EXP.overloadSet: return visitOver(e.isOverExp());
|
||||
case EXP.tuple: return visitTuple(e.isTupleExp());
|
||||
case EXP.function_: return visitFunc(e.isFuncExp());
|
||||
case EXP.declaration: return visitDeclaration(e.isDeclarationExp());
|
||||
case EXP.typeid_: return visitTypeid(e.isTypeidExp());
|
||||
case EXP.traits: return visitTraits(e.isTraitsExp());
|
||||
case EXP.halt: return visitHalt(e.isHaltExp());
|
||||
case EXP.is_: return visitIs(e.isExp());
|
||||
case EXP.comma: return visitComma(e.isCommaExp());
|
||||
case EXP.mixin_: return visitMixin(e.isMixinExp());
|
||||
case EXP.import_: return visitImport(e.isImportExp());
|
||||
case EXP.assert_: return visitAssert(e.isAssertExp());
|
||||
case EXP.throw_: return visitThrow(e.isThrowExp());
|
||||
case EXP.dotIdentifier: return visitDotId(e.isDotIdExp());
|
||||
case EXP.dotTemplateDeclaration: return visitDotTemplate(e.isDotTemplateExp());
|
||||
case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
|
||||
case EXP.dotTemplateInstance: return visitDotTemplateInstance(e.isDotTemplateInstanceExp());
|
||||
case EXP.delegate_: return visitDelegate(e.isDelegateExp());
|
||||
case EXP.dotType: return visitDotType(e.isDotTypeExp());
|
||||
case EXP.call: return visitCall(e.isCallExp());
|
||||
case EXP.star: return visitPtr(e.isPtrExp());
|
||||
case EXP.delete_: return visitDelete(e.isDeleteExp());
|
||||
case EXP.cast_: return visitCast(e.isCastExp());
|
||||
case EXP.vector: return visitVector(e.isVectorExp());
|
||||
case EXP.vectorArray: return visitVectorArray(e.isVectorArrayExp());
|
||||
case EXP.slice: return visitSlice(e.isSliceExp());
|
||||
case EXP.arrayLength: return visitArrayLength(e.isArrayLengthExp());
|
||||
case EXP.interval: return visitInterval(e.isIntervalExp());
|
||||
case EXP.delegatePointer: return visitDelegatePtr(e.isDelegatePtrExp());
|
||||
case EXP.delegateFunctionPointer: return visitDelegateFuncptr(e.isDelegateFuncptrExp());
|
||||
case EXP.array: return visitArray(e.isArrayExp());
|
||||
case EXP.dot: return visitDot(e.isDotExp());
|
||||
case EXP.index: return visitIndex(e.isIndexExp());
|
||||
case EXP.minusMinus:
|
||||
case EXP.plusPlus: return visitPost(e.isPostExp());
|
||||
case EXP.preMinusMinus:
|
||||
case EXP.prePlusPlus: return visitPre(e.isPreExp());
|
||||
case EXP.remove: return visitRemove(e.isRemoveExp());
|
||||
case EXP.question: return visitCond(e.isCondExp());
|
||||
case EXP.classReference: return visitClassReference(e.isClassReferenceExp());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2547,7 +2633,7 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all
|
|||
(ie, 8 chars more than mantissa). Plus one for trailing \0.
|
||||
Plus one for rounding. */
|
||||
const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
|
||||
char[BUFFER_LEN] buffer;
|
||||
char[BUFFER_LEN] buffer = void;
|
||||
CTFloat.sprint(buffer.ptr, 'g', value);
|
||||
assert(strlen(buffer.ptr) < BUFFER_LEN);
|
||||
if (allowHex)
|
||||
|
@ -2754,7 +2840,7 @@ bool stcToBuffer(OutBuffer* buf, StorageClass stc)
|
|||
}
|
||||
if (stc & STC.returninferred)
|
||||
{
|
||||
//buf.writestring("return-inferred ");
|
||||
//buf.writestring((stc & STC.returnScope) ? "return-scope-inferred " : "return-ref-inferred ");
|
||||
stc &= ~(STC.return_ | STC.returninferred);
|
||||
}
|
||||
|
||||
|
@ -2958,8 +3044,7 @@ void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ide
|
|||
|
||||
void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs)
|
||||
{
|
||||
scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
|
||||
(cast() e).accept(v);
|
||||
expressionPrettyPrint(cast()e, buf, hgs);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
@ -3221,8 +3306,7 @@ private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
|
|||
|
||||
private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
|
||||
{
|
||||
scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
|
||||
e.accept(v);
|
||||
expressionPrettyPrint(e, buf, hgs);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
|
|
@ -491,6 +491,7 @@ immutable Msgtable[] msgtable =
|
|||
{ "udaGNUAbiTag", "gnuAbiTag" },
|
||||
{ "udaSelector", "selector" },
|
||||
{ "udaOptional", "optional"},
|
||||
{ "udaMustUse", "mustuse" },
|
||||
|
||||
// C names, for undefined identifier error messages
|
||||
{ "NULL" },
|
||||
|
|
|
@ -554,26 +554,39 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
i.exp = e.optimize(WANTvalue);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Look for the case of statically initializing an array
|
||||
// with a single member.
|
||||
if (tb.ty == Tsarray && !tb.nextOf().equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tb.nextOf()))
|
||||
auto tba = tb.isTypeSArray();
|
||||
if (tba && !tba.next.equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tba.next))
|
||||
{
|
||||
/* If the variable is not actually used in compile time, array creation is
|
||||
* redundant. So delay it until invocation of toExpression() or toDt().
|
||||
*/
|
||||
t = tb.nextOf();
|
||||
}
|
||||
|
||||
auto tta = t.isTypeSArray();
|
||||
if (i.exp.implicitConvTo(t))
|
||||
{
|
||||
i.exp = i.exp.implicitCastTo(sc, t);
|
||||
}
|
||||
else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
|
||||
tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) &&
|
||||
ti.ty == Tpointer && ti.nextOf().ty == Tchar)
|
||||
{
|
||||
/* unsigned char bbb[1] = "";
|
||||
* signed char ccc[1] = "";
|
||||
*/
|
||||
i.exp = i.exp.castTo(sc, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Look for mismatch of compile-time known length to emit
|
||||
// better diagnostic message, as same as AssignExp::semantic.
|
||||
if (tb.ty == Tsarray && i.exp.implicitConvTo(tb.nextOf().arrayOf()) > MATCH.nomatch)
|
||||
if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch)
|
||||
{
|
||||
uinteger_t dim1 = tb.isTypeSArray().dim.toInteger();
|
||||
uinteger_t dim1 = tba.dim.toInteger();
|
||||
uinteger_t dim2 = dim1;
|
||||
if (auto ale = i.exp.isArrayLiteralExp())
|
||||
{
|
||||
|
@ -596,6 +609,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
if (global.endGagging(errors))
|
||||
currExp.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars());
|
||||
}
|
||||
}
|
||||
L1:
|
||||
if (i.exp.op == EXP.error)
|
||||
{
|
||||
|
@ -1059,7 +1073,7 @@ Initializer inferType(Initializer init, Scope* sc)
|
|||
|
||||
Initializer visitC(CInitializer i)
|
||||
{
|
||||
//printf(CInitializer::inferType()\n");
|
||||
//printf("CInitializer.inferType()\n");
|
||||
error(i.loc, "TODO C inferType initializers not supported yet");
|
||||
return new ErrorInitializer();
|
||||
}
|
||||
|
@ -1331,6 +1345,10 @@ private bool hasNonConstPointers(Expression e)
|
|||
}
|
||||
if (auto ae = e.isAddrExp())
|
||||
{
|
||||
if (ae.type.nextOf().isImmutable() || ae.type.nextOf().isConst())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (auto se = ae.e1.isStructLiteralExp())
|
||||
{
|
||||
if (!(se.stageflags & stageSearchPointers))
|
||||
|
|
|
@ -319,10 +319,7 @@ public:
|
|||
// Should not be printed
|
||||
//property(name, "d");
|
||||
break;
|
||||
case LINK.system:
|
||||
// Should not be printed
|
||||
//property(name, "system");
|
||||
break;
|
||||
case LINK.system: return property(name, "system");
|
||||
case LINK.c: return property(name, "c");
|
||||
case LINK.cpp: return property(name, "cpp");
|
||||
case LINK.windows: return property(name, "windows");
|
||||
|
|
|
@ -108,8 +108,8 @@ class Lexer
|
|||
size_t endoffset, bool doDocComment, bool commentToken) pure
|
||||
{
|
||||
scanloc = Loc(filename, 1, 1);
|
||||
//printf("Lexer::Lexer(%p,%d)\n",base,length);
|
||||
//printf("lexer.filename = %s\n", filename);
|
||||
// debug printf("Lexer::Lexer(%p)\n", base);
|
||||
// debug printf("lexer.filename = %s\n", filename);
|
||||
token = Token.init;
|
||||
this.base = base;
|
||||
this.end = base + endoffset;
|
||||
|
@ -2122,7 +2122,7 @@ class Lexer
|
|||
// can't translate invalid octal value, just show a generic message
|
||||
error("octal literals larger than 7 are no longer supported");
|
||||
else
|
||||
error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!%llo%.*s` instead",
|
||||
error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead",
|
||||
n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix);
|
||||
}
|
||||
TOK result;
|
||||
|
@ -2926,7 +2926,7 @@ class Lexer
|
|||
*/
|
||||
static const(char)* combineComments(const(char)[] c1, const(char)[] c2, bool newParagraph) pure
|
||||
{
|
||||
//printf("Lexer::combineComments('%s', '%s', '%i')\n", c1, c2, newParagraph);
|
||||
//debug printf("Lexer::combineComments('%*.s', '%*.s', '%i')\n", cast(int) c1.length, c1.ptr, cast(int) c2.length, c2.ptr, newParagraph);
|
||||
const(int) newParagraphSize = newParagraph ? 1 : 0; // Size of the combining '\n'
|
||||
if (!c1)
|
||||
return c2.ptr;
|
||||
|
|
|
@ -4200,27 +4200,28 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
|
||||
// These flags can be accessed like `bool` properties,
|
||||
// getters and setters are generated for them
|
||||
private enum FunctionFlag : uint
|
||||
private extern (D) static struct BitFields
|
||||
{
|
||||
none = 0,
|
||||
isnothrow = 0x0001, // nothrow
|
||||
isnogc = 0x0002, // is @nogc
|
||||
isproperty = 0x0004, // can be called without parentheses
|
||||
isref = 0x0008, // returns a reference
|
||||
isreturn = 0x0010, // 'this' is returned by ref
|
||||
isScopeQual = 0x0020, // 'this' is scope
|
||||
isreturninferred= 0x0040, // 'this' is return from inference
|
||||
isscopeinferred = 0x0080, // 'this' is scope from inference
|
||||
islive = 0x0100, // is @live
|
||||
incomplete = 0x0200, // return type or default arguments removed
|
||||
isInOutParam = 0x0400, // inout on the parameters
|
||||
isInOutQual = 0x0800, // inout on the qualifier
|
||||
isctor = 0x1000, // the function is a constructor
|
||||
isreturnscope = 0x2000, // `this` is returned by value
|
||||
bool isnothrow; /// nothrow
|
||||
bool isnogc; /// is @nogc
|
||||
bool isproperty; /// can be called without parentheses
|
||||
bool isref; /// returns a reference
|
||||
bool isreturn; /// 'this' is returned by ref
|
||||
bool isScopeQual; /// 'this' is scope
|
||||
bool isreturninferred; /// 'this' is return from inference
|
||||
bool isscopeinferred; /// 'this' is scope from inference
|
||||
bool islive; /// is @live
|
||||
bool incomplete; /// return type or default arguments removed
|
||||
bool isInOutParam; /// inout on the parameters
|
||||
bool isInOutQual; /// inout on the qualifier
|
||||
bool isctor; /// the function is a constructor
|
||||
bool isreturnscope; /// `this` is returned by value
|
||||
}
|
||||
|
||||
import dmd.common.bitfields : generateBitFields;
|
||||
mixin(generateBitFields!(BitFields, ushort));
|
||||
|
||||
LINK linkage; // calling convention
|
||||
FunctionFlag funcFlags;
|
||||
TRUST trust; // level of trust
|
||||
PURE purity = PURE.impure;
|
||||
byte inuse;
|
||||
|
@ -4684,6 +4685,16 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
match = MATCH.convert; // match ... with a "conversion" match level
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22997
|
||||
if (parameterList.varargs == VarArg.none && nparams > nargs && !parameterList[nargs].defaultArg)
|
||||
{
|
||||
OutBuffer buf;
|
||||
buf.printf("too few arguments, expected `%d`, got `%d`", cast(int)nparams, cast(int)nargs);
|
||||
if (pMessage)
|
||||
*pMessage = buf.extractChars();
|
||||
goto Nomatch;
|
||||
}
|
||||
|
||||
foreach (u, p; parameterList)
|
||||
{
|
||||
if (u == nargs)
|
||||
|
@ -5086,41 +5097,21 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
return false;
|
||||
}
|
||||
|
||||
// Generate getter / setter functions for `FunctionFlag` members so they can be
|
||||
// treated like regular `bool` fields, instead of requiring bit twiddling to read/write
|
||||
extern (D) mixin(() {
|
||||
string result = "extern(C++) pure nothrow @safe @nogc {";
|
||||
foreach (string mem; __traits(allMembers, FunctionFlag))
|
||||
{
|
||||
result ~= "
|
||||
/// set or get if the function has the FunctionFlag attribute of the same name
|
||||
bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; }
|
||||
/// ditto
|
||||
void "~mem~"(bool v)
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag."~mem~";
|
||||
else funcFlags &= ~FunctionFlag."~mem~";
|
||||
}";
|
||||
}
|
||||
return result ~ "}\n";
|
||||
}());
|
||||
|
||||
/// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
|
||||
bool iswild() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0;
|
||||
return isInOutParam || isInOutQual;
|
||||
}
|
||||
|
||||
/// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
|
||||
bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc
|
||||
{
|
||||
enum attributes = FunctionFlag.isnothrow
|
||||
| FunctionFlag.isnogc
|
||||
| FunctionFlag.islive;
|
||||
|
||||
return this.trust == other.trust &&
|
||||
this.purity == other.purity &&
|
||||
(this.funcFlags & attributes) == (other.funcFlags & attributes);
|
||||
this.isnothrow == other.isnothrow &&
|
||||
this.isnogc == other.isnogc &&
|
||||
this.islive == other.islive;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
|
|
@ -595,8 +595,8 @@ public:
|
|||
// .next is the return type
|
||||
|
||||
ParameterList parameterList; // function parameters
|
||||
uint16_t bitFields;
|
||||
LINK linkage; // calling convention
|
||||
unsigned funcFlags;
|
||||
TRUST trust; // level of trust
|
||||
PURE purity; // PURExxxx
|
||||
char inuse;
|
||||
|
|
244
gcc/d/dmd/mustuse.d
Normal file
244
gcc/d/dmd/mustuse.d
Normal file
|
@ -0,0 +1,244 @@
|
|||
/**
|
||||
* Compile-time checks associated with the @mustuse attribute.
|
||||
*
|
||||
* Copyright: Copyright (C) 2022 by The D Language Foundation, All Rights Reserved
|
||||
* 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/mustuse.d, _mustuse.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_mustuse.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mustuse.d
|
||||
*/
|
||||
|
||||
module dmd.mustuse;
|
||||
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.expression;
|
||||
import dmd.globals;
|
||||
import dmd.identifier;
|
||||
|
||||
// Used in isIncrementOrDecrement
|
||||
private static const StringExp plusPlus, minusMinus;
|
||||
|
||||
// Loc.initial cannot be used in static initializers, so
|
||||
// these need a static constructor.
|
||||
static this()
|
||||
{
|
||||
plusPlus = new StringExp(Loc.initial, "++");
|
||||
minusMinus = new StringExp(Loc.initial, "--");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether discarding an expression would violate the requirements of
|
||||
* @mustuse. If so, emit an error.
|
||||
*
|
||||
* Params:
|
||||
* e = the expression to check
|
||||
* sc = scope in which `e` was semantically analyzed
|
||||
*
|
||||
* Returns: true on error, false on success.
|
||||
*/
|
||||
bool checkMustUse(Expression e, Scope* sc)
|
||||
{
|
||||
import dmd.id : Id;
|
||||
|
||||
assert(e.type);
|
||||
if (auto sym = e.type.toDsymbol(sc))
|
||||
{
|
||||
auto sd = sym.isStructDeclaration();
|
||||
// isStructDeclaration returns non-null for both structs and unions
|
||||
if (sd && hasMustUseAttribute(sd, sc) && !isAssignment(e) && !isIncrementOrDecrement(e))
|
||||
{
|
||||
e.error("ignored value of `@%s` type `%s`; prepend a `cast(void)` if intentional",
|
||||
Id.udaMustUse.toChars(), e.type.toPrettyChars(true));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from a symbol's semantic to check for reserved usage of @mustuse.
|
||||
*
|
||||
* If such usage is found, emits an errror.
|
||||
*
|
||||
* Params:
|
||||
* sym = symbol to check
|
||||
*/
|
||||
void checkMustUseReserved(Dsymbol sym)
|
||||
{
|
||||
import dmd.attrib : foreachUdaNoSemantic;
|
||||
import dmd.errors : error;
|
||||
import dmd.id : Id;
|
||||
|
||||
// Can't use foreachUda (and by extension hasMustUseAttribute) while
|
||||
// semantic analysis of `sym` is still in progress
|
||||
foreachUdaNoSemantic(sym, (exp) {
|
||||
if (isMustUseAttribute(exp))
|
||||
{
|
||||
if (sym.isFuncDeclaration())
|
||||
{
|
||||
error(sym.loc, "`@%s` on functions is reserved for future use",
|
||||
Id.udaMustUse.toChars());
|
||||
sym.errors = true;
|
||||
}
|
||||
else if (sym.isClassDeclaration() || sym.isEnumDeclaration())
|
||||
{
|
||||
error(sym.loc, "`@%s` on `%s` types is reserved for future use",
|
||||
Id.udaMustUse.toChars(), sym.kind());
|
||||
sym.errors = true;
|
||||
}
|
||||
}
|
||||
return 0; // continue
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: true if the given expression is an assignment, either simple (a = b)
|
||||
* or compound (a += b, etc).
|
||||
*/
|
||||
private bool isAssignment(Expression e)
|
||||
{
|
||||
if (e.isAssignExp || e.isBinAssignExp)
|
||||
return true;
|
||||
if (auto ce = e.isCallExp())
|
||||
{
|
||||
if (auto fd = ce.f)
|
||||
{
|
||||
auto id = fd.ident;
|
||||
if (id && isAssignmentOpId(id))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: true if id is the identifier of an assignment operator overload.
|
||||
*/
|
||||
private bool isAssignmentOpId(Identifier id)
|
||||
{
|
||||
import dmd.id : Id;
|
||||
|
||||
return id == Id.assign
|
||||
|| id == Id.addass
|
||||
|| id == Id.subass
|
||||
|| id == Id.mulass
|
||||
|| id == Id.divass
|
||||
|| id == Id.modass
|
||||
|| id == Id.andass
|
||||
|| id == Id.orass
|
||||
|| id == Id.xorass
|
||||
|| id == Id.shlass
|
||||
|| id == Id.shrass
|
||||
|| id == Id.ushrass
|
||||
|| id == Id.catass
|
||||
|| id == Id.indexass
|
||||
|| id == Id.slice
|
||||
|| id == Id.sliceass
|
||||
|| id == Id.opOpAssign
|
||||
|| id == Id.opIndexOpAssign
|
||||
|| id == Id.opSliceOpAssign
|
||||
|| id == Id.powass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: true if the given expression is an increment (++) or decrement (--).
|
||||
*/
|
||||
private bool isIncrementOrDecrement(Expression e)
|
||||
{
|
||||
import dmd.dtemplate : isExpression;
|
||||
import dmd.globals : Loc;
|
||||
import dmd.id : Id;
|
||||
import dmd.tokens : EXP;
|
||||
|
||||
if (e.op == EXP.plusPlus
|
||||
|| e.op == EXP.minusMinus
|
||||
|| e.op == EXP.prePlusPlus
|
||||
|| e.op == EXP.preMinusMinus)
|
||||
return true;
|
||||
if (auto call = e.isCallExp())
|
||||
{
|
||||
// Check for overloaded preincrement
|
||||
// e.g., a.opUnary!"++"
|
||||
if (auto fd = call.f)
|
||||
{
|
||||
if (fd.ident == Id.opUnary && fd.parent)
|
||||
{
|
||||
if (auto ti = fd.parent.isTemplateInstance())
|
||||
{
|
||||
auto tiargs = ti.tiargs;
|
||||
if (tiargs && tiargs.length >= 1)
|
||||
{
|
||||
if (auto argExp = (*tiargs)[0].isExpression())
|
||||
{
|
||||
auto op = argExp.isStringExp();
|
||||
if (op && (op.compare(plusPlus) == 0 || op.compare(minusMinus) == 0))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto comma = e.isCommaExp())
|
||||
{
|
||||
// Check for overloaded postincrement
|
||||
// e.g., (auto tmp = a, ++a, tmp)
|
||||
if (comma.e1)
|
||||
{
|
||||
if (auto left = comma.e1.isCommaExp())
|
||||
{
|
||||
if (auto middle = left.e2)
|
||||
{
|
||||
if (middle && isIncrementOrDecrement(middle))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: true if the given symbol has the @mustuse attribute.
|
||||
*/
|
||||
private bool hasMustUseAttribute(Dsymbol sym, Scope* sc)
|
||||
{
|
||||
import dmd.attrib : foreachUda;
|
||||
|
||||
bool result = false;
|
||||
|
||||
foreachUda(sym, sc, (Expression uda) {
|
||||
if (isMustUseAttribute(uda))
|
||||
{
|
||||
result = true;
|
||||
return 1; // break
|
||||
}
|
||||
return 0; // continue
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: true if the given expression is core.attribute.mustuse.
|
||||
*/
|
||||
private bool isMustUseAttribute(Expression e)
|
||||
{
|
||||
import dmd.attrib : isCoreUda;
|
||||
import dmd.id : Id;
|
||||
|
||||
// Logic based on dmd.objc.Supported.declaredAsOptionalCount
|
||||
auto typeExp = e.isTypeExp;
|
||||
if (!typeExp)
|
||||
return false;
|
||||
|
||||
auto typeEnum = typeExp.type.isTypeEnum();
|
||||
if (!typeEnum)
|
||||
return false;
|
||||
|
||||
if (isCoreUda(typeEnum.sym, Id.udaMustUse))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
|
@ -213,7 +213,7 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE
|
|||
*/
|
||||
if (isRecursiveAliasThis(e.att1, e.e1.type))
|
||||
return null;
|
||||
//printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
|
||||
//printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
|
||||
BinExp be = cast(BinExp)e.copy();
|
||||
// Resolve 'alias this' but in case of assigment don't resolve properties yet
|
||||
// because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
|
||||
|
@ -241,7 +241,7 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
|
|||
*/
|
||||
if (isRecursiveAliasThis(e.att2, e.e2.type))
|
||||
return null;
|
||||
//printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
|
||||
//printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
|
||||
BinExp be = cast(BinExp)e.copy();
|
||||
be.e2 = resolveAliasThis(sc, e.e2, true);
|
||||
if (!be.e2)
|
||||
|
|
|
@ -271,7 +271,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
|
|||
*/
|
||||
Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
||||
{
|
||||
//printf("Expression_optimize() %s\n", e.toChars());
|
||||
//printf("Expression_optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue);
|
||||
Expression ret = e;
|
||||
|
||||
void error()
|
||||
|
@ -426,7 +426,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
|
||||
void visitAddr(AddrExp e)
|
||||
{
|
||||
//printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
|
||||
//printf("AddrExp::optimize(result = %d, keepLvalue = %d) %s\n", result, keepLvalue, e.toChars());
|
||||
/* Rewrite &(a,b) as (a,&b)
|
||||
*/
|
||||
if (auto ce = e.e1.isCommaExp())
|
||||
|
@ -438,7 +438,8 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
}
|
||||
// Keep lvalue-ness
|
||||
if (expOptimize(e.e1, result, true))
|
||||
return;
|
||||
return; // error return
|
||||
|
||||
// Convert &*ex to ex
|
||||
if (auto pe = e.e1.isPtrExp())
|
||||
{
|
||||
|
@ -515,6 +516,23 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (auto ei = e.isIndexExp())
|
||||
{
|
||||
if (auto ve = ei.e1.isVarExp())
|
||||
{
|
||||
if (!ve.var.isReference() &&
|
||||
!ve.var.isImportedSymbol() &&
|
||||
ve.var.isDataseg() &&
|
||||
ve.var.isCsymbol())
|
||||
{
|
||||
if (auto ie = ei.e2.isIntegerExp())
|
||||
{
|
||||
var = ve.var.isVarDeclaration();
|
||||
offset += ie.toInteger() * ve.type.toBasetype().nextOf().size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -538,7 +556,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (auto ae = e.e1.isIndexExp())
|
||||
else if (auto ae = e.e1.isIndexExp())
|
||||
{
|
||||
// Convert &array[n] to &array+n
|
||||
if (ae.e2.isIntegerExp() && ae.e1.isVarExp())
|
||||
|
@ -551,9 +569,10 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
sinteger_t dim = ts.dim.toInteger();
|
||||
if (index < 0 || index >= dim)
|
||||
{
|
||||
/* 0 for C static arrays means size is unknown, no need to check
|
||||
/* 0 for C static arrays means size is unknown, no need to check,
|
||||
* and address one past the end is OK, too
|
||||
*/
|
||||
if (!(dim == 0 && ve.var.isCsymbol()))
|
||||
if (!((dim == 0 || dim == index) && ve.var.isCsymbol()))
|
||||
{
|
||||
e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
|
||||
return error();
|
||||
|
@ -585,9 +604,10 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
sinteger_t dim = ts.dim.toInteger();
|
||||
if (index < 0 || index >= dim)
|
||||
{
|
||||
/* 0 for C static arrays means size is unknown, no need to check
|
||||
/* 0 for C static arrays means size is unknown, no need to check,
|
||||
* and address one past the end is OK, too
|
||||
*/
|
||||
if (!(dim == 0 && ve.var.isCsymbol()))
|
||||
if (!((dim == 0 || dim == index) && ve.var.isCsymbol()))
|
||||
{
|
||||
e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
|
||||
return error();
|
||||
|
|
|
@ -14,6 +14,8 @@ module dmd.root.aav;
|
|||
import core.stdc.string;
|
||||
import dmd.root.rmem;
|
||||
|
||||
nothrow:
|
||||
|
||||
private size_t hash(size_t a) pure nothrow @nogc @safe
|
||||
{
|
||||
a ^= (a >> 20) ^ (a >> 12);
|
||||
|
|
|
@ -137,7 +137,7 @@ public:
|
|||
|
||||
void reserve(size_t nentries) pure nothrow
|
||||
{
|
||||
//printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", (int)length, (int)data.length, (int)nentries);
|
||||
//printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", cast(int)length, cast(int)data.length, cast(int)nentries);
|
||||
|
||||
// Cold path
|
||||
void enlarge(size_t nentries)
|
||||
|
|
|
@ -13,11 +13,15 @@ module dmd.root.complex;
|
|||
|
||||
import dmd.root.ctfloat;
|
||||
|
||||
nothrow:
|
||||
|
||||
extern (C++) struct complex_t
|
||||
{
|
||||
real_t re;
|
||||
real_t im;
|
||||
|
||||
nothrow:
|
||||
|
||||
this() @disable;
|
||||
|
||||
this(real_t re)
|
||||
|
|
|
@ -26,11 +26,15 @@ import dmd.root.string;
|
|||
import dmd.common.file;
|
||||
import dmd.common.string;
|
||||
|
||||
/// Owns a (rmem-managed) file buffer.
|
||||
struct FileBuffer
|
||||
nothrow:
|
||||
|
||||
/// Owns a (rmem-managed) buffer.
|
||||
struct Buffer
|
||||
{
|
||||
ubyte[] data;
|
||||
|
||||
nothrow:
|
||||
|
||||
this(this) @disable;
|
||||
|
||||
~this() pure nothrow
|
||||
|
@ -54,7 +58,7 @@ struct File
|
|||
static struct ReadResult
|
||||
{
|
||||
bool success;
|
||||
FileBuffer buffer;
|
||||
Buffer buffer;
|
||||
|
||||
/// Transfers ownership of the buffer to the caller.
|
||||
ubyte[] extractSlice() pure nothrow @nogc @safe
|
||||
|
|
|
@ -29,6 +29,8 @@ nothrow:
|
|||
// Type used by the front-end for compile-time reals
|
||||
struct longdouble
|
||||
{
|
||||
nothrow:
|
||||
@nogc:
|
||||
extern (D) this(T)(T r)
|
||||
{
|
||||
this.set(cast(SetType!T)r);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
*/
|
||||
module dmd.root.optional;
|
||||
|
||||
nothrow:
|
||||
|
||||
///
|
||||
unittest
|
||||
{
|
||||
|
@ -45,6 +47,8 @@ extern (C++) struct Optional(T)
|
|||
/// whether `value` is set
|
||||
private bool present;
|
||||
|
||||
nothrow:
|
||||
|
||||
/// Creates an `Optional` with the given value
|
||||
this(T value)
|
||||
{
|
||||
|
|
|
@ -478,7 +478,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
|
|||
i.mod.semantic2(null);
|
||||
if (i.mod.needmoduleinfo)
|
||||
{
|
||||
//printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars());
|
||||
//printf("module5 %s because of %s\n", sc._module.toChars(), mod.toChars());
|
||||
if (sc)
|
||||
sc._module.needmoduleinfo = 1;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import dmd.importc;
|
|||
import dmd.init;
|
||||
import dmd.intrange;
|
||||
import dmd.mtype;
|
||||
import dmd.mustuse;
|
||||
import dmd.nogc;
|
||||
import dmd.opover;
|
||||
import dmd.parse;
|
||||
|
@ -211,7 +212,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
|||
if (f.checkForwardRef(s.exp.loc))
|
||||
s.exp = ErrorExp.get();
|
||||
}
|
||||
|
||||
if (checkMustUse(s.exp, sc))
|
||||
s.exp = ErrorExp.get();
|
||||
if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
|
||||
s.exp = ErrorExp.get();
|
||||
|
||||
|
|
|
@ -591,7 +591,7 @@ shared static this() nothrow
|
|||
Identifier.initTable();
|
||||
foreach (kw; keywords)
|
||||
{
|
||||
//printf("keyword[%d] = '%s'\n",kw, tochars[kw].ptr);
|
||||
//printf("keyword[%d] = '%s'\n",kw, Token.tochars[kw].ptr);
|
||||
Identifier.idPool(Token.tochars[kw].ptr, Token.tochars[kw].length, cast(uint)kw);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1278,7 +1278,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
|||
{
|
||||
s = s.isImport().mod;
|
||||
}
|
||||
//printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s.scope);
|
||||
//printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s._scope);
|
||||
udad = s.userAttribDecl;
|
||||
}
|
||||
else
|
||||
|
@ -1514,7 +1514,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
|||
TypeFunction tf = toTypeFunction(o, fd);
|
||||
|
||||
if (tf)
|
||||
link = tf.linkage;
|
||||
{
|
||||
link = fd ? fd.linkage : tf.linkage;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto s = getDsymbol(o);
|
||||
|
@ -1730,69 +1732,33 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
|||
bool err = false;
|
||||
|
||||
auto t = isType(o);
|
||||
while (t)
|
||||
auto ex = isExpression(o);
|
||||
if (t)
|
||||
{
|
||||
if (auto tm = t.isTypeMixin())
|
||||
Dsymbol s;
|
||||
t.resolve(e.loc, sc2, ex, t, s);
|
||||
if (t)
|
||||
{
|
||||
/* The mixin string could be a type or an expression.
|
||||
* Have to try compiling it to see.
|
||||
*/
|
||||
OutBuffer buf;
|
||||
if (expressionsToString(buf, sc, tm.exps))
|
||||
{
|
||||
t.typeSemantic(e.loc, sc2);
|
||||
if (t.ty == Terror)
|
||||
err = true;
|
||||
break;
|
||||
}
|
||||
const olderrors = global.errors;
|
||||
const len = buf.length;
|
||||
buf.writeByte(0);
|
||||
const str = buf.extractSlice()[0 .. len];
|
||||
scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false);
|
||||
p.nextToken();
|
||||
//printf("p.loc.linnum = %d\n", p.loc.linnum);
|
||||
|
||||
o = p.parseTypeOrAssignExp(TOK.endOfFile);
|
||||
if (olderrors != global.errors || p.token.value != TOK.endOfFile)
|
||||
{
|
||||
err = true;
|
||||
break;
|
||||
}
|
||||
t = o.isType();
|
||||
}
|
||||
else
|
||||
break;
|
||||
else if (s && s.errors)
|
||||
err = true;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
if (ex)
|
||||
{
|
||||
auto ex = t ? t.typeToExpression() : isExpression(o);
|
||||
if (!ex && t)
|
||||
ex = ex.expressionSemantic(sc2);
|
||||
ex = resolvePropertiesOnly(sc2, ex);
|
||||
ex = ex.optimize(WANTvalue);
|
||||
if (sc2.func && sc2.func.type.ty == Tfunction)
|
||||
{
|
||||
Dsymbol s;
|
||||
t.resolve(e.loc, sc2, ex, t, s);
|
||||
if (t)
|
||||
{
|
||||
t.typeSemantic(e.loc, sc2);
|
||||
if (t.ty == Terror)
|
||||
err = true;
|
||||
}
|
||||
else if (s && s.errors)
|
||||
err = true;
|
||||
}
|
||||
if (ex)
|
||||
{
|
||||
ex = ex.expressionSemantic(sc2);
|
||||
ex = resolvePropertiesOnly(sc2, ex);
|
||||
ex = ex.optimize(WANTvalue);
|
||||
if (sc2.func && sc2.func.type.ty == Tfunction)
|
||||
{
|
||||
const tf = cast(TypeFunction)sc2.func.type;
|
||||
err |= tf.isnothrow && canThrow(ex, sc2.func, false);
|
||||
}
|
||||
ex = checkGC(sc2, ex);
|
||||
if (ex.op == EXP.error)
|
||||
err = true;
|
||||
const tf = cast(TypeFunction)sc2.func.type;
|
||||
err |= tf.isnothrow && canThrow(ex, sc2.func, false);
|
||||
}
|
||||
ex = checkGC(sc2, ex);
|
||||
if (ex.op == EXP.error)
|
||||
err = true;
|
||||
}
|
||||
|
||||
// Carefully detach the scope from the parent and throw it away as
|
||||
|
|
|
@ -1220,6 +1220,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
|||
tf.islive = true;
|
||||
|
||||
tf.linkage = sc.linkage;
|
||||
if (tf.linkage == LINK.system)
|
||||
tf.linkage = target.systemLinkage();
|
||||
|
||||
version (none)
|
||||
{
|
||||
/* If the parent is @safe, then this function defaults to safe
|
||||
|
@ -2281,10 +2284,7 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
|
|||
return null;
|
||||
}
|
||||
|
||||
Type t = o.isType();
|
||||
Expression e = t ? t.typeToExpression() : o.isExpression();
|
||||
|
||||
return (!e && t) ? t : e;
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3619,12 +3619,31 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
|
|||
e.error("`%s` is not an expression", e.toChars());
|
||||
return ErrorExp.get();
|
||||
}
|
||||
else if (checkUnsafeDotExp(sc, e, ident, flag))
|
||||
else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
|
||||
{
|
||||
// .ptr on static array is @safe unless size is 0
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20853
|
||||
return ErrorExp.get();
|
||||
}
|
||||
e = e.castTo(sc, e.type.nextOf().pointerTo());
|
||||
}
|
||||
else if (ident == Id._tupleof)
|
||||
{
|
||||
if (e.isTypeExp())
|
||||
{
|
||||
e.error("`.tupleof` cannot be used on type `%s`", mt.toChars);
|
||||
return ErrorExp.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
const length = cast(size_t)mt.dim.toUInteger();
|
||||
auto exps = new Expressions();
|
||||
exps.reserve(length);
|
||||
foreach (i; 0 .. length)
|
||||
exps.push(new IndexExp(e.loc, e, new IntegerExp(e.loc, i, Type.tsize_t)));
|
||||
e = new TupleExp(e.loc, exps);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e = visitArray(mt);
|
||||
|
|
|
@ -19,6 +19,7 @@ import dmd.root.filename;
|
|||
import dmd.common.outbuffer;
|
||||
import dmd.root.string;
|
||||
|
||||
nothrow:
|
||||
|
||||
/**
|
||||
* Normalize path by turning forward slashes into backslashes
|
||||
|
@ -52,13 +53,13 @@ const(char)* toWinPath(const(char)* src)
|
|||
* loc = The line number information from where the call originates
|
||||
* filename = Path to file
|
||||
*/
|
||||
FileBuffer readFile(Loc loc, const(char)* filename)
|
||||
Buffer readFile(Loc loc, const(char)* filename)
|
||||
{
|
||||
return readFile(loc, filename.toDString());
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
FileBuffer readFile(Loc loc, const(char)[] filename)
|
||||
Buffer readFile(Loc loc, const(char)[] filename)
|
||||
{
|
||||
auto result = File.read(filename);
|
||||
if (!result.success)
|
||||
|
@ -66,7 +67,7 @@ FileBuffer readFile(Loc loc, const(char)[] filename)
|
|||
error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
|
||||
fatal();
|
||||
}
|
||||
return FileBuffer(result.extractSlice());
|
||||
return Buffer(result.extractSlice());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3006,6 +3006,16 @@ public:
|
|||
this->result_ = var;
|
||||
}
|
||||
|
||||
/* Build an uninitialized value, generated from void initializers. */
|
||||
|
||||
void visit (VoidInitExp *e)
|
||||
{
|
||||
/* The front-end only generates these for the initializer of globals.
|
||||
Represent `void' as zeroes, regardless of the type's default value. */
|
||||
gcc_assert (this->constp_);
|
||||
this->result_ = build_zero_cst (build_ctype (e->type));
|
||||
}
|
||||
|
||||
/* These expressions are mainly just a placeholders in the frontend.
|
||||
We shouldn't see them here. */
|
||||
|
||||
|
|
|
@ -607,3 +607,13 @@ T throwStuff(T)(T t)
|
|||
if (false) test13x(1, throw new Exception(""), 2);
|
||||
return t ? t : throw new Exception("Bad stuff happens!");
|
||||
}
|
||||
|
||||
class C12344
|
||||
{
|
||||
abstract int c12344(int x) in(x > 0) out(result) {assert(result > 0);};
|
||||
}
|
||||
|
||||
interface I12344
|
||||
{
|
||||
int i12344(int x) in(x > 0) out(result) {assert(result > 0);};
|
||||
}
|
||||
|
|
1
gcc/testsuite/gdc.test/compilable/imports/imp17434a.d
Normal file
1
gcc/testsuite/gdc.test/compilable/imports/imp17434a.d
Normal file
|
@ -0,0 +1 @@
|
|||
module imp17434a.test1;
|
6
gcc/testsuite/gdc.test/compilable/imports/imp17434b.d
Normal file
6
gcc/testsuite/gdc.test/compilable/imports/imp17434b.d
Normal file
|
@ -0,0 +1,6 @@
|
|||
module imp.imports17434b;
|
||||
|
||||
void testing()
|
||||
{
|
||||
return;
|
||||
}
|
|
@ -2473,12 +2473,12 @@ static assert(checkPass("foobar") == 1);
|
|||
|
||||
struct Toq
|
||||
{
|
||||
const(char)* m;
|
||||
char* m;
|
||||
}
|
||||
|
||||
Toq ptrRet(bool b)
|
||||
{
|
||||
string x = "abc";
|
||||
char[] x = "abc".dup;
|
||||
return Toq(b ? x[0 .. 1].ptr : null);
|
||||
}
|
||||
|
||||
|
@ -7808,3 +7808,101 @@ int test9937()
|
|||
}
|
||||
|
||||
static assert(test9937());
|
||||
|
||||
/************************************************/
|
||||
// static array .tupleof
|
||||
|
||||
struct SArrayTupleEquiv(T)
|
||||
{
|
||||
T f1;
|
||||
T f2;
|
||||
}
|
||||
|
||||
// basic .tupleof invariants
|
||||
bool testSArrayTupleA()
|
||||
{
|
||||
int[2] xs;
|
||||
assert(xs.tupleof == TypeTuple!(0, 0));
|
||||
assert(xs.tupleof == (cast(int[2])[0, 0]).tupleof);
|
||||
|
||||
xs.tupleof = TypeTuple!(1, 2);
|
||||
assert(xs.tupleof == TypeTuple!(1, 2));
|
||||
|
||||
auto ys = SArrayTupleEquiv!int(1, 2);
|
||||
assert(xs.tupleof == ys.tupleof);
|
||||
|
||||
return true;
|
||||
}
|
||||
static assert(testSArrayTupleA());
|
||||
|
||||
// tuples with side effects
|
||||
bool testSArrayTupleB()
|
||||
{
|
||||
// Counter records lifetime events in copies/dtors, as a cheap way to check that .tupleof for
|
||||
// static arrays exhibit all the same side effects as an equivalent struct's .tupleof
|
||||
int[int] copies;
|
||||
int[int] dtors;
|
||||
struct Counter
|
||||
{
|
||||
int id = -1;
|
||||
|
||||
this(this)
|
||||
{
|
||||
copies[id] = copies.get(id, 0) + 1;
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dtors[id] = dtors.get(id, 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void consume(Counter, Counter) {}
|
||||
Counter[2] produce(int id1, int id2)
|
||||
{
|
||||
return [Counter(id1), Counter(id2)];
|
||||
}
|
||||
|
||||
// first sample expected behavior from struct .tupleof
|
||||
// braces create a subscope, shortening lifetimes
|
||||
{
|
||||
auto a = SArrayTupleEquiv!Counter(Counter(0), Counter(1));
|
||||
|
||||
typeof(a) b;
|
||||
b.tupleof = a.tupleof;
|
||||
|
||||
Counter x, y;
|
||||
TypeTuple!(x, y) = a.tupleof;
|
||||
|
||||
a.tupleof[0] = Counter(2);
|
||||
a.tupleof[1] = Counter(3);
|
||||
consume(a.tupleof);
|
||||
|
||||
a.tupleof = produce(4, 5).tupleof;
|
||||
}
|
||||
int[int][2] expected = [copies.dup, dtors.dup];
|
||||
copies = null; // .clear is not CTFE friendly
|
||||
dtors = null;
|
||||
|
||||
// the real test -- sample behavior of array .tupleof
|
||||
{
|
||||
Counter[2] a = [Counter(0), Counter(1)];
|
||||
|
||||
typeof(a) b;
|
||||
b.tupleof = a.tupleof;
|
||||
|
||||
Counter x, y;
|
||||
TypeTuple!(x, y) = a.tupleof;
|
||||
|
||||
a.tupleof[0] = Counter(2);
|
||||
a.tupleof[1] = Counter(3);
|
||||
consume(a.tupleof);
|
||||
|
||||
a.tupleof = produce(4, 5).tupleof;
|
||||
}
|
||||
assert(expected[0] == copies);
|
||||
assert(expected[1] == dtors);
|
||||
|
||||
return true;
|
||||
}
|
||||
static assert(testSArrayTupleB());
|
||||
|
|
|
@ -203,14 +203,14 @@ extern(C) int vlinakgeC;
|
|||
extern(C++) __gshared int vlinkageCpp;
|
||||
extern(Windows) int vlinkageWindows;
|
||||
extern(Objective-C) int vlinkageObjc;
|
||||
|
||||
extern(System) int vlinkageSystem;
|
||||
extern int flinkageDefault();
|
||||
extern(D) int flinkageD();
|
||||
extern(C) int linakgeC();
|
||||
extern(C++) int flinkageCpp();
|
||||
extern(Windows) int flinkageWindows();
|
||||
extern(Objective-C) int flinkageObjc();
|
||||
|
||||
extern(System) int flinkageSystem();
|
||||
mixin template test18211(int n)
|
||||
{
|
||||
static foreach (i; 0 .. n>10 ? 10 : n)
|
||||
|
|
|
@ -115,3 +115,9 @@ void test_statements_22356()
|
|||
mixin("int") y22356, z22356;
|
||||
static assert(is(typeof(y22356) == int) && is(typeof(z22356) == int));
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22969
|
||||
|
||||
enum e = 0;
|
||||
alias a = mixin("e");
|
||||
|
|
9
gcc/testsuite/gdc.test/compilable/must_use_assign.d
Normal file
9
gcc/testsuite/gdc.test/compilable/must_use_assign.d
Normal file
|
@ -0,0 +1,9 @@
|
|||
import core.attribute;
|
||||
|
||||
@mustuse struct S {}
|
||||
|
||||
void test()
|
||||
{
|
||||
S a, b;
|
||||
a = b;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import core.attribute;
|
||||
|
||||
@mustuse int n;
|
||||
@mustuse alias A = int;
|
||||
@mustuse template tpl() {}
|
15
gcc/testsuite/gdc.test/compilable/must_use_opassign.d
Normal file
15
gcc/testsuite/gdc.test/compilable/must_use_opassign.d
Normal file
|
@ -0,0 +1,15 @@
|
|||
import core.attribute;
|
||||
|
||||
@mustuse struct S
|
||||
{
|
||||
ref S opAssign(S rhs) return
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
S a, b;
|
||||
a = b;
|
||||
}
|
15
gcc/testsuite/gdc.test/compilable/must_use_opopassign.d
Normal file
15
gcc/testsuite/gdc.test/compilable/must_use_opopassign.d
Normal file
|
@ -0,0 +1,15 @@
|
|||
import core.attribute;
|
||||
|
||||
@mustuse struct S
|
||||
{
|
||||
ref S opOpAssign(string op)(S rhs) return
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
S a, b;
|
||||
a += b;
|
||||
}
|
18
gcc/testsuite/gdc.test/compilable/must_use_opunary.d
Normal file
18
gcc/testsuite/gdc.test/compilable/must_use_opunary.d
Normal file
|
@ -0,0 +1,18 @@
|
|||
import core.attribute;
|
||||
|
||||
@mustuse struct S
|
||||
{
|
||||
ref S opUnary(string op)() return
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
S s;
|
||||
++s;
|
||||
--s;
|
||||
s++;
|
||||
s--;
|
||||
}
|
10
gcc/testsuite/gdc.test/compilable/must_use_suppress.d
Normal file
10
gcc/testsuite/gdc.test/compilable/must_use_suppress.d
Normal file
|
@ -0,0 +1,10 @@
|
|||
import core.attribute;
|
||||
|
||||
@mustuse struct S {}
|
||||
|
||||
S fun() { return S(); }
|
||||
|
||||
void test()
|
||||
{
|
||||
cast(void) fun();
|
||||
}
|
|
@ -17,10 +17,7 @@ static assert(__traits(getLinkage, food) == "D");
|
|||
static assert(__traits(getLinkage, foocpp) == "C++");
|
||||
static assert(__traits(getLinkage, foow) == "Windows");
|
||||
static assert(__traits(getLinkage, fooobjc) == "Objective-C");
|
||||
version (Windows)
|
||||
static assert(__traits(getLinkage, foos) == "Windows");
|
||||
else
|
||||
static assert(__traits(getLinkage, foos) == "C");
|
||||
static assert(__traits(getLinkage, foos) == "System");
|
||||
|
||||
extern (C) int global;
|
||||
static assert(__traits(getLinkage, global) == "C");
|
||||
|
|
11
gcc/testsuite/gdc.test/compilable/test17434.d
Normal file
11
gcc/testsuite/gdc.test/compilable/test17434.d
Normal file
|
@ -0,0 +1,11 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=17434
|
||||
|
||||
// EXTRA_FILES: test17434a.d imports/imp17434a.d imports/imp17434b.d
|
||||
module test17434;
|
||||
|
||||
import test17434a;
|
||||
|
||||
void main()
|
||||
{
|
||||
imports.imp17434b.testing();
|
||||
}
|
5
gcc/testsuite/gdc.test/compilable/test17434a.d
Normal file
5
gcc/testsuite/gdc.test/compilable/test17434a.d
Normal file
|
@ -0,0 +1,5 @@
|
|||
// EXTRA_FILES: imports/imp17434a.d imports/imp17434b.d
|
||||
module test17434a;
|
||||
|
||||
private import imports.imp17434a;
|
||||
public import imports.imp17434b;
|
|
@ -21,3 +21,43 @@ void foo(scope int* pf)
|
|||
betty(rf, pf);
|
||||
boop(rf, pf);
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22801
|
||||
struct Wrapper
|
||||
{
|
||||
int* ptr;
|
||||
|
||||
this(return ref int var) @safe
|
||||
{
|
||||
this.ptr = &var;
|
||||
}
|
||||
}
|
||||
|
||||
void main() @safe
|
||||
{
|
||||
int i;
|
||||
auto w = Wrapper(i);
|
||||
auto wt = WrapperT!()(i);
|
||||
}
|
||||
|
||||
void assign(ref scope int* x, return ref int y) @safe
|
||||
{
|
||||
x = &y;
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22967
|
||||
// inference of `return ref` when assigned to first parameter
|
||||
struct WrapperT()
|
||||
{
|
||||
int* ptr;
|
||||
|
||||
this(ref int var) @safe
|
||||
{
|
||||
this.ptr = &var;
|
||||
}
|
||||
|
||||
static void assignInferred(ref scope int* xi, ref int yi) @safe
|
||||
{
|
||||
xi = &yi;
|
||||
}
|
||||
}
|
||||
|
|
15
gcc/testsuite/gdc.test/compilable/test22988.d
Normal file
15
gcc/testsuite/gdc.test/compilable/test22988.d
Normal file
|
@ -0,0 +1,15 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=22988
|
||||
|
||||
enum a1 = 0;
|
||||
enum b1 = a1 ? 1 << a1 - 1 : 0;
|
||||
|
||||
enum l = 0;
|
||||
enum int[l] a2 = [];
|
||||
enum b2 = l ? a2[l - 1] : 0;
|
||||
|
||||
enum a3 = 0 ? 1 << -1 : 0;
|
||||
|
||||
enum int[0] a4 = [];
|
||||
enum b4 = 0 ? a4[0] : 0;
|
||||
|
||||
enum b5 = false ? (1 << -1) : 0;
|
14
gcc/testsuite/gdc.test/compilable/test22997.d
Normal file
14
gcc/testsuite/gdc.test/compilable/test22997.d
Normal file
|
@ -0,0 +1,14 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=22997
|
||||
|
||||
struct Forward {}
|
||||
|
||||
struct Foo
|
||||
{
|
||||
this(ref typeof(this) rhs)
|
||||
{
|
||||
this(rhs, Forward.init);
|
||||
}
|
||||
|
||||
this(ref typeof(this) rhs, Forward) {}
|
||||
this(typeof(this) rhs, int i, double d, string s) {}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
EXTRA_FILES: imports/a14235.d
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diag14235.d(12): Error: template identifier `Undefined` is not a member of module `imports.a14235`
|
||||
fail_compilation/diag14235.d(13): Error: template identifier `Something` is not a member of module `imports.a14235`, did you mean struct `SomeThing(T...)`?
|
||||
fail_compilation/diag14235.d(12): Error: undefined identifier `Undefined` in module `imports.a14235`
|
||||
fail_compilation/diag14235.d(13): Error: undefined identifier `Something` in module `imports.a14235`, did you mean struct `SomeThing(T...)`?
|
||||
fail_compilation/diag14235.d(14): Error: `imports.a14235.SomeClass` is not a template, it is a class
|
||||
---
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diag8101.d(57): Error: function `diag8101.f_0(int)` is not callable using argument types `()`
|
||||
fail_compilation/diag8101.d(57): missing argument for parameter #1: `int`
|
||||
fail_compilation/diag8101.d(57): too few arguments, expected `1`, got `0`
|
||||
fail_compilation/diag8101.d(58): Error: none of the overloads of `f_1` are callable using argument types `()`
|
||||
fail_compilation/diag8101.d(33): Candidates are: `diag8101.f_1(int)`
|
||||
fail_compilation/diag8101.d(34): `diag8101.f_1(int, int)`
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diag_funclit.d(103): Error: function literal `__lambda1(x, y, z)` is not callable using argument types `()`
|
||||
fail_compilation/diag_funclit.d(103): missing argument for parameter #1: `x`
|
||||
fail_compilation/diag_funclit.d(103): too few arguments, expected `3`, got `0`
|
||||
fail_compilation/diag_funclit.d(106): Error: function literal `__lambda2(x, y, z)` is not callable using argument types `(int, string, int, int)`
|
||||
fail_compilation/diag_funclit.d(106): too many arguments, expected `3`, got `4`
|
||||
fail_compilation/diag_funclit.d(108): Error: function literal `__lambda3(x, y, string z = "Hello")` is not callable using argument types `(int, int, string, string)`
|
||||
|
|
|
@ -3,7 +3,7 @@ PERMUTE_ARGS: -preview=in
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()`
|
||||
fail_compilation/diagin.d(14): missing argument for parameter #1: `in int`
|
||||
fail_compilation/diagin.d(14): too few arguments, expected `1`, got `0`
|
||||
fail_compilation/diagin.d(16): Error: none of the overloads of template `diagin.foo1` are callable using argument types `!()(bool[])`
|
||||
fail_compilation/diagin.d(20): Candidate is: `foo1(T)(in T v, string)`
|
||||
---
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail2656.d(21): Error: octal literals `0123` are no longer supported, use `std.conv.octal!123` instead
|
||||
fail_compilation/fail2656.d(22): Error: octal literals `01000000000000000000000` are no longer supported, use `std.conv.octal!1000000000000000000000` instead
|
||||
fail_compilation/fail2656.d(23): Error: octal literals `0100000L` are no longer supported, use `std.conv.octal!100000L` instead
|
||||
fail_compilation/fail2656.d(24): Error: octal literals `01777777777777777777777u` are no longer supported, use `std.conv.octal!1777777777777777777777u` instead
|
||||
fail_compilation/fail2656.d(25): Error: octal literals `017777777777uL` are no longer supported, use `std.conv.octal!17777777777uL` instead
|
||||
fail_compilation/fail2656.d(26): Error: octal literals `0177777` are no longer supported, use `std.conv.octal!177777` instead
|
||||
fail_compilation/fail2656.d(27): Error: octal literals `020000000000L` are no longer supported, use `std.conv.octal!20000000000L` instead
|
||||
fail_compilation/fail2656.d(28): Error: octal literals `0200000u` are no longer supported, use `std.conv.octal!200000u` instead
|
||||
fail_compilation/fail2656.d(29): Error: octal literals `037777777777uL` are no longer supported, use `std.conv.octal!37777777777uL` instead
|
||||
fail_compilation/fail2656.d(30): Error: octal literals `040000000000` are no longer supported, use `std.conv.octal!40000000000` instead
|
||||
fail_compilation/fail2656.d(31): Error: octal literals `0777777777777777777777L` are no longer supported, use `std.conv.octal!777777777777777777777L` instead
|
||||
fail_compilation/fail2656.d(32): Error: octal literals `077777u` are no longer supported, use `std.conv.octal!77777u` instead
|
||||
fail_compilation/fail2656.d(33): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead
|
||||
fail_compilation/fail2656.d(34): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead
|
||||
fail_compilation/fail2656.d(21): Error: octal literals `0123` are no longer supported, use `std.conv.octal!"123"` instead
|
||||
fail_compilation/fail2656.d(22): Error: octal literals `01000000000000000000000` are no longer supported, use `std.conv.octal!"1000000000000000000000"` instead
|
||||
fail_compilation/fail2656.d(23): Error: octal literals `0100000L` are no longer supported, use `std.conv.octal!"100000L"` instead
|
||||
fail_compilation/fail2656.d(24): Error: octal literals `01777777777777777777777u` are no longer supported, use `std.conv.octal!"1777777777777777777777u"` instead
|
||||
fail_compilation/fail2656.d(25): Error: octal literals `017777777777uL` are no longer supported, use `std.conv.octal!"17777777777uL"` instead
|
||||
fail_compilation/fail2656.d(26): Error: octal literals `0177777` are no longer supported, use `std.conv.octal!"177777"` instead
|
||||
fail_compilation/fail2656.d(27): Error: octal literals `020000000000L` are no longer supported, use `std.conv.octal!"20000000000L"` instead
|
||||
fail_compilation/fail2656.d(28): Error: octal literals `0200000u` are no longer supported, use `std.conv.octal!"200000u"` instead
|
||||
fail_compilation/fail2656.d(29): Error: octal literals `037777777777uL` are no longer supported, use `std.conv.octal!"37777777777uL"` instead
|
||||
fail_compilation/fail2656.d(30): Error: octal literals `040000000000` are no longer supported, use `std.conv.octal!"40000000000"` instead
|
||||
fail_compilation/fail2656.d(31): Error: octal literals `0777777777777777777777L` are no longer supported, use `std.conv.octal!"777777777777777777777L"` instead
|
||||
fail_compilation/fail2656.d(32): Error: octal literals `077777u` are no longer supported, use `std.conv.octal!"77777u"` instead
|
||||
fail_compilation/fail2656.d(33): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!"77777uL"` instead
|
||||
fail_compilation/fail2656.d(34): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!"77777uL"` instead
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail99.d(13): Error: delegate `dg(int)` is not callable using argument types `()`
|
||||
fail_compilation/fail99.d(13): missing argument for parameter #1: `int`
|
||||
fail_compilation/fail99.d(13): too few arguments, expected `1`, got `0`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ fail_compilation/fix19059.d(16): Error: octal digit expected, not `8`
|
|||
fail_compilation/fix19059.d(16): Error: octal literals larger than 7 are no longer supported
|
||||
fail_compilation/fix19059.d(17): Error: octal digit expected, not `9`
|
||||
fail_compilation/fix19059.d(17): Error: octal literals larger than 7 are no longer supported
|
||||
fail_compilation/fix19059.d(18): Error: octal literals `010` are no longer supported, use `std.conv.octal!10` instead
|
||||
fail_compilation/fix19059.d(18): Error: octal literals `010` are no longer supported, use `std.conv.octal!"10"` instead
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/ice10922.d(10): Error: function `ice10922.__lambda4(in uint n)` is not callable using argument types `()`
|
||||
fail_compilation/ice10922.d(10): missing argument for parameter #1: `in uint n`
|
||||
fail_compilation/ice10922.d(10): too few arguments, expected `1`, got `0`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int _param_0)` is not callable using argument types `()`
|
||||
fail_compilation/ice9540.d(35): missing argument for parameter #1: `int _param_0`
|
||||
fail_compilation/ice9540.d(35): too few arguments, expected `1`, got `0`
|
||||
fail_compilation/ice9540.d(26): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating
|
||||
---
|
||||
*/
|
||||
|
|
16
gcc/testsuite/gdc.test/fail_compilation/must_use.d
Normal file
16
gcc/testsuite/gdc.test/fail_compilation/must_use.d
Normal file
|
@ -0,0 +1,16 @@
|
|||
/+
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/must_use.d(15): Error: ignored value of `@mustuse` type `must_use.S`; prepend a `cast(void)` if intentional
|
||||
---
|
||||
+/
|
||||
import core.attribute;
|
||||
|
||||
@mustuse struct S {}
|
||||
|
||||
S fun() { return S(); }
|
||||
|
||||
void test()
|
||||
{
|
||||
fun();
|
||||
}
|
17
gcc/testsuite/gdc.test/fail_compilation/must_use_comma.d
Normal file
17
gcc/testsuite/gdc.test/fail_compilation/must_use_comma.d
Normal file
|
@ -0,0 +1,17 @@
|
|||
/+
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/must_use_comma.d(16): Error: ignored value of `@mustuse` type `must_use_comma.S`; prepend a `cast(void)` if intentional
|
||||
---
|
||||
+/
|
||||
import core.attribute;
|
||||
|
||||
@mustuse struct S {}
|
||||
|
||||
S fun() { return S(); }
|
||||
void sideEffect() {}
|
||||
|
||||
void test()
|
||||
{
|
||||
(fun(), sideEffect());
|
||||
}
|
21
gcc/testsuite/gdc.test/fail_compilation/must_use_opunary.d
Normal file
21
gcc/testsuite/gdc.test/fail_compilation/must_use_opunary.d
Normal file
|
@ -0,0 +1,21 @@
|
|||
/+
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/must_use_opunary.d(20): Error: ignored value of `@mustuse` type `must_use_opunary.S`; prepend a `cast(void)` if intentional
|
||||
---
|
||||
+/
|
||||
import core.attribute;
|
||||
|
||||
@mustuse struct S
|
||||
{
|
||||
ref S opUnary(string op)() return
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
S s;
|
||||
-s;
|
||||
}
|
20
gcc/testsuite/gdc.test/fail_compilation/must_use_reserved.d
Normal file
20
gcc/testsuite/gdc.test/fail_compilation/must_use_reserved.d
Normal file
|
@ -0,0 +1,20 @@
|
|||
/+
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/must_use_reserved.d(14): Error: `@mustuse` on `class` types is reserved for future use
|
||||
fail_compilation/must_use_reserved.d(15): Error: `@mustuse` on `interface` types is reserved for future use
|
||||
fail_compilation/must_use_reserved.d(16): Error: `@mustuse` on `enum` types is reserved for future use
|
||||
fail_compilation/must_use_reserved.d(17): Error: `@mustuse` on functions is reserved for future use
|
||||
fail_compilation/must_use_reserved.d(19): Error: `@mustuse` on `class` types is reserved for future use
|
||||
fail_compilation/must_use_reserved.d(20): Error: template instance `must_use_reserved.CT!int` error instantiating
|
||||
---
|
||||
+/
|
||||
import core.attribute;
|
||||
|
||||
@mustuse class C {}
|
||||
@mustuse interface I {}
|
||||
@mustuse enum E { x }
|
||||
@mustuse int fun() { return 0; }
|
||||
|
||||
@mustuse class CT(T) {}
|
||||
alias _ = CT!int;
|
16
gcc/testsuite/gdc.test/fail_compilation/must_use_template.d
Normal file
16
gcc/testsuite/gdc.test/fail_compilation/must_use_template.d
Normal file
|
@ -0,0 +1,16 @@
|
|||
/+
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/must_use_template.d(15): Error: ignored value of `@mustuse` type `must_use_template.S!int`; prepend a `cast(void)` if intentional
|
||||
---
|
||||
+/
|
||||
import core.attribute;
|
||||
|
||||
@mustuse struct S(T) {}
|
||||
|
||||
S!int fun() { return S!int(); }
|
||||
|
||||
void test()
|
||||
{
|
||||
fun();
|
||||
}
|
16
gcc/testsuite/gdc.test/fail_compilation/must_use_union.d
Normal file
16
gcc/testsuite/gdc.test/fail_compilation/must_use_union.d
Normal file
|
@ -0,0 +1,16 @@
|
|||
/+
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/must_use_union.d(15): Error: ignored value of `@mustuse` type `must_use_union.U`; prepend a `cast(void)` if intentional
|
||||
---
|
||||
+/
|
||||
import core.attribute;
|
||||
|
||||
@mustuse union U {}
|
||||
|
||||
U fun() { return U(); }
|
||||
|
||||
void test()
|
||||
{
|
||||
fun();
|
||||
}
|
|
@ -12,6 +12,10 @@ fail_compilation/test11176.d(16): Error: `b.ptr` cannot be used in `@safe` code,
|
|||
return *b.ptr;
|
||||
}
|
||||
|
||||
@safe ubyte oops(ubyte[3] b) {
|
||||
@safe ubyte oops(ubyte[0] b) {
|
||||
return *b.ptr;
|
||||
}
|
||||
|
||||
@safe ubyte cool(ubyte[1] b) {
|
||||
return *b.ptr;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test17284.d(1): Error: no identifier for declarator `TEST_OUTPUT`
|
||||
fail_compilation/test17284.d(1): Error: declaration expected, not `:`
|
||||
fail_compilation/test17284.d(12): Error: unmatched closing brace
|
||||
fail_compilation/test17284.d(16): Error: field `U.c` cannot access pointers in `@safe` code that overlap other fields
|
||||
pure nothrow @safe void(U t)
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
/* REQUIRED_ARGS: -preview=dip1000
|
||||
* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test19097.d(37): Error: scope variable `s` may not be returned
|
||||
fail_compilation/test19097.d(66): Error: scope variable `z` assigned to `refPtr` with longer lifetime
|
||||
fail_compilation/test19097.d(97): Error: scope variable `s` may not be returned
|
||||
fail_compilation/test19097.d(44): Error: scope variable `s` may not be returned
|
||||
fail_compilation/test19097.d(48): Error: scope variable `s1` may not be returned
|
||||
fail_compilation/test19097.d(77): Error: scope variable `z` assigned to `refPtr` with longer lifetime
|
||||
fail_compilation/test19097.d(108): Error: scope variable `s4` may not be returned
|
||||
fail_compilation/test19097.d(126): Error: scope variable `s5c` may not be returned
|
||||
fail_compilation/test19097.d(130): Error: scope variable `s5m` may not be returned
|
||||
fail_compilation/test19097.d(147): Error: scope variable `s6c` may not be returned
|
||||
fail_compilation/test19097.d(151): Error: scope variable `s6m` may not be returned
|
||||
---
|
||||
*/
|
||||
|
||||
// Test extended return-scope / return-ref semantics, e.g. assigning to `this` or the first parameter
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=19097
|
||||
|
||||
@safe:
|
||||
|
@ -35,6 +42,10 @@ S thorin()
|
|||
int i;
|
||||
S s = S(&i); // should infer scope for s
|
||||
return s; // so this should error
|
||||
|
||||
S s1;
|
||||
s1.mem(&i);
|
||||
return s1;
|
||||
}
|
||||
|
||||
/************************/
|
||||
|
@ -93,6 +104,49 @@ struct S4
|
|||
int* escape2()
|
||||
{
|
||||
int x;
|
||||
auto s = S4(0, &x);
|
||||
return s.p;
|
||||
auto s4 = S4(0, &x);
|
||||
return s4.p;
|
||||
}
|
||||
|
||||
/************************/
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22801
|
||||
struct S5
|
||||
{
|
||||
int* a;
|
||||
this(return ref int b) { a = &b; }
|
||||
|
||||
int* c;
|
||||
void mem(return ref int d) scope { c = &d; }
|
||||
}
|
||||
|
||||
S5 frerin()
|
||||
{
|
||||
int i;
|
||||
S5 s5c = S5(i); // should infer scope for s
|
||||
return s5c; // so this should error
|
||||
|
||||
S5 s5m;
|
||||
s5m.mem(i);
|
||||
return s5m;
|
||||
}
|
||||
|
||||
|
||||
struct S6
|
||||
{
|
||||
int** a;
|
||||
this(return ref int* b) { a = &b; }
|
||||
|
||||
int** c;
|
||||
void mem(return ref int* d) scope { c = &d; }
|
||||
}
|
||||
|
||||
S6 dis()
|
||||
{
|
||||
int* i = null;
|
||||
S6 s6c = S6(i); // should infer scope for s
|
||||
return s6c; // so this should error
|
||||
|
||||
S6 s6m;
|
||||
s6m.mem(i);
|
||||
return s6m;
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular
|
|||
fail_compilation/test21008.d(117): Error: need `this` for `toString` of type `string()`
|
||||
fail_compilation/test21008.d(117): Error: need `this` for `toHash` of type `nothrow @trusted $?:32=uint|64=ulong$()`
|
||||
fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()`
|
||||
fail_compilation/test21008.d(117): missing argument for parameter #1: `Object o`
|
||||
fail_compilation/test21008.d(117): too few arguments, expected `1`, got `0`
|
||||
fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()`
|
||||
fail_compilation/test21008.d(117): missing argument for parameter #1: `Object o`
|
||||
fail_compilation/test21008.d(117): too few arguments, expected `1`, got `0`
|
||||
fail_compilation/test21008.d(117): Error: `Monitor` has no effect
|
||||
fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()`
|
||||
fail_compilation/test21008.d(117): missing argument for parameter #1: `string classname`
|
||||
fail_compilation/test21008.d(117): too few arguments, expected `1`, got `0`
|
||||
fail_compilation/test21008.d(105): called from here: `handleMiddlewareAnnotation()`
|
||||
fail_compilation/test21008.d(108): Error: class `test21008.C` no size because of forward reference
|
||||
---
|
||||
|
|
31
gcc/testsuite/gdc.test/runnable/test20603.d
Normal file
31
gcc/testsuite/gdc.test/runnable/test20603.d
Normal file
|
@ -0,0 +1,31 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=20603
|
||||
|
||||
enum immutable(int)* x = new int(3);
|
||||
enum const(int)* y = new int(5);
|
||||
|
||||
struct Base {
|
||||
union {
|
||||
int overlap;
|
||||
immutable(Sub)* sub;
|
||||
}
|
||||
|
||||
this(Sub) {
|
||||
sub = new Sub;
|
||||
}
|
||||
}
|
||||
|
||||
struct Sub {
|
||||
Base base;
|
||||
}
|
||||
|
||||
immutable c0 = Base(Sub.init);
|
||||
|
||||
void main()
|
||||
{
|
||||
enum const(int)* z = new int(9);
|
||||
|
||||
assert(*x == 3);
|
||||
assert(*y == 5);
|
||||
assert(*z == 9);
|
||||
assert(c0.sub.base.sub == null);
|
||||
}
|
|
@ -3816,8 +3816,8 @@ void test153()
|
|||
/***************************************************/
|
||||
// https://issues.dlang.org/show_bug.cgi?id=3632
|
||||
|
||||
|
||||
void test154() {
|
||||
void test154()
|
||||
{
|
||||
float f;
|
||||
assert(f is float.init);
|
||||
double d;
|
||||
|
@ -3832,6 +3832,87 @@ void test154() {
|
|||
|
||||
/***************************************************/
|
||||
|
||||
__gshared int global3632 = 1;
|
||||
|
||||
void test3632()
|
||||
{
|
||||
int test(T)()
|
||||
{
|
||||
static struct W
|
||||
{
|
||||
T f;
|
||||
this(T g) { if (__ctfe || global3632) f = g; }
|
||||
}
|
||||
auto nan = W(T.nan);
|
||||
auto nan2 = W(T.nan);
|
||||
auto init = W(T.init);
|
||||
auto init2 = W(T.init);
|
||||
auto zero = W(cast(T)0);
|
||||
auto zero2 = W(cast(T)0);
|
||||
auto nzero2 = W(-cast(T)0);
|
||||
|
||||
// Struct equality
|
||||
assert(!(nan == nan2));
|
||||
assert(!(nan == init2));
|
||||
assert(!(init == init2));
|
||||
assert( (zero == zero2));
|
||||
assert( (zero == nzero2));
|
||||
|
||||
// Float equality
|
||||
assert(!(nan.f == nan2.f));
|
||||
assert(!(nan.f == init2.f));
|
||||
assert(!(init.f == init2.f));
|
||||
assert( (zero.f == zero2.f));
|
||||
assert( (zero.f == nzero2.f));
|
||||
|
||||
// Struct identity
|
||||
assert( (nan is nan2));
|
||||
assert( (nan is init2));
|
||||
assert( (init is init2));
|
||||
assert( (zero is zero2));
|
||||
assert(!(zero is nzero2));
|
||||
|
||||
// Float identity
|
||||
assert( (nan.f is nan2.f));
|
||||
assert( (nan.f is init2.f));
|
||||
assert( (init.f is init2.f));
|
||||
assert( (zero.f is zero2.f));
|
||||
assert(!(zero.f is nzero2.f));
|
||||
|
||||
// Struct !identity
|
||||
assert(!(nan !is nan2));
|
||||
assert( (nan is init2));
|
||||
assert(!(init !is init2));
|
||||
assert(!(zero !is zero2));
|
||||
assert( (zero !is nzero2));
|
||||
|
||||
// float !identity
|
||||
assert(!(nan.f !is nan2.f));
|
||||
assert( (nan.f is init2.f));
|
||||
assert(!(init.f !is init2.f));
|
||||
assert(!(zero.f !is zero2.f));
|
||||
assert( (zero.f !is nzero2.f));
|
||||
|
||||
// .init identity
|
||||
assert(W.init is W.init);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto rtF = test!float();
|
||||
enum ctF = test!float();
|
||||
auto rtD = test!double();
|
||||
enum ctD = test!double();
|
||||
auto rtR = test!real();
|
||||
enum ctR = test!real();
|
||||
|
||||
assert(float.nan !is -float.nan);
|
||||
assert(double.nan !is -double.nan);
|
||||
assert(real.nan !is -real.nan);
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
void test6545()
|
||||
{
|
||||
static int[] func()
|
||||
|
@ -8142,6 +8223,7 @@ int main()
|
|||
test155();
|
||||
test156();
|
||||
test658();
|
||||
test3632();
|
||||
test4258();
|
||||
test4539();
|
||||
test4963();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
c52e28b723ccfbe845a95e8e7b528e3cc0b9d790
|
||||
9ba9a6ae2b8f6811cb85107cb56701df04f36ac6
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/druntime repository.
|
||||
|
|
|
@ -18,15 +18,26 @@ alias I = long;
|
|||
alias U = ulong;
|
||||
enum Ubits = uint(U.sizeof * 8);
|
||||
|
||||
align(16) struct Cent
|
||||
version (X86_64) private enum Cent_alignment = 16;
|
||||
else private enum Cent_alignment = (size_t.sizeof * 2);
|
||||
|
||||
align(Cent_alignment) struct Cent
|
||||
{
|
||||
U lo; // low 64 bits
|
||||
U hi; // high 64 bits
|
||||
version (LittleEndian)
|
||||
{
|
||||
U lo; // low 64 bits
|
||||
U hi; // high 64 bits
|
||||
}
|
||||
else
|
||||
{
|
||||
U hi; // high 64 bits
|
||||
U lo; // low 64 bits
|
||||
}
|
||||
}
|
||||
|
||||
enum One = Cent(1);
|
||||
enum Zero = Cent();
|
||||
enum MinusOne = neg(One);
|
||||
enum Cent One = { lo:1 };
|
||||
enum Cent Zero = { lo:0 };
|
||||
enum Cent MinusOne = neg(One);
|
||||
|
||||
/*****************************
|
||||
* Test against 0
|
||||
|
@ -320,7 +331,8 @@ Cent ror(Cent c, uint n)
|
|||
pure
|
||||
Cent and(Cent c1, Cent c2)
|
||||
{
|
||||
return Cent(c1.lo & c2.lo, c1.hi & c2.hi);
|
||||
const Cent ret = { lo:c1.lo & c2.lo, hi:c1.hi & c2.hi };
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************
|
||||
|
@ -334,7 +346,8 @@ Cent and(Cent c1, Cent c2)
|
|||
pure
|
||||
Cent or(Cent c1, Cent c2)
|
||||
{
|
||||
return Cent(c1.lo | c2.lo, c1.hi | c2.hi);
|
||||
const Cent ret = { lo:c1.lo | c2.lo, hi:c1.hi | c2.hi };
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************
|
||||
|
@ -348,7 +361,8 @@ Cent or(Cent c1, Cent c2)
|
|||
pure
|
||||
Cent xor(Cent c1, Cent c2)
|
||||
{
|
||||
return Cent(c1.lo ^ c2.lo, c1.hi ^ c2.hi);
|
||||
const Cent ret = { lo:c1.lo ^ c2.lo, hi:c1.hi ^ c2.hi };
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************
|
||||
|
@ -363,7 +377,8 @@ pure
|
|||
Cent add(Cent c1, Cent c2)
|
||||
{
|
||||
U r = cast(U)(c1.lo + c2.lo);
|
||||
return Cent(r, cast(U)(c1.hi + c2.hi + (r < c1.lo)));
|
||||
const Cent ret = { lo:r, hi:cast(U)(c1.hi + c2.hi + (r < c1.lo)) };
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************
|
||||
|
@ -419,9 +434,9 @@ Cent mul(Cent c1, Cent c2)
|
|||
const c1h1 = c1.hi >> mulshift;
|
||||
r3 = c1h1 * c2l0 + (r3 & mulmask);
|
||||
|
||||
return Cent((r0 & mulmask) + (r1 & mulmask) * (mulmask + 1),
|
||||
(r2 & mulmask) + (r3 & mulmask) * (mulmask + 1));
|
||||
|
||||
const Cent ret = { lo:(r0 & mulmask) + (r1 & mulmask) * (mulmask + 1),
|
||||
hi:(r2 & mulmask) + (r3 & mulmask) * (mulmask + 1) };
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -523,8 +538,10 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus)
|
|||
if (c1.hi == 0 && c2.hi == 0)
|
||||
{
|
||||
// Single precision divide
|
||||
modulus = Cent(c1.lo % c2.lo);
|
||||
return Cent(c1.lo / c2.lo);
|
||||
const Cent rem = { lo:c1.lo % c2.lo };
|
||||
modulus = rem;
|
||||
const Cent ret = { lo:c1.lo / c2.lo };
|
||||
return ret;
|
||||
}
|
||||
if (c1.hi == 0)
|
||||
{
|
||||
|
@ -539,10 +556,11 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus)
|
|||
const q1 = (c1.hi < c2.lo) ? 0 : (c1.hi / c2.lo);
|
||||
if (q1)
|
||||
c1.hi = c1.hi % c2.lo;
|
||||
U rem;
|
||||
const q0 = udivmod128_64(c1, c2.lo, rem);
|
||||
modulus = Cent(rem);
|
||||
return Cent(q0, q1);
|
||||
Cent rem;
|
||||
const q0 = udivmod128_64(c1, c2.lo, rem.lo);
|
||||
modulus = rem;
|
||||
const Cent ret = { lo:q0, hi:q1 };
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Full cent precision division.
|
||||
|
@ -560,10 +578,10 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus)
|
|||
|
||||
// Get quotient from divide unsigned operation.
|
||||
U rem_ignored;
|
||||
const q1 = udivmod128_64(u1, v1, rem_ignored);
|
||||
const Cent q1 = { lo:udivmod128_64(u1, v1, rem_ignored) };
|
||||
|
||||
// Undo normalization and division of c1 by 2.
|
||||
Cent quotient = shr(shl(Cent(q1), shift), 63);
|
||||
Cent quotient = shr(shl(q1, shift), 63);
|
||||
|
||||
// Make quotient correct or too small by 1
|
||||
if (tst(quotient))
|
||||
|
@ -770,44 +788,44 @@ version (unittest)
|
|||
|
||||
unittest
|
||||
{
|
||||
const C0 = Zero;
|
||||
const C1 = One;
|
||||
const C2 = Cent(2);
|
||||
const C3 = Cent(3);
|
||||
const C5 = Cent(5);
|
||||
const C10 = Cent(10);
|
||||
const C20 = Cent(20);
|
||||
const C30 = Cent(30);
|
||||
const C100 = Cent(100);
|
||||
const Cent C0 = Zero;
|
||||
const Cent C1 = One;
|
||||
const Cent C2 = { lo:2 };
|
||||
const Cent C3 = { lo:3 };
|
||||
const Cent C5 = { lo:5 };
|
||||
const Cent C10 = { lo:10 };
|
||||
const Cent C20 = { lo:20 };
|
||||
const Cent C30 = { lo:30 };
|
||||
const Cent C100 = { lo:100 };
|
||||
|
||||
const Cm1 = neg(One);
|
||||
const Cm3 = neg(C3);
|
||||
const Cm10 = neg(C10);
|
||||
const Cent Cm1 = neg(One);
|
||||
const Cent Cm3 = neg(C3);
|
||||
const Cent Cm10 = neg(C10);
|
||||
|
||||
const C3_1 = Cent(1,3);
|
||||
const C3_2 = Cent(2,3);
|
||||
const C4_8 = Cent(8, 4);
|
||||
const C5_0 = Cent(0, 5);
|
||||
const C7_1 = Cent(1,7);
|
||||
const C7_9 = Cent(9,7);
|
||||
const C9_3 = Cent(3,9);
|
||||
const C10_0 = Cent(0,10);
|
||||
const C10_1 = Cent(1,10);
|
||||
const C10_3 = Cent(3,10);
|
||||
const C11_3 = Cent(3,11);
|
||||
const C20_0 = Cent(0,20);
|
||||
const C90_30 = Cent(30,90);
|
||||
const Cent C3_1 = { lo:1, hi:3 };
|
||||
const Cent C3_2 = { lo:2, hi:3 };
|
||||
const Cent C4_8 = { lo:8, hi:4 };
|
||||
const Cent C5_0 = { lo:0, hi:5 };
|
||||
const Cent C7_1 = { lo:1, hi:7 };
|
||||
const Cent C7_9 = { lo:9, hi:7 };
|
||||
const Cent C9_3 = { lo:3, hi:9 };
|
||||
const Cent C10_0 = { lo:0, hi:10 };
|
||||
const Cent C10_1 = { lo:1, hi:10 };
|
||||
const Cent C10_3 = { lo:3, hi:10 };
|
||||
const Cent C11_3 = { lo:3, hi:11 };
|
||||
const Cent C20_0 = { lo:0, hi:20 };
|
||||
const Cent C90_30 = { lo:30, hi:90 };
|
||||
|
||||
const Cm10_0 = inc(com(C10_0)); // Cent(0, -10);
|
||||
const Cm10_1 = inc(com(C10_1)); // Cent(-1, -11);
|
||||
const Cm10_3 = inc(com(C10_3)); // Cent(-3, -11);
|
||||
const Cm20_0 = inc(com(C20_0)); // Cent(0, -20);
|
||||
const Cent Cm10_0 = inc(com(C10_0)); // Cent(lo=0, hi=-10);
|
||||
const Cent Cm10_1 = inc(com(C10_1)); // Cent(lo=-1, hi=-11);
|
||||
const Cent Cm10_3 = inc(com(C10_3)); // Cent(lo=-3, hi=-11);
|
||||
const Cent Cm20_0 = inc(com(C20_0)); // Cent(lo=0, hi=-20);
|
||||
|
||||
enum Cs_3 = Cent(3, I.min);
|
||||
enum Cent Cs_3 = { lo:3, hi:I.min };
|
||||
|
||||
const Cbig_1 = Cent(0xa3ccac1832952398, 0xc3ac542864f652f8);
|
||||
const Cbig_2 = Cent(0x5267b85f8a42fc20, 0);
|
||||
const Cbig_3 = Cent(0xf0000000ffffffff, 0);
|
||||
const Cent Cbig_1 = { lo:0xa3ccac1832952398, hi:0xc3ac542864f652f8 };
|
||||
const Cent Cbig_2 = { lo:0x5267b85f8a42fc20, hi:0 };
|
||||
const Cent Cbig_3 = { lo:0xf0000000ffffffff, hi:0 };
|
||||
|
||||
/************************/
|
||||
|
||||
|
@ -893,12 +911,20 @@ unittest
|
|||
assert(div(mul(C90_30, C2), C2) == C90_30);
|
||||
assert(div(mul(C90_30, C2), C90_30) == C2);
|
||||
|
||||
assert(divmod(Cbig_1, Cbig_2, modulus) == Cent(0x4496aa309d4d4a2f, U.max));
|
||||
assert(modulus == Cent(0xd83203d0fdc799b8, U.max));
|
||||
assert(udivmod(Cbig_1, Cbig_2, modulus) == Cent(0x5fe0e9bace2bedad, 2));
|
||||
assert(modulus == Cent(0x2c923125a68721f8, 0));
|
||||
assert(div(Cbig_1, Cbig_3) == Cent(0xbfa6c02b5aff8b86, U.max));
|
||||
assert(udiv(Cbig_1, Cbig_3) == Cent(0xd0b7d13b48cb350f, 0));
|
||||
const Cent Cb1divb2 = { lo:0x4496aa309d4d4a2f, hi:U.max };
|
||||
const Cent Cb1modb2 = { lo:0xd83203d0fdc799b8, hi:U.max };
|
||||
assert(divmod(Cbig_1, Cbig_2, modulus) == Cb1divb2);
|
||||
assert(modulus == Cb1modb2);
|
||||
|
||||
const Cent Cb1udivb2 = { lo:0x5fe0e9bace2bedad, hi:2 };
|
||||
const Cent Cb1umodb2 = { lo:0x2c923125a68721f8, hi:0 };
|
||||
assert(udivmod(Cbig_1, Cbig_2, modulus) == Cb1udivb2);
|
||||
assert(modulus == Cb1umodb2);
|
||||
|
||||
const Cent Cb1divb3 = { lo:0xbfa6c02b5aff8b86, hi:U.max };
|
||||
const Cent Cb1udivb3 = { lo:0xd0b7d13b48cb350f, hi:0 };
|
||||
assert(div(Cbig_1, Cbig_3) == Cb1divb3);
|
||||
assert(udiv(Cbig_1, Cbig_3) == Cb1udivb3);
|
||||
|
||||
assert(mul(Cm10, C1) == Cm10);
|
||||
assert(mul(C1, Cm10) == Cm10);
|
||||
|
|
|
@ -1273,7 +1273,9 @@ void copyEmplace(S, T)(ref S source, ref T target) @system
|
|||
}
|
||||
else static if (__traits(hasCopyConstructor, T))
|
||||
{
|
||||
emplace(cast(Unqual!(T)*) &target); // blit T.init
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22766
|
||||
import core.internal.lifetime : emplaceInitializer;
|
||||
emplaceInitializer(*(cast(Unqual!T*)&target));
|
||||
static if (__traits(isNested, T))
|
||||
{
|
||||
// copy context pointer
|
||||
|
@ -1373,6 +1375,22 @@ void copyEmplace(S, T)(ref S source, ref T target) @system
|
|||
static assert(!__traits(compiles, copyEmplace(ss, t)));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22766
|
||||
@system pure nothrow @nogc unittest
|
||||
{
|
||||
static struct S
|
||||
{
|
||||
@disable this();
|
||||
this(int) @safe pure nothrow @nogc{}
|
||||
this(ref const(S) other) @safe pure nothrow @nogc {}
|
||||
}
|
||||
|
||||
S s1 = S(1);
|
||||
S s2 = void;
|
||||
copyEmplace(s1, s2);
|
||||
assert(s2 == S(1));
|
||||
}
|
||||
|
||||
version (DigitalMars) version (X86) version (Posix) version = DMD_X86_Posix;
|
||||
|
||||
// don't violate immutability for reference types
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
99e9c1b7741e0f4e6f2a8c14883c4828d092701d
|
||||
c0cc5e917db105301dd1199b4b3c854626526407
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/phobos repository.
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
/* updated from 1.2.1 to 1.2.3 by Thomas Kuehne */
|
||||
/* updated from 1.2.3 to 1.2.8 by Dmitry Atamanov */
|
||||
/* updated from 1.2.8 to 1.2.11 by Iain Buclaw */
|
||||
/* updated from 1.2.11 to 1.2.12 by Brian Callahan */
|
||||
|
||||
module etc.c.zlib;
|
||||
|
||||
import core.stdc.config;
|
||||
|
||||
/* zlib.h -- interface of the 'zlib' general purpose compression library
|
||||
version 1.2.11, January 15th, 2017
|
||||
version 1.2.12, March 11th, 2022
|
||||
|
||||
Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
|
||||
Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -42,8 +43,8 @@ nothrow:
|
|||
extern (C):
|
||||
|
||||
// Those are extern(D) as they should be mangled
|
||||
extern(D) immutable string ZLIB_VERSION = "1.2.11";
|
||||
extern(D) immutable ZLIB_VERNUM = 0x12b0;
|
||||
extern(D) immutable string ZLIB_VERSION = "1.2.12";
|
||||
extern(D) immutable ZLIB_VERNUM = 0x12c0;
|
||||
|
||||
/*
|
||||
The 'zlib' compression library provides in-memory compression and
|
||||
|
@ -566,8 +567,7 @@ int deflateInit2(z_streamp strm,
|
|||
}
|
||||
/*
|
||||
This is another version of deflateInit with more compression options. The
|
||||
fields next_in, zalloc, zfree and opaque must be initialized before by the
|
||||
caller.
|
||||
fields zalloc, zfree and opaque must be initialized before by the caller.
|
||||
|
||||
The method parameter is the compression method. It must be Z_DEFLATED in
|
||||
this version of the library.
|
||||
|
@ -586,7 +586,7 @@ int deflateInit2(z_streamp strm,
|
|||
with deflateInit2() with this initialization, or at least in that case use 9
|
||||
with inflateInit2().
|
||||
|
||||
windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
|
||||
windowBits can also be -8 .. -15 for raw deflate. In this case, -windowBits
|
||||
determines the window size. deflate() will then generate raw deflate data
|
||||
with no zlib header or trailer, and will not compute a check value.
|
||||
|
||||
|
@ -728,11 +728,12 @@ int deflateParams(z_streamp strm, int level, int strategy);
|
|||
used to switch between compression and straight copy of the input data, or
|
||||
to switch to a different kind of input data requiring a different strategy.
|
||||
If the compression approach (which is a function of the level) or the
|
||||
strategy is changed, and if any input has been consumed in a previous
|
||||
deflate() call, then the input available so far is compressed with the old
|
||||
level and strategy using deflate(strm, Z_BLOCK). There are three approaches
|
||||
for the compression levels 0, 1 .. 3, and 4 .. 9 respectively. The new level
|
||||
and strategy will take effect at the next call of deflate().
|
||||
strategy is changed, and if there have been any deflate() calls since the
|
||||
state was initialized or reset, then the input available so far is
|
||||
compressed with the old level and strategy using deflate(strm, Z_BLOCK).
|
||||
There are three approaches for the compression levels 0, 1 .. 3, and 4 .. 9
|
||||
respectively. The new level and strategy will take effect at the next call
|
||||
of deflate().
|
||||
|
||||
If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does
|
||||
not have enough output space to complete, then the parameter change will not
|
||||
|
@ -856,7 +857,7 @@ int inflateInit2(z_streamp strm, int windowBits)
|
|||
windowBits can also be zero to request that inflate use the window size in
|
||||
the zlib header of the compressed stream.
|
||||
|
||||
windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
|
||||
windowBits can also be -8 .. -15 for raw inflate. In this case, -windowBits
|
||||
determines the window size. inflate() will then process raw deflate data,
|
||||
not looking for a zlib or gzip header, not generating a check value, and not
|
||||
looking for any check values for comparison at the end of the stream. This
|
||||
|
@ -873,9 +874,11 @@ int inflateInit2(z_streamp strm, int windowBits)
|
|||
detection, or add 16 to decode only the gzip format (the zlib format will
|
||||
return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
|
||||
CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see
|
||||
below), inflate() will not automatically decode concatenated gzip streams.
|
||||
inflate() will return Z_STREAM_END at the end of the gzip stream. The state
|
||||
would need to be reset to continue decoding a subsequent gzip stream.
|
||||
below), inflate() will *not* automatically decode concatenated gzip members.
|
||||
inflate() will return Z_STREAM_END at the end of the gzip member. The state
|
||||
would need to be reset to continue decoding a subsequent gzip member. This
|
||||
*must* be done if there is more data after a gzip member, in order for the
|
||||
decompression to be compliant with the gzip standard (RFC 1952).
|
||||
|
||||
inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
|
||||
memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
|
||||
|
@ -1311,14 +1314,14 @@ alias z_size_t = size_t;
|
|||
|
||||
gzFile gzopen(const(char)* path, const(char)* mode);
|
||||
/*
|
||||
Opens a gzip (.gz) file for reading or writing. The mode parameter is as
|
||||
in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
|
||||
a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
|
||||
compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
|
||||
for fixed code compression as in "wb9F". (See the description of
|
||||
deflateInit2 for more information about the strategy parameter.) 'T' will
|
||||
request transparent writing or appending with no compression and not using
|
||||
the gzip format.
|
||||
Open the gzip (.gz) file at path for reading and decompressing, or
|
||||
compressing and writing. The mode parameter is as in fopen ("rb" or "wb")
|
||||
but can also include a compression level ("wb9") or a strategy: 'f' for
|
||||
filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h",
|
||||
'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression
|
||||
as in "wb9F". (See the description of deflateInit2 for more information
|
||||
about the strategy parameter.) 'T' will request transparent writing or
|
||||
appending with no compression and not using the gzip format.
|
||||
|
||||
"a" can be used instead of "w" to request that the gzip stream that will
|
||||
be written be appended to the file. "+" will result in an error, since
|
||||
|
@ -1348,9 +1351,9 @@ gzFile gzopen(const(char)* path, const(char)* mode);
|
|||
|
||||
gzFile gzdopen(int fd, const(char)* mode);
|
||||
/*
|
||||
gzdopen associates a gzFile with the file descriptor fd. File descriptors
|
||||
are obtained from calls like open, dup, creat, pipe or fileno (if the file
|
||||
has been previously opened with fopen). The mode parameter is as in gzopen.
|
||||
Associate a gzFile with the file descriptor fd. File descriptors are
|
||||
obtained from calls like open, dup, creat, pipe or fileno (if the file has
|
||||
been previously opened with fopen). The mode parameter is as in gzopen.
|
||||
|
||||
The next call of gzclose on the returned gzFile will also close the file
|
||||
descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
|
||||
|
@ -1371,13 +1374,13 @@ gzFile gzdopen(int fd, const(char)* mode);
|
|||
|
||||
int gzbuffer(gzFile file, uint size);
|
||||
/*
|
||||
Set the internal buffer size used by this library's functions. The
|
||||
default buffer size is 8192 bytes. This function must be called after
|
||||
gzopen() or gzdopen(), and before any other calls that read or write the
|
||||
file. The buffer memory allocation is always deferred to the first read or
|
||||
write. Three times that size in buffer space is allocated. A larger buffer
|
||||
size of, for example, 64K or 128K bytes will noticeably increase the speed
|
||||
of decompression (reading).
|
||||
Set the internal buffer size used by this library's functions for file to
|
||||
size. The default buffer size is 8192 bytes. This function must be called
|
||||
after gzopen() or gzdopen(), and before any other calls that read or write
|
||||
the file. The buffer memory allocation is always deferred to the first read
|
||||
or write. Three times that size in buffer space is allocated. A larger
|
||||
buffer size of, for example, 64K or 128K bytes will noticeably increase the
|
||||
speed of decompression (reading).
|
||||
|
||||
The new buffer size also affects the maximum length for gzprintf().
|
||||
|
||||
|
@ -1387,9 +1390,9 @@ int gzbuffer(gzFile file, uint size);
|
|||
|
||||
int gzsetparams(gzFile file, int level, int strategy);
|
||||
/*
|
||||
Dynamically update the compression level or strategy. See the description
|
||||
of deflateInit2 for the meaning of these parameters. Previously provided
|
||||
data is flushed before the parameter change.
|
||||
Dynamically update the compression level and strategy for file. See the
|
||||
description of deflateInit2 for the meaning of these parameters. Previously
|
||||
provided data is flushed before applying the parameter changes.
|
||||
|
||||
gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not
|
||||
opened for writing, Z_ERRNO if there is an error writing the flushed data,
|
||||
|
@ -1398,7 +1401,7 @@ int gzsetparams(gzFile file, int level, int strategy);
|
|||
|
||||
int gzread(gzFile file, void* buf, uint len);
|
||||
/*
|
||||
Reads the given number of uncompressed bytes from the compressed file. If
|
||||
Read and decompress up to len uncompressed bytes from file into buf. If
|
||||
the input file is not in gzip format, gzread copies the given number of
|
||||
bytes into the buffer directly from the file.
|
||||
|
||||
|
@ -1428,11 +1431,11 @@ int gzread(gzFile file, void* buf, uint len);
|
|||
|
||||
z_size_t gzfread(void* buf, z_size_t size, z_size_t nitems, gzFile file);
|
||||
/*
|
||||
Read up to nitems items of size size from file to buf, otherwise operating
|
||||
as gzread() does. This duplicates the interface of stdio's fread(), with
|
||||
size_t request and return types. If the library defines size_t, then
|
||||
z_size_t is identical to size_t. If not, then z_size_t is an unsigned
|
||||
integer type that can contain a pointer.
|
||||
Read and decompress up to nitems items of size size from file into buf,
|
||||
otherwise operating as gzread() does. This duplicates the interface of
|
||||
stdio's fread(), with size_t request and return types. If the library
|
||||
defines size_t, then z_size_t is identical to size_t. If not, then z_size_t
|
||||
is an unsigned integer type that can contain a pointer.
|
||||
|
||||
gzfread() returns the number of full items read of size size, or zero if
|
||||
the end of the file was reached and a full item could not be read, or if
|
||||
|
@ -1453,14 +1456,13 @@ z_size_t gzfread(void* buf, z_size_t size, z_size_t nitems, gzFile file);
|
|||
|
||||
int gzwrite(gzFile file, void* buf, uint len);
|
||||
/*
|
||||
Writes the given number of uncompressed bytes into the compressed file.
|
||||
gzwrite returns the number of uncompressed bytes written or 0 in case of
|
||||
error.
|
||||
Compress and write the len uncompressed bytes at buf to file. gzwrite
|
||||
returns the number of uncompressed bytes written or 0 in case of error.
|
||||
*/
|
||||
|
||||
z_size_t gzfwrite(void* buf, z_size_t size, z_size_t nitems, gzFile file);
|
||||
/*
|
||||
gzfwrite() writes nitems items of size size from buf to file, duplicating
|
||||
Compress and write nitems items of size size from buf to file, duplicating
|
||||
the interface of stdio's fwrite(), with size_t request and return types. If
|
||||
the library defines size_t, then z_size_t is identical to size_t. If not,
|
||||
then z_size_t is an unsigned integer type that can contain a pointer.
|
||||
|
@ -1473,22 +1475,22 @@ z_size_t gzfwrite(void* buf, z_size_t size, z_size_t nitems, gzFile file);
|
|||
|
||||
int gzprintf(gzFile file, const(char)* format, ...);
|
||||
/*
|
||||
Converts, formats, and writes the arguments to the compressed file under
|
||||
control of the format string, as in fprintf. gzprintf returns the number of
|
||||
Convert, format, compress, and write the arguments (...) to file under
|
||||
control of the string format, as in fprintf. gzprintf returns the number of
|
||||
uncompressed bytes actually written, or a negative zlib error code in case
|
||||
of error. The number of uncompressed bytes written is limited to 8191, or
|
||||
one less than the buffer size given to gzbuffer(). The caller should assure
|
||||
that this limit is not exceeded. If it is exceeded, then gzprintf() will
|
||||
return an error (0) with nothing written. In this case, there may also be a
|
||||
buffer overflow with unpredictable consequences, which is possible only if
|
||||
zlib was compiled with the insecure functions sprintf() or vsprintf()
|
||||
zlib was compiled with the insecure functions sprintf() or vsprintf(),
|
||||
because the secure snprintf() or vsnprintf() functions were not available.
|
||||
This can be determined using zlibCompileFlags().
|
||||
*/
|
||||
|
||||
int gzputs(gzFile file, const(char)* s);
|
||||
/*
|
||||
Writes the given null-terminated string to the compressed file, excluding
|
||||
Compress and write the given null-terminated string s to file, excluding
|
||||
the terminating null character.
|
||||
|
||||
gzputs returns the number of characters written, or -1 in case of error.
|
||||
|
@ -1496,11 +1498,12 @@ int gzputs(gzFile file, const(char)* s);
|
|||
|
||||
const(char)* gzgets(gzFile file, const(char)* buf, int len);
|
||||
/*
|
||||
Reads bytes from the compressed file until len-1 characters are read, or a
|
||||
newline character is read and transferred to buf, or an end-of-file
|
||||
condition is encountered. If any characters are read or if len == 1, the
|
||||
string is terminated with a null character. If no characters are read due
|
||||
to an end-of-file or len < 1, then the buffer is left untouched.
|
||||
Read and decompress bytes from file into buf, until len-1 characters are
|
||||
read, or until a newline character is read and transferred to buf, or an
|
||||
end-of-file condition is encountered. If any characters are read or if len
|
||||
is one, the string is terminated with a null character. If no characters
|
||||
are read due to an end-of-file or len is less than one, then the buffer is
|
||||
left untouched.
|
||||
|
||||
gzgets returns buf which is a null-terminated string, or it returns NULL
|
||||
for end-of-file or in case of error. If there was an error, the contents at
|
||||
|
@ -1509,13 +1512,13 @@ const(char)* gzgets(gzFile file, const(char)* buf, int len);
|
|||
|
||||
int gzputc(gzFile file, int c);
|
||||
/*
|
||||
Writes c, converted to an unsigned char, into the compressed file. gzputc
|
||||
Compress and write c, converted to an unsigned char, into file. gzputc
|
||||
returns the value that was written, or -1 in case of error.
|
||||
*/
|
||||
|
||||
int gzgetc(gzFile file);
|
||||
/*
|
||||
Reads one byte from the compressed file. gzgetc returns this byte or -1
|
||||
Read and decompress one byte from file. gzgetc returns this byte or -1
|
||||
in case of end of file or error. This is implemented as a macro for speed.
|
||||
As such, it does not do all of the checking the other functions do. I.e.
|
||||
it does not check to see if file is NULL, nor whether the structure file
|
||||
|
@ -1524,8 +1527,8 @@ int gzgetc(gzFile file);
|
|||
|
||||
int gzungetc(int c, gzFile file);
|
||||
/*
|
||||
Push one character back onto the stream to be read as the first character
|
||||
on the next read. At least one character of push-back is allowed.
|
||||
Push c back onto the stream for file to be read as the first character on
|
||||
the next read. At least one character of push-back is always allowed.
|
||||
gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
|
||||
fail if c is -1, and may fail if a character has been pushed but not read
|
||||
yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
|
||||
|
@ -1536,9 +1539,9 @@ int gzungetc(int c, gzFile file);
|
|||
|
||||
int gzflush(gzFile file, int flush);
|
||||
/*
|
||||
Flushes all pending output into the compressed file. The parameter flush
|
||||
is as in the deflate() function. The return value is the zlib error number
|
||||
(see function gzerror below). gzflush is only permitted when writing.
|
||||
Flush all pending output to file. The parameter flush is as in the
|
||||
deflate() function. The return value is the zlib error number (see function
|
||||
gzerror below). gzflush is only permitted when writing.
|
||||
|
||||
If the flush parameter is Z_FINISH, the remaining data is written and the
|
||||
gzip stream is completed in the output. If gzwrite() is called again, a new
|
||||
|
@ -1551,8 +1554,8 @@ int gzflush(gzFile file, int flush);
|
|||
|
||||
z_off_t gzseek(gzFile file, z_off_t offset, int whence);
|
||||
/*
|
||||
Sets the starting position for the next gzread or gzwrite on the given
|
||||
compressed file. The offset represents a number of bytes in the
|
||||
Set the starting position to offset relative to whence for the next gzread
|
||||
or gzwrite on file. The offset represents a number of bytes in the
|
||||
uncompressed data stream. The whence parameter is defined as in lseek(2);
|
||||
the value SEEK_END is not supported.
|
||||
|
||||
|
@ -1569,39 +1572,39 @@ z_off_t gzseek(gzFile file, z_off_t offset, int whence);
|
|||
|
||||
int gzrewind(gzFile file);
|
||||
/*
|
||||
Rewinds the given file. This function is supported only for reading.
|
||||
Rewind file. This function is supported only for reading.
|
||||
|
||||
gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
|
||||
gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET).
|
||||
*/
|
||||
|
||||
z_off_t gztell(gzFile file);
|
||||
/*
|
||||
Returns the starting position for the next gzread or gzwrite on the given
|
||||
compressed file. This position represents a number of bytes in the
|
||||
uncompressed data stream, and is zero when starting, even if appending or
|
||||
reading a gzip stream from the middle of a file using gzdopen().
|
||||
Return the starting position for the next gzread or gzwrite on file.
|
||||
This position represents a number of bytes in the uncompressed data stream,
|
||||
and is zero when starting, even if appending or reading a gzip stream from
|
||||
the middle of a file using gzdopen().
|
||||
|
||||
gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
|
||||
*/
|
||||
|
||||
z_off_t gzoffset(gzFile file);
|
||||
/*
|
||||
Returns the current offset in the file being read or written. This offset
|
||||
includes the count of bytes that precede the gzip stream, for example when
|
||||
appending or when using gzdopen() for reading. When reading, the offset
|
||||
does not include as yet unused buffered input. This information can be used
|
||||
for a progress indicator. On error, gzoffset() returns -1.
|
||||
Return the current compressed (actual) read or write offset of file. This
|
||||
offset includes the count of bytes that precede the gzip stream, for example
|
||||
when appending or when using gzdopen() for reading. When reading, the
|
||||
offset does not include as yet unused buffered input. This information can
|
||||
be used for a progress indicator. On error, gzoffset() returns -1.
|
||||
*/
|
||||
|
||||
int gzeof(gzFile file);
|
||||
/*
|
||||
Returns true (1) if the end-of-file indicator has been set while reading,
|
||||
false (0) otherwise. Note that the end-of-file indicator is set only if the
|
||||
read tried to go past the end of the input, but came up short. Therefore,
|
||||
just like feof(), gzeof() may return false even if there is no more data to
|
||||
read, in the event that the last read request was for the exact number of
|
||||
bytes remaining in the input file. This will happen if the input file size
|
||||
is an exact multiple of the buffer size.
|
||||
Return true (1) if the end-of-file indicator for file has been set while
|
||||
reading, false (0) otherwise. Note that the end-of-file indicator is set
|
||||
only if the read tried to go past the end of the input, but came up short.
|
||||
Therefore, just like feof(), gzeof() may return false even if there is no
|
||||
more data to read, in the event that the last read request was for the exact
|
||||
number of bytes remaining in the input file. This will happen if the input
|
||||
file size is an exact multiple of the buffer size.
|
||||
|
||||
If gzeof() returns true, then the read functions will return no more data,
|
||||
unless the end-of-file indicator is reset by gzclearerr() and the input file
|
||||
|
@ -1610,7 +1613,7 @@ int gzeof(gzFile file);
|
|||
|
||||
int gzdirect(gzFile file);
|
||||
/*
|
||||
Returns true (1) if file is being copied directly while reading, or false
|
||||
Return true (1) if file is being copied directly while reading, or false
|
||||
(0) if file is a gzip stream being decompressed.
|
||||
|
||||
If the input file is empty, gzdirect() will return true, since the input
|
||||
|
@ -1631,8 +1634,8 @@ int gzdirect(gzFile file);
|
|||
|
||||
int gzclose(gzFile file);
|
||||
/*
|
||||
Flushes all pending output if necessary, closes the compressed file and
|
||||
deallocates the (de)compression state. Note that once file is closed, you
|
||||
Flush all pending output for file, if necessary, close file and
|
||||
deallocate the (de)compression state. Note that once file is closed, you
|
||||
cannot call gzerror with file, since its structures have been deallocated.
|
||||
gzclose must not be called more than once on the same file, just as free
|
||||
must not be called more than once on the same allocation.
|
||||
|
@ -1656,10 +1659,10 @@ int gzclose_w(gzFile file);
|
|||
|
||||
const(char)* gzerror(gzFile file, int* errnum);
|
||||
/*
|
||||
Returns the error message for the last error which occurred on the given
|
||||
compressed file. errnum is set to zlib error number. If an error occurred
|
||||
in the file system and not in the compression library, errnum is set to
|
||||
Z_ERRNO and the application may consult errno to get the exact error code.
|
||||
Return the error message for the last error which occurred on file.
|
||||
errnum is set to zlib error number. If an error occurred in the file system
|
||||
and not in the compression library, errnum is set to Z_ERRNO and the
|
||||
application may consult errno to get the exact error code.
|
||||
|
||||
The application must not modify the returned string. Future calls to
|
||||
this function may invalidate the previously returned string. If file is
|
||||
|
@ -1672,7 +1675,7 @@ const(char)* gzerror(gzFile file, int* errnum);
|
|||
|
||||
void gzclearerr(gzFile file);
|
||||
/*
|
||||
Clears the error and end-of-file flags for file. This is analogous to the
|
||||
Clear the error and end-of-file flags for file. This is analogous to the
|
||||
clearerr() function in stdio. This is useful for continuing to read a gzip
|
||||
file that is being written concurrently.
|
||||
*/
|
||||
|
@ -1688,8 +1691,9 @@ void gzclearerr(gzFile file);
|
|||
uint adler32(uint adler, const(ubyte)* buf, uint len);
|
||||
/*
|
||||
Update a running Adler-32 checksum with the bytes buf[0 .. len-1] and
|
||||
return the updated checksum. If buf is Z_NULL, this function returns the
|
||||
required initial value for the checksum.
|
||||
return the updated checksum. An Adler-32 value is in the range of a 32-bit
|
||||
unsigned integer. If buf is Z_NULL, this function returns the required
|
||||
initial value for the checksum.
|
||||
|
||||
An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed
|
||||
much faster.
|
||||
|
@ -1722,9 +1726,10 @@ uint adler32_combine(uint adler1, uint adler2, z_off_t len2);
|
|||
uint crc32(uint crc, const(ubyte)* buf, uint len);
|
||||
/*
|
||||
Update a running CRC-32 with the bytes buf[0 .. len-1] and return the
|
||||
updated CRC-32. If buf is Z_NULL, this function returns the required
|
||||
initial value for the crc. Pre- and post-conditioning (one's complement) is
|
||||
performed within this function so it shouldn't be done by the application.
|
||||
updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer.
|
||||
If buf is Z_NULL, this function returns the required initial value for the
|
||||
crc. Pre- and post-conditioning (one's complement) is performed within this
|
||||
function so it shouldn't be done by the application.
|
||||
|
||||
Usage example:
|
||||
|
||||
|
@ -1736,7 +1741,7 @@ uint crc32(uint crc, const(ubyte)* buf, uint len);
|
|||
if (crc != original_crc) error();
|
||||
*/
|
||||
|
||||
uint crc32_z(uint adler, const(ubyte)* buf, z_size_t len);
|
||||
uint crc32_z(uint crc, const(ubyte)* buf, z_size_t len);
|
||||
/*
|
||||
Same as crc32(), but with a size_t length.
|
||||
*/
|
||||
|
@ -1751,6 +1756,18 @@ uint crc32_combine(uint crc1, uint crc2, z_off_t len2);
|
|||
len2.
|
||||
*/
|
||||
|
||||
uint crc32_combine_gen(z_off_t len2);
|
||||
/*
|
||||
Return the operator corresponding to length len2, to be used with
|
||||
crc32_combine_op().
|
||||
*/
|
||||
|
||||
uint crc32_combine_op(uint crc1, uint crc2, uint op);
|
||||
/*
|
||||
Give the same result as crc32_combine(), using op in place of len2. op is
|
||||
is generated from len2 by crc32_combine_gen(). This will be faster than
|
||||
crc32_combine() if the generated op is used more than once.
|
||||
*/
|
||||
|
||||
/* various hacks, don't look :) */
|
||||
|
||||
|
|
|
@ -841,7 +841,7 @@ if (isForwardRange!R && is(ElementType!R : dchar))
|
|||
switch (front)
|
||||
{
|
||||
case '*', '?', '+', '|', '{', '}':
|
||||
error("'*', '+', '?', '{', '}' not allowed in atom");
|
||||
return error("'*', '+', '?', '{', '}' not allowed in atom");
|
||||
case '.':
|
||||
if (re_flags & RegexOption.singleline)
|
||||
g.put(Bytecode(IR.Any, 0));
|
||||
|
|
Loading…
Add table
Reference in a new issue