d: Merge upstream dmd, druntime f8bae04558, phobos ba2ade9dec
D front-end changes: - Import dmd v2.108.1-beta-1. D runtime changes: - Import druntime v2.108.1-beta-1. Phobos changes: - Import phobos v2.108.1-beta-1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd f8bae04558. * dmd/VERSION: Bump version to v2.108.0-beta.1. * d-builtins.cc (build_frontend_type): Update for new front-end interface. * d-codegen.cc (build_assert_call): Likewise. * d-convert.cc (d_array_convert): Likewise. * decl.cc (get_vtable_decl): Likewise. * expr.cc (ExprVisitor::visit (EqualExp *)): Likewise. (ExprVisitor::visit (VarExp *)): Likewise. (ExprVisitor::visit (ArrayLiteralExp *)): Likewise. (ExprVisitor::visit (AssocArrayLiteralExp)): Likewise. * intrinsics.cc (build_shuffle_mask_type): Likewise. (maybe_warn_intrinsic_mismatch): Likewise. * runtime.cc (get_libcall_type): Likewise. * typeinfo.cc (TypeInfoVisitor::layout_string): Likewise. (TypeInfoVisitor::visit(TypeInfoTupleDeclaration *)): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 02d6d07a69. * src/MERGE: Merge upstream phobos a2ade9dec.
This commit is contained in:
parent
24975a9195
commit
bbfbaa792b
36 changed files with 717 additions and 618 deletions
|
@ -197,8 +197,8 @@ build_frontend_type (tree type)
|
|||
length = size_binop (PLUS_EXPR, size_one_node,
|
||||
convert (sizetype, length));
|
||||
|
||||
dtype =
|
||||
dmd::addMod (dtype->sarrayOf (TREE_INT_CST_LOW (length)), mod);
|
||||
dtype = dmd::sarrayOf (dtype, TREE_INT_CST_LOW (length));
|
||||
dtype = dmd::addMod (dtype, mod);
|
||||
builtin_converted_decls.safe_push (builtin_data (dtype, type));
|
||||
return dtype;
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ build_frontend_type (tree type)
|
|||
if (!dtype)
|
||||
break;
|
||||
|
||||
dtype = dmd::addMod (dtype->sarrayOf (nunits), mod);
|
||||
dtype = dmd::addMod (dmd::sarrayOf (dtype, nunits), mod);
|
||||
if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ()))
|
||||
break;
|
||||
|
||||
|
|
|
@ -1906,7 +1906,7 @@ build_assert_call (const Loc &loc, libcall_fn libcall, tree msg)
|
|||
tree str = build_string (len, filename);
|
||||
TREE_TYPE (str) = make_array_type (Type::tchar, len);
|
||||
|
||||
file = d_array_value (build_ctype (Type::tchar->arrayOf ()),
|
||||
file = d_array_value (build_ctype (dmd::arrayOf (Type::tchar)),
|
||||
size_int (len), build_address (str));
|
||||
}
|
||||
else
|
||||
|
|
|
@ -957,7 +957,7 @@ d_array_convert (Expression *exp)
|
|||
|
||||
if (tb->ty == TY::Tsarray)
|
||||
{
|
||||
Type *totype = tb->nextOf ()->arrayOf ();
|
||||
Type *totype = dmd::arrayOf (tb->nextOf ());
|
||||
return convert_expr (build_expr (exp), exp->type, totype);
|
||||
}
|
||||
|
||||
|
@ -986,7 +986,7 @@ d_array_convert (Type *etype, Expression *exp)
|
|||
expr = compound_expr (modify_expr (var, expr), var);
|
||||
}
|
||||
|
||||
return d_array_value (build_ctype (exp->type->arrayOf ()),
|
||||
return d_array_value (build_ctype (dmd::arrayOf (exp->type)),
|
||||
size_int (1), build_address (expr));
|
||||
}
|
||||
else
|
||||
|
|
|
@ -2211,7 +2211,7 @@ get_vtable_decl (ClassDeclaration *decl)
|
|||
tree ident = mangle_internal_decl (decl, "__vtbl", "Z");
|
||||
/* Note: Using a static array type for the VAR_DECL, the DECL_INITIAL value
|
||||
will have a different type. However the back-end seems to accept this. */
|
||||
tree type = build_ctype (Type::tvoidptr->sarrayOf (decl->vtbl.length));
|
||||
tree type = build_ctype (dmd::sarrayOf (Type::tvoidptr, decl->vtbl.length));
|
||||
|
||||
Dsymbol *vtblsym = decl->vtblSymbol ();
|
||||
vtblsym->csym = declare_extern_var (ident, type);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ceff48bf7db05503117f54fdc0cefcb89b711136
|
||||
f8bae0455851a1dfc8113d69323415f6de549e39
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -1 +1 @@
|
|||
v2.107.1-rc.1
|
||||
v2.108.0-beta.1
|
||||
|
|
|
@ -36,7 +36,7 @@ import dmd.root.utf;
|
|||
import dmd.sideeffect;
|
||||
import dmd.target;
|
||||
import dmd.tokens;
|
||||
import dmd.typesem : toDsymbol, equivalent;
|
||||
import dmd.typesem : toDsymbol, equivalent, sarrayOf;
|
||||
|
||||
private enum LOG = false;
|
||||
|
||||
|
|
|
@ -2155,7 +2155,7 @@ final class CParser(AST) : Parser!AST
|
|||
error("function identifier-list cannot end with `...`");
|
||||
ft.parameterList.varargs = AST.VarArg.KRvariadic; // but C11 allows extra arguments
|
||||
auto plLength = pl.length;
|
||||
if (symbols.length != plLength)
|
||||
if (symbols && symbols.length != plLength)
|
||||
error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
|
||||
|
||||
/* Transfer the types and storage classes from symbols[] to pl[]
|
||||
|
@ -2176,6 +2176,12 @@ final class CParser(AST) : Parser!AST
|
|||
|
||||
if (p.type || !(p.storageClass & STC.parameter))
|
||||
error("storage class and type are not allowed in identifier-list");
|
||||
if (!symbols)
|
||||
{
|
||||
// Error already given in cparseDeclaration
|
||||
p.type = AST.Type.terror;
|
||||
continue;
|
||||
}
|
||||
foreach (s; (*symbols)[]) // yes, quadratic
|
||||
{
|
||||
auto ad = s.isAttribDeclaration();
|
||||
|
|
|
@ -475,6 +475,18 @@ bool equivalent(Type src, Type t)
|
|||
return dmd.typesem.equivalent(src, t);
|
||||
}
|
||||
|
||||
Type sarrayOf(Type type, dinteger_t dim)
|
||||
{
|
||||
import dmd.typesem;
|
||||
return dmd.typesem.sarrayOf(type, dim);
|
||||
}
|
||||
|
||||
Type arrayOf(Type type)
|
||||
{
|
||||
import dmd.typesem;
|
||||
return dmd.typesem.arrayOf(type);
|
||||
}
|
||||
|
||||
Type constOf(Type type)
|
||||
{
|
||||
import dmd.typesem;
|
||||
|
@ -535,6 +547,30 @@ Type sharedWildConstOf(Type type)
|
|||
return dmd.typesem.sharedWildConstOf(type);
|
||||
}
|
||||
|
||||
Type substWildTo(Type type, uint mod)
|
||||
{
|
||||
import dmd.typesem;
|
||||
return dmd.typesem.substWildTo(type, mod);
|
||||
}
|
||||
|
||||
Type unqualify(Type type, uint m)
|
||||
{
|
||||
import dmd.typesem;
|
||||
return dmd.typesem.unqualify(type, m);
|
||||
}
|
||||
|
||||
Type toHeadMutable(const(Type) type)
|
||||
{
|
||||
import dmd.typesem;
|
||||
return dmd.typesem.toHeadMutable(type);
|
||||
}
|
||||
|
||||
Type aliasthisOf(Type type)
|
||||
{
|
||||
import dmd.typesem;
|
||||
return dmd.typesem.aliasthisOf(type);
|
||||
}
|
||||
|
||||
Type castMod(Type type, MOD mod)
|
||||
{
|
||||
import dmd.typesem;
|
||||
|
|
|
@ -20,7 +20,6 @@ import dmd.astenums;
|
|||
import dmd.attrib;
|
||||
import dmd.gluelayer;
|
||||
import dmd.declaration;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.expression;
|
||||
import dmd.id;
|
||||
|
|
|
@ -50,7 +50,7 @@ import dmd.rootobject;
|
|||
import dmd.root.utf;
|
||||
import dmd.statement;
|
||||
import dmd.tokens;
|
||||
import dmd.typesem : mutableOf, equivalent, pointerTo;
|
||||
import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf;
|
||||
import dmd.utils : arrayCastBigEndian;
|
||||
import dmd.visitor;
|
||||
|
||||
|
@ -3787,7 +3787,7 @@ public:
|
|||
if (v is v2 || !v.isOverlappedWith(v2))
|
||||
continue;
|
||||
auto e = (*sle.elements)[i];
|
||||
if (e.op != EXP.void_)
|
||||
if (e !is null && e.op != EXP.void_)
|
||||
(*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1394,6 +1394,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
{
|
||||
enum SourceEncoding { utf16, utf32}
|
||||
enum Endian { little, big}
|
||||
immutable loc = mod.getLoc();
|
||||
|
||||
/*
|
||||
* Convert a buffer from UTF32 to UTF8
|
||||
|
@ -1413,7 +1414,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
|
||||
if (buf.length & 3)
|
||||
{
|
||||
.error(mod.loc, "%s `%s` odd length of UTF-32 char source %llu",
|
||||
.error(loc, "%s `%s` odd length of UTF-32 char source %llu",
|
||||
mod.kind, mod.toPrettyChars, cast(ulong) buf.length);
|
||||
return null;
|
||||
}
|
||||
|
@ -1430,7 +1431,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
{
|
||||
if (u > 0x10FFFF)
|
||||
{
|
||||
.error(mod.loc, "%s `%s` UTF-32 value %08x greater than 0x10FFFF", mod.kind, mod.toPrettyChars, u);
|
||||
.error(loc, "%s `%s` UTF-32 value %08x greater than 0x10FFFF", mod.kind, mod.toPrettyChars, u);
|
||||
return null;
|
||||
}
|
||||
dbuf.writeUTF8(u);
|
||||
|
@ -1460,7 +1461,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
|
||||
if (buf.length & 1)
|
||||
{
|
||||
.error(mod.loc, "%s `%s` odd length of UTF-16 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length);
|
||||
.error(loc, "%s `%s` odd length of UTF-16 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1480,13 +1481,13 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
i++;
|
||||
if (i >= eBuf.length)
|
||||
{
|
||||
.error(mod.loc, "%s `%s` surrogate UTF-16 high value %04x at end of file", mod.kind, mod.toPrettyChars, u);
|
||||
.error(loc, "%s `%s` surrogate UTF-16 high value %04x at end of file", mod.kind, mod.toPrettyChars, u);
|
||||
return null;
|
||||
}
|
||||
const u2 = readNext(&eBuf[i]);
|
||||
if (u2 < 0xDC00 || 0xE000 <= u2)
|
||||
{
|
||||
.error(mod.loc, "%s `%s` surrogate UTF-16 low value %04x out of range", mod.kind, mod.toPrettyChars, u2);
|
||||
.error(loc, "%s `%s` surrogate UTF-16 low value %04x out of range", mod.kind, mod.toPrettyChars, u2);
|
||||
return null;
|
||||
}
|
||||
u = (u - 0xD7C0) << 10;
|
||||
|
@ -1494,12 +1495,12 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
}
|
||||
else if (u >= 0xDC00 && u <= 0xDFFF)
|
||||
{
|
||||
.error(mod.loc, "%s `%s` unpaired surrogate UTF-16 value %04x", mod.kind, mod.toPrettyChars, u);
|
||||
.error(loc, "%s `%s` unpaired surrogate UTF-16 value %04x", mod.kind, mod.toPrettyChars, u);
|
||||
return null;
|
||||
}
|
||||
else if (u == 0xFFFE || u == 0xFFFF)
|
||||
{
|
||||
.error(mod.loc, "%s `%s` illegal UTF-16 value %04x", mod.kind, mod.toPrettyChars, u);
|
||||
.error(loc, "%s `%s` illegal UTF-16 value %04x", mod.kind, mod.toPrettyChars, u);
|
||||
return null;
|
||||
}
|
||||
dbuf.writeUTF8(u);
|
||||
|
@ -1558,7 +1559,6 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
|
|||
// It's UTF-8
|
||||
if (buf[0] >= 0x80)
|
||||
{
|
||||
auto loc = mod.getLoc();
|
||||
.error(loc, "%s `%s` source file must start with BOM or ASCII character, not \\x%02X", mod.kind, mod.toPrettyChars, buf[0]);
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -12357,8 +12357,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
return result;
|
||||
}
|
||||
|
||||
void handleCatArgument(Expressions *arguments, Expression e)
|
||||
void handleCatArgument(Expressions *arguments, Expression e, Type catType, bool isRightArg)
|
||||
{
|
||||
auto tb = e.type.toBasetype();
|
||||
|
||||
if ((isRightArg && e.parens) || (!isRightArg && !tb.equals(catType)))
|
||||
{
|
||||
arguments.push(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto ce = e.isCatExp())
|
||||
{
|
||||
Expression lowering = ce.lowering;
|
||||
|
@ -12388,8 +12396,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
arguments.push(new StringExp(exp.loc, funcname.toDString()));
|
||||
}
|
||||
|
||||
handleCatArgument(arguments, exp.e1);
|
||||
handleCatArgument(arguments, exp.e2);
|
||||
handleCatArgument(arguments, exp.e1, exp.type.toBasetype(), false);
|
||||
handleCatArgument(arguments, exp.e2, exp.type.toBasetype(), true);
|
||||
|
||||
Expression id = new IdentifierExp(exp.loc, Id.empty);
|
||||
id = new DotIdExp(exp.loc, id, Id.object);
|
||||
|
|
176
gcc/d/dmd/func.d
176
gcc/d/dmd/func.d
|
@ -34,12 +34,10 @@ import dmd.dmodule;
|
|||
import dmd.dscope;
|
||||
import dmd.dstruct;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
import dmd.errors;
|
||||
import dmd.escape;
|
||||
import dmd.expression;
|
||||
import dmd.funcsem;
|
||||
import dmd.globals;
|
||||
import dmd.hdrgen;
|
||||
import dmd.id;
|
||||
|
@ -57,7 +55,6 @@ import dmd.semantic2;
|
|||
import dmd.semantic3;
|
||||
import dmd.statement_rewrite_walker;
|
||||
import dmd.statement;
|
||||
import dmd.statementsem;
|
||||
import dmd.tokens;
|
||||
import dmd.typesem;
|
||||
import dmd.visitor;
|
||||
|
@ -115,90 +112,6 @@ enum BUILTIN : ubyte
|
|||
toPrecReal
|
||||
}
|
||||
|
||||
/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
|
||||
*/
|
||||
extern (C++) final class NrvoWalker : StatementRewriteWalker
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
public:
|
||||
FuncDeclaration fd;
|
||||
Scope* sc;
|
||||
|
||||
override void visit(ReturnStatement s)
|
||||
{
|
||||
// See if all returns are instead to be replaced with a goto returnLabel;
|
||||
if (fd.returnLabel)
|
||||
{
|
||||
/* Rewrite:
|
||||
* return exp;
|
||||
* as:
|
||||
* vresult = exp; goto Lresult;
|
||||
*/
|
||||
auto gs = new GotoStatement(s.loc, Id.returnLabel);
|
||||
gs.label = fd.returnLabel;
|
||||
|
||||
Statement s1 = gs;
|
||||
if (s.exp)
|
||||
s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
|
||||
|
||||
replaceCurrent(s1);
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(TryFinallyStatement s)
|
||||
{
|
||||
DtorExpStatement des;
|
||||
if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
|
||||
fd.nrvo_var == des.var)
|
||||
{
|
||||
if (!(global.params.useExceptions && ClassDeclaration.throwable))
|
||||
{
|
||||
/* Don't need to call destructor at all, since it is nrvo
|
||||
*/
|
||||
replaceCurrent(s._body);
|
||||
s._body.accept(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Normally local variable dtors are called regardless exceptions.
|
||||
* But for nrvo_var, its dtor should be called only when exception is thrown.
|
||||
*
|
||||
* Rewrite:
|
||||
* try { s.body; } finally { nrvo_var.edtor; }
|
||||
* // equivalent with:
|
||||
* // s.body; scope(exit) nrvo_var.edtor;
|
||||
* as:
|
||||
* try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
|
||||
* // equivalent with:
|
||||
* // s.body; scope(failure) nrvo_var.edtor;
|
||||
*/
|
||||
Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
|
||||
Identifier id = Identifier.generateId("__o");
|
||||
|
||||
Statement handler = new PeelStatement(sexception);
|
||||
if (sexception.blockExit(fd, null) & BE.fallthru)
|
||||
{
|
||||
auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
|
||||
ts.internalThrow = true;
|
||||
handler = new CompoundStatement(Loc.initial, handler, ts);
|
||||
}
|
||||
|
||||
auto catches = new Catches();
|
||||
auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
|
||||
ctch.internalCatch = true;
|
||||
ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
|
||||
catches.push(ctch);
|
||||
|
||||
Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
|
||||
fd.hasNoEH = false;
|
||||
replaceCurrent(s2);
|
||||
s2.accept(this);
|
||||
}
|
||||
else
|
||||
StatementRewriteWalker.visit(s);
|
||||
}
|
||||
}
|
||||
|
||||
private struct FUNCFLAG
|
||||
{
|
||||
bool purityInprocess; /// working on determining purity
|
||||
|
@ -2021,44 +1934,6 @@ extern (C++) class FuncDeclaration : Declaration
|
|||
return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Declare result variable lazily.
|
||||
*/
|
||||
extern (D) final void buildResultVar(Scope* sc, Type tret)
|
||||
{
|
||||
if (!vresult)
|
||||
{
|
||||
Loc loc = fensure ? fensure.loc : this.loc;
|
||||
|
||||
/* If inferRetType is true, tret may not be a correct return type yet.
|
||||
* So, in here it may be a temporary type for vresult, and after
|
||||
* fbody.dsymbolSemantic() running, vresult.type might be modified.
|
||||
*/
|
||||
vresult = new VarDeclaration(loc, tret, Id.result, null);
|
||||
vresult.storage_class |= STC.nodtor | STC.temp;
|
||||
if (!isVirtual())
|
||||
vresult.storage_class |= STC.const_;
|
||||
vresult.storage_class |= STC.result;
|
||||
|
||||
// set before the semantic() for checkNestedReference()
|
||||
vresult.parent = this;
|
||||
}
|
||||
|
||||
if (sc && vresult.semanticRun == PASS.initial)
|
||||
{
|
||||
TypeFunction tf = type.toTypeFunction();
|
||||
if (tf.isref)
|
||||
vresult.storage_class |= STC.ref_;
|
||||
vresult.type = tret;
|
||||
|
||||
vresult.dsymbolSemantic(sc);
|
||||
|
||||
if (!sc.insert(vresult))
|
||||
.error(loc, "%s `%s` out result %s is already defined", kind, toPrettyChars, vresult.toChars());
|
||||
assert(vresult.parent == this);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Merge into this function the 'in' contracts of all it overrides.
|
||||
* 'in's are OR'd together, i.e. only one of them needs to pass.
|
||||
|
@ -2680,57 +2555,6 @@ extern (C++) class FuncDeclaration : Declaration
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Generate Expression to call the invariant.
|
||||
* Input:
|
||||
* ad aggregate with the invariant
|
||||
* vthis variable with 'this'
|
||||
* Returns:
|
||||
* void expression that calls the invariant
|
||||
*/
|
||||
Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
|
||||
{
|
||||
Expression e = null;
|
||||
// Call invariant directly only if it exists
|
||||
FuncDeclaration inv = ad.inv;
|
||||
ClassDeclaration cd = ad.isClassDeclaration();
|
||||
|
||||
while (!inv && cd)
|
||||
{
|
||||
cd = cd.baseClass;
|
||||
if (!cd)
|
||||
break;
|
||||
inv = cd.inv;
|
||||
}
|
||||
if (inv)
|
||||
{
|
||||
version (all)
|
||||
{
|
||||
// Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
|
||||
// For the correct mangling,
|
||||
// run attribute inference on inv if needed.
|
||||
functionSemantic(inv);
|
||||
}
|
||||
|
||||
//e = new DsymbolExp(Loc.initial, inv);
|
||||
//e = new CallExp(Loc.initial, e);
|
||||
//e = e.semantic(sc2);
|
||||
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=13113
|
||||
* Currently virtual invariant calls completely
|
||||
* bypass attribute enforcement.
|
||||
* Change the behavior of pre-invariant call by following it.
|
||||
*/
|
||||
e = new ThisExp(Loc.initial);
|
||||
e.type = ad.type.addMod(vthis.type.mod);
|
||||
e = new DotVarExp(Loc.initial, e, inv, false);
|
||||
e.type = inv.type;
|
||||
e = new CallExp(Loc.initial, e);
|
||||
e.type = Type.tvoid;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/***************************************************
|
||||
* Visit each overloaded function/template in turn, and call dg(s) on it.
|
||||
* Exit when no more, or dg(s) returns nonzero.
|
||||
|
|
|
@ -65,6 +65,90 @@ import dmd.tokens;
|
|||
import dmd.typesem;
|
||||
import dmd.visitor;
|
||||
|
||||
/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
|
||||
*/
|
||||
extern (C++) final class NrvoWalker : StatementRewriteWalker
|
||||
{
|
||||
alias visit = typeof(super).visit;
|
||||
public:
|
||||
FuncDeclaration fd;
|
||||
Scope* sc;
|
||||
|
||||
override void visit(ReturnStatement s)
|
||||
{
|
||||
// See if all returns are instead to be replaced with a goto returnLabel;
|
||||
if (fd.returnLabel)
|
||||
{
|
||||
/* Rewrite:
|
||||
* return exp;
|
||||
* as:
|
||||
* vresult = exp; goto Lresult;
|
||||
*/
|
||||
auto gs = new GotoStatement(s.loc, Id.returnLabel);
|
||||
gs.label = fd.returnLabel;
|
||||
|
||||
Statement s1 = gs;
|
||||
if (s.exp)
|
||||
s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
|
||||
|
||||
replaceCurrent(s1);
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(TryFinallyStatement s)
|
||||
{
|
||||
DtorExpStatement des;
|
||||
if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
|
||||
fd.nrvo_var == des.var)
|
||||
{
|
||||
if (!(global.params.useExceptions && ClassDeclaration.throwable))
|
||||
{
|
||||
/* Don't need to call destructor at all, since it is nrvo
|
||||
*/
|
||||
replaceCurrent(s._body);
|
||||
s._body.accept(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Normally local variable dtors are called regardless exceptions.
|
||||
* But for nrvo_var, its dtor should be called only when exception is thrown.
|
||||
*
|
||||
* Rewrite:
|
||||
* try { s.body; } finally { nrvo_var.edtor; }
|
||||
* // equivalent with:
|
||||
* // s.body; scope(exit) nrvo_var.edtor;
|
||||
* as:
|
||||
* try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
|
||||
* // equivalent with:
|
||||
* // s.body; scope(failure) nrvo_var.edtor;
|
||||
*/
|
||||
Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
|
||||
Identifier id = Identifier.generateId("__o");
|
||||
|
||||
Statement handler = new PeelStatement(sexception);
|
||||
if (sexception.blockExit(fd, null) & BE.fallthru)
|
||||
{
|
||||
auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
|
||||
ts.internalThrow = true;
|
||||
handler = new CompoundStatement(Loc.initial, handler, ts);
|
||||
}
|
||||
|
||||
auto catches = new Catches();
|
||||
auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
|
||||
ctch.internalCatch = true;
|
||||
ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
|
||||
catches.push(ctch);
|
||||
|
||||
Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
|
||||
fd.hasNoEH = false;
|
||||
replaceCurrent(s2);
|
||||
s2.accept(this);
|
||||
}
|
||||
else
|
||||
StatementRewriteWalker.visit(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Main semantic routine for functions.
|
||||
*/
|
||||
|
@ -1755,3 +1839,87 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
|
|||
if (constraintsTip)
|
||||
.tip(constraintsTip);
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Generate Expression to call the invariant.
|
||||
* Input:
|
||||
* ad aggregate with the invariant
|
||||
* vthis variable with 'this'
|
||||
* Returns:
|
||||
* void expression that calls the invariant
|
||||
*/
|
||||
Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
|
||||
{
|
||||
Expression e = null;
|
||||
// Call invariant directly only if it exists
|
||||
FuncDeclaration inv = ad.inv;
|
||||
ClassDeclaration cd = ad.isClassDeclaration();
|
||||
|
||||
while (!inv && cd)
|
||||
{
|
||||
cd = cd.baseClass;
|
||||
if (!cd)
|
||||
break;
|
||||
inv = cd.inv;
|
||||
}
|
||||
if (inv)
|
||||
{
|
||||
version (all)
|
||||
{
|
||||
// Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
|
||||
// For the correct mangling,
|
||||
// run attribute inference on inv if needed.
|
||||
functionSemantic(inv);
|
||||
}
|
||||
|
||||
//e = new DsymbolExp(Loc.initial, inv);
|
||||
//e = new CallExp(Loc.initial, e);
|
||||
//e = e.semantic(sc2);
|
||||
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=13113
|
||||
* Currently virtual invariant calls completely
|
||||
* bypass attribute enforcement.
|
||||
* Change the behavior of pre-invariant call by following it.
|
||||
*/
|
||||
e = new ThisExp(Loc.initial);
|
||||
e.type = ad.type.addMod(vthis.type.mod);
|
||||
e = new DotVarExp(Loc.initial, e, inv, false);
|
||||
e.type = inv.type;
|
||||
e = new CallExp(Loc.initial, e);
|
||||
e.type = Type.tvoid;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Declare result variable lazily.
|
||||
*/
|
||||
void buildResultVar(FuncDeclaration fd, Scope* sc, Type tret)
|
||||
{
|
||||
if (!fd.vresult)
|
||||
{
|
||||
Loc loc = fd.fensure ? fd.fensure.loc : fd.loc;
|
||||
/* If inferRetType is true, tret may not be a correct return type yet.
|
||||
* So, in here it may be a temporary type for vresult, and after
|
||||
* fbody.dsymbolSemantic() running, vresult.type might be modified.
|
||||
*/
|
||||
fd.vresult = new VarDeclaration(loc, tret, Id.result, null);
|
||||
fd.vresult.storage_class |= STC.nodtor | STC.temp;
|
||||
if (!fd.isVirtual())
|
||||
fd.vresult.storage_class |= STC.const_;
|
||||
fd.vresult.storage_class |= STC.result;
|
||||
// set before the semantic() for checkNestedReference()
|
||||
fd.vresult.parent = fd;
|
||||
}
|
||||
if (sc && fd.vresult.semanticRun == PASS.initial)
|
||||
{
|
||||
TypeFunction tf = fd.type.toTypeFunction();
|
||||
if (tf.isref)
|
||||
fd.vresult.storage_class |= STC.ref_;
|
||||
fd.vresult.type = tret;
|
||||
fd.vresult.dsymbolSemantic(sc);
|
||||
if (!sc.insert(fd.vresult))
|
||||
.error(fd.loc, "%s `%s` out result %s is already defined", fd.kind, fd.toPrettyChars, fd.vresult.toChars());
|
||||
assert(fd.vresult.parent == fd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,15 +115,7 @@ nothrow:
|
|||
//printf("setting %s\n", name);
|
||||
filenames.push(name);
|
||||
fileIndex = cast(uint)filenames.length;
|
||||
if (!fileIndex)
|
||||
{
|
||||
import dmd.globals : global;
|
||||
import dmd.errors : error, fatal;
|
||||
|
||||
global.gag = 0; // ensure error message gets printed
|
||||
error(Loc.initial, "internal compiler error: file name index overflow!");
|
||||
fatal();
|
||||
}
|
||||
assert(fileIndex, "internal compiler error: file name index overflow");
|
||||
}
|
||||
else
|
||||
fileIndex = 0;
|
||||
|
|
|
@ -1185,110 +1185,12 @@ extern (C++) abstract class Type : ASTNode
|
|||
return t;
|
||||
}
|
||||
|
||||
final Type arrayOf()
|
||||
{
|
||||
if (ty == Terror)
|
||||
return this;
|
||||
if (!arrayof)
|
||||
{
|
||||
Type t = new TypeDArray(this);
|
||||
arrayof = t.merge();
|
||||
}
|
||||
return arrayof;
|
||||
}
|
||||
|
||||
// Make corresponding static array type without semantic
|
||||
final Type sarrayOf(dinteger_t dim)
|
||||
{
|
||||
assert(deco);
|
||||
Type t = new TypeSArray(this, new IntegerExp(Loc.initial, dim, Type.tsize_t));
|
||||
// according to TypeSArray::semantic()
|
||||
t = t.addMod(mod);
|
||||
t = t.merge();
|
||||
return t;
|
||||
}
|
||||
|
||||
final bool hasDeprecatedAliasThis()
|
||||
{
|
||||
auto ad = isAggregate(this);
|
||||
return ad && ad.aliasthis && (ad.aliasthis.isDeprecated || ad.aliasthis.sym.isDeprecated);
|
||||
}
|
||||
|
||||
final Type aliasthisOf()
|
||||
{
|
||||
auto ad = isAggregate(this);
|
||||
if (!ad || !ad.aliasthis)
|
||||
return null;
|
||||
|
||||
auto s = ad.aliasthis.sym;
|
||||
if (s.isAliasDeclaration())
|
||||
s = s.toAlias();
|
||||
|
||||
if (s.isTupleDeclaration())
|
||||
return null;
|
||||
|
||||
if (auto vd = s.isVarDeclaration())
|
||||
{
|
||||
auto t = vd.type;
|
||||
if (vd.needThis())
|
||||
t = t.addMod(this.mod);
|
||||
return t;
|
||||
}
|
||||
Dsymbol callable = s.isFuncDeclaration();
|
||||
callable = callable ? callable : s.isTemplateDeclaration();
|
||||
if (callable)
|
||||
{
|
||||
auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet);
|
||||
if (!fd || fd.errors || !functionSemantic(fd))
|
||||
return Type.terror;
|
||||
|
||||
auto t = fd.type.nextOf();
|
||||
if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185
|
||||
return Type.terror;
|
||||
t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod);
|
||||
return t;
|
||||
}
|
||||
if (auto d = s.isDeclaration())
|
||||
{
|
||||
assert(d.type);
|
||||
return d.type;
|
||||
}
|
||||
if (auto ed = s.isEnumDeclaration())
|
||||
{
|
||||
return ed.type;
|
||||
}
|
||||
|
||||
//printf("%s\n", s.kind());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this type has endless `alias this` recursion.
|
||||
* Returns:
|
||||
* `true` if this type has an `alias this` that can be implicitly
|
||||
* converted back to this type itself.
|
||||
*/
|
||||
extern (D) final bool checkAliasThisRec()
|
||||
{
|
||||
Type tb = toBasetype();
|
||||
AliasThisRec* pflag;
|
||||
if (tb.ty == Tstruct)
|
||||
pflag = &(cast(TypeStruct)tb).att;
|
||||
else if (tb.ty == Tclass)
|
||||
pflag = &(cast(TypeClass)tb).att;
|
||||
else
|
||||
return false;
|
||||
|
||||
AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask);
|
||||
if (flag == AliasThisRec.fwdref)
|
||||
{
|
||||
Type att = aliasthisOf();
|
||||
flag = att && att.implicitConvTo(this) ? AliasThisRec.yes : AliasThisRec.no;
|
||||
}
|
||||
*pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask));
|
||||
return flag == AliasThisRec.yes;
|
||||
}
|
||||
|
||||
Type makeConst()
|
||||
{
|
||||
//printf("Type::makeConst() %p, %s\n", this, toChars());
|
||||
|
@ -1451,129 +1353,6 @@ extern (C++) abstract class Type : ASTNode
|
|||
return 0;
|
||||
}
|
||||
|
||||
Type substWildTo(uint mod)
|
||||
{
|
||||
//printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
|
||||
Type t;
|
||||
|
||||
if (Type tn = nextOf())
|
||||
{
|
||||
// substitution has no effect on function pointer type.
|
||||
if (ty == Tpointer && tn.ty == Tfunction)
|
||||
{
|
||||
t = this;
|
||||
goto L1;
|
||||
}
|
||||
|
||||
t = tn.substWildTo(mod);
|
||||
if (t == tn)
|
||||
t = this;
|
||||
else
|
||||
{
|
||||
if (ty == Tpointer)
|
||||
t = t.pointerTo();
|
||||
else if (ty == Tarray)
|
||||
t = t.arrayOf();
|
||||
else if (ty == Tsarray)
|
||||
t = new TypeSArray(t, (cast(TypeSArray)this).dim.syntaxCopy());
|
||||
else if (ty == Taarray)
|
||||
{
|
||||
t = new TypeAArray(t, (cast(TypeAArray)this).index.syntaxCopy());
|
||||
}
|
||||
else if (ty == Tdelegate)
|
||||
{
|
||||
t = new TypeDelegate(t.isTypeFunction());
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
t = t.merge();
|
||||
}
|
||||
}
|
||||
else
|
||||
t = this;
|
||||
|
||||
L1:
|
||||
if (isWild())
|
||||
{
|
||||
if (mod == MODFlags.immutable_)
|
||||
{
|
||||
t = t.immutableOf();
|
||||
}
|
||||
else if (mod == MODFlags.wildconst)
|
||||
{
|
||||
t = t.wildConstOf();
|
||||
}
|
||||
else if (mod == MODFlags.wild)
|
||||
{
|
||||
if (isWildConst())
|
||||
t = t.wildConstOf();
|
||||
else
|
||||
t = t.wildOf();
|
||||
}
|
||||
else if (mod == MODFlags.const_)
|
||||
{
|
||||
t = t.constOf();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isWildConst())
|
||||
t = t.constOf();
|
||||
else
|
||||
t = t.mutableOf();
|
||||
}
|
||||
}
|
||||
if (isConst())
|
||||
t = t.addMod(MODFlags.const_);
|
||||
if (isShared())
|
||||
t = t.addMod(MODFlags.shared_);
|
||||
|
||||
//printf("-Type::substWildTo t = %s\n", t.toChars());
|
||||
return t;
|
||||
}
|
||||
|
||||
final Type unqualify(uint m)
|
||||
{
|
||||
Type t = this.mutableOf().unSharedOf();
|
||||
|
||||
Type tn = ty == Tenum ? null : nextOf();
|
||||
if (tn && tn.ty != Tfunction)
|
||||
{
|
||||
Type utn = tn.unqualify(m);
|
||||
if (utn != tn)
|
||||
{
|
||||
if (ty == Tpointer)
|
||||
t = utn.pointerTo();
|
||||
else if (ty == Tarray)
|
||||
t = utn.arrayOf();
|
||||
else if (ty == Tsarray)
|
||||
t = new TypeSArray(utn, (cast(TypeSArray)this).dim);
|
||||
else if (ty == Taarray)
|
||||
{
|
||||
t = new TypeAArray(utn, (cast(TypeAArray)this).index);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
t = t.merge();
|
||||
}
|
||||
}
|
||||
t = t.addMod(mod & ~m);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**************************
|
||||
* Return type with the top level of it being mutable.
|
||||
*/
|
||||
inout(Type) toHeadMutable() inout
|
||||
{
|
||||
if (!mod)
|
||||
return this;
|
||||
Type unqualThis = cast(Type) this;
|
||||
// `mutableOf` needs a mutable `this` only for caching
|
||||
return cast(inout(Type)) unqualThis.mutableOf();
|
||||
}
|
||||
|
||||
inout(ClassDeclaration) isClassHandle() inout
|
||||
{
|
||||
return null;
|
||||
|
@ -3396,55 +3175,6 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
|
||||
}
|
||||
|
||||
override Type substWildTo(uint)
|
||||
{
|
||||
if (!iswild && !(mod & MODFlags.wild))
|
||||
return this;
|
||||
|
||||
// Substitude inout qualifier of function type to mutable or immutable
|
||||
// would break type system. Instead substitude inout to the most weak
|
||||
// qualifer - const.
|
||||
uint m = MODFlags.const_;
|
||||
|
||||
assert(next);
|
||||
Type tret = next.substWildTo(m);
|
||||
Parameters* params = parameterList.parameters;
|
||||
if (mod & MODFlags.wild)
|
||||
params = parameterList.parameters.copy();
|
||||
for (size_t i = 0; i < params.length; i++)
|
||||
{
|
||||
Parameter p = (*params)[i];
|
||||
Type t = p.type.substWildTo(m);
|
||||
if (t == p.type)
|
||||
continue;
|
||||
if (params == parameterList.parameters)
|
||||
params = parameterList.parameters.copy();
|
||||
(*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null);
|
||||
}
|
||||
if (next == tret && params == parameterList.parameters)
|
||||
return this;
|
||||
|
||||
// Similar to TypeFunction::syntaxCopy;
|
||||
auto t = new TypeFunction(ParameterList(params, parameterList.varargs), tret, linkage);
|
||||
t.mod = ((mod & MODFlags.wild) ? (mod & ~MODFlags.wild) | MODFlags.const_ : mod);
|
||||
t.isnothrow = isnothrow;
|
||||
t.isnogc = isnogc;
|
||||
t.purity = purity;
|
||||
t.isproperty = isproperty;
|
||||
t.isref = isref;
|
||||
t.isreturn = isreturn;
|
||||
t.isreturnscope = isreturnscope;
|
||||
t.isScopeQual = isScopeQual;
|
||||
t.isreturninferred = isreturninferred;
|
||||
t.isscopeinferred = isscopeinferred;
|
||||
t.isInOutParam = false;
|
||||
t.isInOutQual = false;
|
||||
t.trust = trust;
|
||||
t.fargs = fargs;
|
||||
t.isctor = isctor;
|
||||
return t.merge();
|
||||
}
|
||||
|
||||
extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args)
|
||||
{
|
||||
if (global.gag && !global.params.v.showGaggedErrors)
|
||||
|
@ -4316,7 +4046,7 @@ extern (C++) final class TypeStruct : Type
|
|||
MATCH m;
|
||||
if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing))
|
||||
{
|
||||
if (auto ato = aliasthisOf())
|
||||
if (auto ato = aliasthisOf(this))
|
||||
{
|
||||
att = cast(AliasThisRec)(att | AliasThisRec.tracing);
|
||||
m = ato.implicitConvTo(to);
|
||||
|
@ -4353,7 +4083,7 @@ extern (C++) final class TypeStruct : Type
|
|||
|
||||
if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing))
|
||||
{
|
||||
if (auto ato = aliasthisOf())
|
||||
if (auto ato = aliasthisOf(this))
|
||||
{
|
||||
att = cast(AliasThisRec)(att | AliasThisRec.tracing);
|
||||
wm = ato.deduceWild(t, isRef);
|
||||
|
@ -4364,11 +4094,6 @@ extern (C++) final class TypeStruct : Type
|
|||
return wm;
|
||||
}
|
||||
|
||||
override inout(Type) toHeadMutable() inout
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
|
@ -4595,7 +4320,7 @@ extern (C++) final class TypeClass : Type
|
|||
MATCH m;
|
||||
if (sym.aliasthis && !(att & AliasThisRec.tracing))
|
||||
{
|
||||
if (auto ato = aliasthisOf())
|
||||
if (auto ato = aliasthisOf(this))
|
||||
{
|
||||
att = cast(AliasThisRec)(att | AliasThisRec.tracing);
|
||||
m = ato.implicitConvTo(to);
|
||||
|
@ -4644,7 +4369,7 @@ extern (C++) final class TypeClass : Type
|
|||
|
||||
if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing))
|
||||
{
|
||||
if (auto ato = aliasthisOf())
|
||||
if (auto ato = aliasthisOf(this))
|
||||
{
|
||||
att = cast(AliasThisRec)(att | AliasThisRec.tracing);
|
||||
wm = ato.deduceWild(t, isRef);
|
||||
|
@ -4655,11 +4380,6 @@ extern (C++) final class TypeClass : Type
|
|||
return wm;
|
||||
}
|
||||
|
||||
override inout(Type) toHeadMutable() inout
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override bool isZeroInit(const ref Loc loc)
|
||||
{
|
||||
return true;
|
||||
|
@ -5852,36 +5572,3 @@ TypeIdentifier getException()
|
|||
tid.addIdent(Id.Exception);
|
||||
return tid;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Check and set 'att' if 't' is a recursive 'alias this' type
|
||||
*
|
||||
* The goal is to prevent endless loops when there is a cycle in the alias this chain.
|
||||
* Since there is no multiple `alias this`, the chain either ends in a leaf,
|
||||
* or it loops back on itself as some point.
|
||||
*
|
||||
* Example: S0 -> (S1 -> S2 -> S3 -> S1)
|
||||
*
|
||||
* `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
|
||||
* `S1` is a recursive alias this type, but since `att` is initialized to `null`,
|
||||
* this still returns `false`, but `att1` is set to `S1`.
|
||||
* A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
|
||||
* we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
|
||||
*
|
||||
* Params:
|
||||
* att = type reference used to detect recursion. Should be initialized to `null`.
|
||||
* t = type of 'alias this' rewrite to attempt
|
||||
*
|
||||
* Returns:
|
||||
* `false` if the rewrite is safe, `true` if it would loop back around
|
||||
*/
|
||||
bool isRecursiveAliasThis(ref Type att, Type t)
|
||||
{
|
||||
//printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
|
||||
auto tb = t.toBasetype();
|
||||
if (att && tb.equivalent(att))
|
||||
return true;
|
||||
else if (!att && tb.checkAliasThisRec())
|
||||
att = tb;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -257,7 +257,6 @@ public:
|
|||
Type *arrayOf();
|
||||
Type *sarrayOf(dinteger_t dim);
|
||||
bool hasDeprecatedAliasThis();
|
||||
Type *aliasthisOf();
|
||||
virtual Type *makeConst();
|
||||
virtual Type *makeImmutable();
|
||||
virtual Type *makeShared();
|
||||
|
@ -271,11 +270,7 @@ public:
|
|||
virtual MATCH implicitConvTo(Type *to);
|
||||
virtual MATCH constConv(Type *to);
|
||||
virtual unsigned char deduceWild(Type *t, bool isRef);
|
||||
virtual Type *substWildTo(unsigned mod);
|
||||
|
||||
Type *unqualify(unsigned m);
|
||||
|
||||
virtual Type *toHeadMutable();
|
||||
virtual ClassDeclaration *isClassHandle();
|
||||
virtual structalign_t alignment();
|
||||
virtual Expression *defaultInitLiteral(const Loc &loc);
|
||||
|
@ -580,7 +575,6 @@ public:
|
|||
bool hasLazyParameters();
|
||||
bool isDstyleVariadic() const;
|
||||
|
||||
Type *substWildTo(unsigned mod) override;
|
||||
MATCH constConv(Type *to) override;
|
||||
|
||||
bool isnothrow() const;
|
||||
|
@ -751,7 +745,6 @@ public:
|
|||
MATCH implicitConvTo(Type *to) override;
|
||||
MATCH constConv(Type *to) override;
|
||||
unsigned char deduceWild(Type *t, bool isRef) override;
|
||||
Type *toHeadMutable() override;
|
||||
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
};
|
||||
|
@ -804,7 +797,6 @@ public:
|
|||
MATCH implicitConvTo(Type *to) override;
|
||||
MATCH constConv(Type *to) override;
|
||||
unsigned char deduceWild(Type *t, bool isRef) override;
|
||||
Type *toHeadMutable() override;
|
||||
bool isZeroInit(const Loc &loc) override;
|
||||
bool isscope() override;
|
||||
bool isBoolean() override;
|
||||
|
@ -892,6 +884,8 @@ namespace dmd
|
|||
Type *pointerTo(Type *type);
|
||||
Type *referenceTo(Type *type);
|
||||
Type *merge2(Type *type);
|
||||
Type *sarrayOf(Type *type, dinteger_t dim);
|
||||
Type *arrayOf(Type *type);
|
||||
Type *constOf(Type *type);
|
||||
Type *immutableOf(Type *type);
|
||||
Type *mutableOf(Type *type);
|
||||
|
@ -902,7 +896,11 @@ namespace dmd
|
|||
Type *wildConstOf(Type *type);
|
||||
Type *sharedWildOf(Type *type);
|
||||
Type *sharedWildConstOf(Type *type);
|
||||
Type *unqualify(Type *type, unsigned m);
|
||||
Type *toHeadMutable(Type *type);
|
||||
Type *aliasthisOf(Type *type);
|
||||
Type *castMod(Type *type, MOD mod);
|
||||
Type *addMod(Type *type, MOD mod);
|
||||
Type *addStorageClass(Type *type, StorageClass stc);
|
||||
Type *substWildTo(Type *type, unsigned mod);
|
||||
}
|
||||
|
|
|
@ -1349,7 +1349,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
|
|||
if (b++ == global.recursionLimit)
|
||||
{
|
||||
error(e.loc, "infinite loop while optimizing expression");
|
||||
fatal();
|
||||
return ErrorExp.get();
|
||||
}
|
||||
|
||||
auto ex = ret;
|
||||
|
|
|
@ -26,7 +26,7 @@ import dmd.identifier;
|
|||
import dmd.mtype;
|
||||
import dmd.target;
|
||||
import dmd.tokens;
|
||||
import dmd.typesem : hasPointers;
|
||||
import dmd.typesem : hasPointers, arrayOf;
|
||||
import dmd.func : setUnsafe, setUnsafePreview;
|
||||
|
||||
/*************************************************************
|
||||
|
|
|
@ -1687,7 +1687,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
|||
if (!ClassDeclaration.object)
|
||||
{
|
||||
.error(Loc.initial, "missing or corrupt object.d");
|
||||
fatal();
|
||||
return error();
|
||||
}
|
||||
|
||||
__gshared FuncDeclaration feq = null;
|
||||
|
@ -6229,6 +6229,29 @@ Type referenceTo(Type type)
|
|||
return type.rto;
|
||||
}
|
||||
|
||||
// Make corresponding static array type without semantic
|
||||
Type sarrayOf(Type type, dinteger_t dim)
|
||||
{
|
||||
assert(type.deco);
|
||||
Type t = new TypeSArray(type, new IntegerExp(Loc.initial, dim, Type.tsize_t));
|
||||
// according to TypeSArray.semantic()
|
||||
t = t.addMod(type.mod);
|
||||
t = t.merge();
|
||||
return t;
|
||||
}
|
||||
|
||||
Type arrayOf(Type type)
|
||||
{
|
||||
if (type.ty == Terror)
|
||||
return type;
|
||||
if (!type.arrayof)
|
||||
{
|
||||
Type t = new TypeDArray(type);
|
||||
type.arrayof = t.merge();
|
||||
}
|
||||
return type.arrayof;
|
||||
}
|
||||
|
||||
/********************************
|
||||
* Convert to 'const'.
|
||||
*/
|
||||
|
@ -6478,6 +6501,104 @@ Type sharedWildConstOf(Type type)
|
|||
return t;
|
||||
}
|
||||
|
||||
Type unqualify(Type type, uint m)
|
||||
{
|
||||
Type t = type.mutableOf().unSharedOf();
|
||||
|
||||
Type tn = type.ty == Tenum ? null : type.nextOf();
|
||||
if (tn && tn.ty != Tfunction)
|
||||
{
|
||||
Type utn = tn.unqualify(m);
|
||||
if (utn != tn)
|
||||
{
|
||||
if (type.ty == Tpointer)
|
||||
t = utn.pointerTo();
|
||||
else if (type.ty == Tarray)
|
||||
t = utn.arrayOf();
|
||||
else if (type.ty == Tsarray)
|
||||
t = new TypeSArray(utn, (cast(TypeSArray)type).dim);
|
||||
else if (type.ty == Taarray)
|
||||
{
|
||||
t = new TypeAArray(utn, (cast(TypeAArray)type).index);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
t = t.merge();
|
||||
}
|
||||
}
|
||||
t = t.addMod(type.mod & ~m);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**************************
|
||||
* Return type with the top level of it being mutable.
|
||||
*
|
||||
* Params:
|
||||
* t = type for which the top level mutable version is being returned
|
||||
*
|
||||
* Returns:
|
||||
* type version with mutable top level
|
||||
*/
|
||||
Type toHeadMutable(const Type t)
|
||||
{
|
||||
Type unqualType = cast(Type) t;
|
||||
if (t.isTypeStruct() || t.isTypeClass())
|
||||
return unqualType;
|
||||
|
||||
if (!t.mod)
|
||||
return unqualType;
|
||||
return unqualType.mutableOf();
|
||||
}
|
||||
|
||||
Type aliasthisOf(Type type)
|
||||
{
|
||||
auto ad = isAggregate(type);
|
||||
if (!ad || !ad.aliasthis)
|
||||
return null;
|
||||
|
||||
auto s = ad.aliasthis.sym;
|
||||
if (s.isAliasDeclaration())
|
||||
s = s.toAlias();
|
||||
|
||||
if (s.isTupleDeclaration())
|
||||
return null;
|
||||
|
||||
if (auto vd = s.isVarDeclaration())
|
||||
{
|
||||
auto t = vd.type;
|
||||
if (vd.needThis())
|
||||
t = t.addMod(type.mod);
|
||||
return t;
|
||||
}
|
||||
Dsymbol callable = s.isFuncDeclaration();
|
||||
callable = callable ? callable : s.isTemplateDeclaration();
|
||||
if (callable)
|
||||
{
|
||||
auto fd = resolveFuncCall(Loc.initial, null, callable, null, type, ArgumentList(), FuncResolveFlag.quiet);
|
||||
if (!fd || fd.errors || !functionSemantic(fd))
|
||||
return Type.terror;
|
||||
|
||||
auto t = fd.type.nextOf();
|
||||
if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185
|
||||
return Type.terror;
|
||||
t = t.substWildTo(type.mod == 0 ? MODFlags.mutable : type.mod);
|
||||
return t;
|
||||
}
|
||||
if (auto d = s.isDeclaration())
|
||||
{
|
||||
assert(d.type);
|
||||
return d.type;
|
||||
}
|
||||
if (auto ed = s.isEnumDeclaration())
|
||||
{
|
||||
return ed.type;
|
||||
}
|
||||
|
||||
//printf("%s\n", s.kind());
|
||||
return null;
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Apply MODxxxx bits to existing type.
|
||||
*/
|
||||
|
@ -6528,6 +6649,137 @@ Type castMod(Type type, MOD mod)
|
|||
return t;
|
||||
}
|
||||
|
||||
Type substWildTo(Type type, uint mod)
|
||||
{
|
||||
auto tf = type.isTypeFunction();
|
||||
if (!tf)
|
||||
{
|
||||
//printf("+Type.substWildTo this = %s, mod = x%x\n", toChars(), mod);
|
||||
Type t;
|
||||
|
||||
if (Type tn = type.nextOf())
|
||||
{
|
||||
// substitution has no effect on function pointer type.
|
||||
if (type.ty == Tpointer && tn.ty == Tfunction)
|
||||
{
|
||||
t = type;
|
||||
goto L1;
|
||||
}
|
||||
|
||||
t = tn.substWildTo(mod);
|
||||
if (t == tn)
|
||||
t = type;
|
||||
else
|
||||
{
|
||||
if (type.ty == Tpointer)
|
||||
t = t.pointerTo();
|
||||
else if (type.ty == Tarray)
|
||||
t = t.arrayOf();
|
||||
else if (type.ty == Tsarray)
|
||||
t = new TypeSArray(t, (cast(TypeSArray)type).dim.syntaxCopy());
|
||||
else if (type.ty == Taarray)
|
||||
{
|
||||
t = new TypeAArray(t, (cast(TypeAArray)type).index.syntaxCopy());
|
||||
}
|
||||
else if (type.ty == Tdelegate)
|
||||
{
|
||||
t = new TypeDelegate(t.isTypeFunction());
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
t = t.merge();
|
||||
}
|
||||
}
|
||||
else
|
||||
t = type;
|
||||
|
||||
L1:
|
||||
if (type.isWild())
|
||||
{
|
||||
if (mod == MODFlags.immutable_)
|
||||
{
|
||||
t = t.immutableOf();
|
||||
}
|
||||
else if (mod == MODFlags.wildconst)
|
||||
{
|
||||
t = t.wildConstOf();
|
||||
}
|
||||
else if (mod == MODFlags.wild)
|
||||
{
|
||||
if (type.isWildConst())
|
||||
t = t.wildConstOf();
|
||||
else
|
||||
t = t.wildOf();
|
||||
}
|
||||
else if (mod == MODFlags.const_)
|
||||
{
|
||||
t = t.constOf();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type.isWildConst())
|
||||
t = t.constOf();
|
||||
else
|
||||
t = t.mutableOf();
|
||||
}
|
||||
}
|
||||
if (type.isConst())
|
||||
t = t.addMod(MODFlags.const_);
|
||||
if (type.isShared())
|
||||
t = t.addMod(MODFlags.shared_);
|
||||
|
||||
//printf("-Type.substWildTo t = %s\n", t.toChars());
|
||||
return t;
|
||||
}
|
||||
|
||||
if (!tf.iswild && !(tf.mod & MODFlags.wild))
|
||||
return tf;
|
||||
|
||||
// Substitude inout qualifier of function type to mutable or immutable
|
||||
// would break type system. Instead substitude inout to the most weak
|
||||
// qualifer - const.
|
||||
uint m = MODFlags.const_;
|
||||
|
||||
assert(tf.next);
|
||||
Type tret = tf.next.substWildTo(m);
|
||||
Parameters* params = tf.parameterList.parameters;
|
||||
if (tf.mod & MODFlags.wild)
|
||||
params = tf.parameterList.parameters.copy();
|
||||
for (size_t i = 0; i < params.length; i++)
|
||||
{
|
||||
Parameter p = (*params)[i];
|
||||
Type t = p.type.substWildTo(m);
|
||||
if (t == p.type)
|
||||
continue;
|
||||
if (params == tf.parameterList.parameters)
|
||||
params = tf.parameterList.parameters.copy();
|
||||
(*params)[i] = new Parameter(p.loc, p.storageClass, t, null, null, null);
|
||||
}
|
||||
if (tf.next == tret && params == tf.parameterList.parameters)
|
||||
return tf;
|
||||
|
||||
// Similar to TypeFunction.syntaxCopy;
|
||||
auto t = new TypeFunction(ParameterList(params, tf.parameterList.varargs), tret, tf.linkage);
|
||||
t.mod = ((tf.mod & MODFlags.wild) ? (tf.mod & ~MODFlags.wild) | MODFlags.const_ : tf.mod);
|
||||
t.isnothrow = tf.isnothrow;
|
||||
t.isnogc = tf.isnogc;
|
||||
t.purity = tf.purity;
|
||||
t.isproperty = tf.isproperty;
|
||||
t.isref = tf.isref;
|
||||
t.isreturn = tf.isreturn;
|
||||
t.isreturnscope = tf.isreturnscope;
|
||||
t.isScopeQual = tf.isScopeQual;
|
||||
t.isreturninferred = tf.isreturninferred;
|
||||
t.isscopeinferred = tf.isscopeinferred;
|
||||
t.isInOutParam = false;
|
||||
t.isInOutQual = false;
|
||||
t.trust = tf.trust;
|
||||
t.fargs = tf.fargs;
|
||||
t.isctor = tf.isctor;
|
||||
return t.merge();
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Add MODxxxx bits to existing type.
|
||||
* We're adding, not replacing, so adding const to
|
||||
|
@ -6633,6 +6885,69 @@ Type addMod(Type type, MOD mod)
|
|||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this type has endless `alias this` recursion.
|
||||
*
|
||||
* Params:
|
||||
* t = type to check whether it has a recursive alias this
|
||||
* Returns:
|
||||
* `true` if `t` has an `alias this` that can be implicitly
|
||||
* converted back to `t` itself.
|
||||
*/
|
||||
private bool checkAliasThisRec(Type t)
|
||||
{
|
||||
Type tb = t.toBasetype();
|
||||
AliasThisRec* pflag;
|
||||
if (tb.ty == Tstruct)
|
||||
pflag = &(cast(TypeStruct)tb).att;
|
||||
else if (tb.ty == Tclass)
|
||||
pflag = &(cast(TypeClass)tb).att;
|
||||
else
|
||||
return false;
|
||||
|
||||
AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask);
|
||||
if (flag == AliasThisRec.fwdref)
|
||||
{
|
||||
Type att = aliasthisOf(t);
|
||||
flag = att && att.implicitConvTo(t) ? AliasThisRec.yes : AliasThisRec.no;
|
||||
}
|
||||
*pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask));
|
||||
return flag == AliasThisRec.yes;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Check and set 'att' if 't' is a recursive 'alias this' type
|
||||
*
|
||||
* The goal is to prevent endless loops when there is a cycle in the alias this chain.
|
||||
* Since there is no multiple `alias this`, the chain either ends in a leaf,
|
||||
* or it loops back on itself as some point.
|
||||
*
|
||||
* Example: S0 -> (S1 -> S2 -> S3 -> S1)
|
||||
*
|
||||
* `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
|
||||
* `S1` is a recursive alias this type, but since `att` is initialized to `null`,
|
||||
* this still returns `false`, but `att1` is set to `S1`.
|
||||
* A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
|
||||
* we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
|
||||
*
|
||||
* Params:
|
||||
* att = type reference used to detect recursion. Should be initialized to `null`.
|
||||
* t = type of 'alias this' rewrite to attempt
|
||||
*
|
||||
* Returns:
|
||||
* `false` if the rewrite is safe, `true` if it would loop back around
|
||||
*/
|
||||
bool isRecursiveAliasThis(ref Type att, Type t)
|
||||
{
|
||||
//printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
|
||||
auto tb = t.toBasetype();
|
||||
if (att && tb.equivalent(att))
|
||||
return true;
|
||||
else if (!att && tb.checkAliasThisRec())
|
||||
att = tb;
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************* Private *****************************************/
|
||||
|
||||
private:
|
||||
|
|
|
@ -464,7 +464,7 @@ public:
|
|||
else
|
||||
{
|
||||
/* Use _adEq2() to compare each element. */
|
||||
Type *t1array = t1elem->arrayOf ();
|
||||
Type *t1array = dmd::arrayOf (t1elem);
|
||||
tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3,
|
||||
d_array_convert (e->e1),
|
||||
d_array_convert (e->e2),
|
||||
|
@ -2172,7 +2172,8 @@ public:
|
|||
{
|
||||
/* Generate a slice for non-zero initialized aggregates,
|
||||
otherwise create an empty array. */
|
||||
gcc_assert (e->type == dmd::constOf (Type::tvoid->arrayOf ()));
|
||||
gcc_assert (e->type->isConst ()
|
||||
&& e->type->nextOf ()->ty == TY::Tvoid);
|
||||
|
||||
tree type = build_ctype (e->type);
|
||||
tree length = size_int (sd->dsym->structsize);
|
||||
|
@ -2571,7 +2572,7 @@ public:
|
|||
|
||||
/* Implicitly convert void[n] to ubyte[n]. */
|
||||
if (tb->ty == TY::Tsarray && tb->nextOf ()->toBasetype ()->ty == TY::Tvoid)
|
||||
tb = Type::tuns8->sarrayOf (tb->isTypeSArray ()->dim->toUInteger ());
|
||||
tb = dmd::sarrayOf (Type::tuns8, tb->isTypeSArray ()->dim->toUInteger ());
|
||||
|
||||
gcc_assert (tb->ty == TY::Tarray || tb->ty == TY::Tsarray
|
||||
|| tb->ty == TY::Tpointer);
|
||||
|
@ -2685,7 +2686,7 @@ public:
|
|||
/* Allocate space on the memory managed heap. */
|
||||
tree mem = build_libcall (LIBCALL_ARRAYLITERALTX,
|
||||
dmd::pointerTo (etype), 2,
|
||||
build_typeinfo (e, etype->arrayOf ()),
|
||||
build_typeinfo (e, dmd::arrayOf (etype)),
|
||||
size_int (e->elements->length));
|
||||
mem = d_save_expr (mem);
|
||||
|
||||
|
@ -2732,20 +2733,20 @@ public:
|
|||
|
||||
/* Build an expression that assigns all expressions in KEYS
|
||||
to a constructor. */
|
||||
tree akeys = build_array_from_exprs (ta->index->sarrayOf (e->keys->length),
|
||||
e->keys, this->constp_);
|
||||
Type *tkarray = dmd::sarrayOf (ta->index, e->keys->length);
|
||||
tree akeys = build_array_from_exprs (tkarray, e->keys, this->constp_);
|
||||
tree init = stabilize_expr (&akeys);
|
||||
|
||||
/* Do the same with all expressions in VALUES. */
|
||||
tree avals = build_array_from_exprs (ta->next->sarrayOf (e->values->length),
|
||||
e->values, this->constp_);
|
||||
Type *tvarray = dmd::sarrayOf (ta->next, e->values->length);
|
||||
tree avals = build_array_from_exprs (tvarray, e->values, this->constp_);
|
||||
init = compound_expr (init, stabilize_expr (&avals));
|
||||
|
||||
/* Generate: _d_assocarrayliteralTX (ti, keys, vals); */
|
||||
tree keys = d_array_value (build_ctype (ta->index->arrayOf ()),
|
||||
tree keys = d_array_value (build_ctype (dmd::arrayOf (ta->index)),
|
||||
size_int (e->keys->length),
|
||||
build_address (akeys));
|
||||
tree vals = d_array_value (build_ctype (ta->next->arrayOf ()),
|
||||
tree vals = d_array_value (build_ctype (dmd::arrayOf (ta->next)),
|
||||
size_int (e->values->length),
|
||||
build_address (avals));
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ build_shuffle_mask_type (tree type)
|
|||
gcc_assert (t != NULL);
|
||||
unsigned HOST_WIDE_INT nunits = TYPE_VECTOR_SUBPARTS (type).to_constant ();
|
||||
|
||||
return build_ctype (TypeVector::create (t->sarrayOf (nunits)));
|
||||
return build_ctype (TypeVector::create (dmd::sarrayOf (t, nunits)));
|
||||
}
|
||||
|
||||
/* Checks if call to intrinsic FUNCTION in CALLEXP matches the internal
|
||||
|
@ -414,7 +414,7 @@ maybe_warn_intrinsic_mismatch (tree function, tree callexp)
|
|||
break;
|
||||
|
||||
Type *inner = build_frontend_type (TREE_TYPE (vec0));
|
||||
Type *vector = TypeVector::create (inner->sarrayOf (nunits));
|
||||
Type *vector = TypeVector::create (dmd::sarrayOf (inner, nunits));
|
||||
return warn_mismatched_argument (callexp, 1,
|
||||
build_ctype (vector), true);
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ maybe_warn_intrinsic_mismatch (tree function, tree callexp)
|
|||
break;
|
||||
|
||||
Type *inner = build_frontend_type (TREE_TYPE (arg));
|
||||
Type *vector = TypeVector::create (inner->sarrayOf (nunits));
|
||||
Type *vector = TypeVector::create (dmd::sarrayOf (inner, nunits));
|
||||
return warn_mismatched_argument (callexp, 0,
|
||||
build_ctype (vector), true);
|
||||
}
|
||||
|
|
|
@ -158,31 +158,31 @@ get_libcall_type (d_libcall_type type)
|
|||
break;
|
||||
|
||||
case LCT_ARRAY_VOID:
|
||||
libcall_types[type] = Type::tvoid->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::tvoid);
|
||||
break;
|
||||
|
||||
case LCT_ARRAY_SIZE_T:
|
||||
libcall_types[type] = Type::tsize_t->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::tsize_t);
|
||||
break;
|
||||
|
||||
case LCT_ARRAY_BYTE:
|
||||
libcall_types[type] = Type::tint8->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::tint8);
|
||||
break;
|
||||
|
||||
case LCT_ARRAY_STRING:
|
||||
libcall_types[type] = Type::tstring->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::tstring);
|
||||
break;
|
||||
|
||||
case LCT_ARRAY_WSTRING:
|
||||
libcall_types[type] = Type::twstring->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::twstring);
|
||||
break;
|
||||
|
||||
case LCT_ARRAY_DSTRING:
|
||||
libcall_types[type] = Type::tdstring->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::tdstring);
|
||||
break;
|
||||
|
||||
case LCT_ARRAYARRAY_BYTE:
|
||||
libcall_types[type] = Type::tint8->arrayOf ()->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::tint8);
|
||||
break;
|
||||
|
||||
case LCT_POINTER_ASSOCARRAY:
|
||||
|
@ -190,15 +190,15 @@ get_libcall_type (d_libcall_type type)
|
|||
break;
|
||||
|
||||
case LCT_POINTER_VOIDPTR:
|
||||
libcall_types[type] = Type::tvoidptr->arrayOf ();
|
||||
libcall_types[type] = dmd::arrayOf (Type::tvoidptr);
|
||||
break;
|
||||
|
||||
case LCT_ARRAYPTR_VOID:
|
||||
libcall_types[type] = dmd::pointerTo (Type::tvoid->arrayOf ());
|
||||
libcall_types[type] = dmd::pointerTo (dmd::arrayOf (Type::tvoid));
|
||||
break;
|
||||
|
||||
case LCT_ARRAYPTR_BYTE:
|
||||
libcall_types[type] = dmd::pointerTo (Type::tint8->arrayOf ());
|
||||
libcall_types[type] = dmd::pointerTo (dmd::arrayOf (Type::tint8));
|
||||
break;
|
||||
|
||||
case LCT_IMMUTABLE_CHARPTR:
|
||||
|
|
|
@ -415,7 +415,7 @@ class TypeInfoVisitor : public Visitor
|
|||
tree decl = this->internal_reference (value);
|
||||
TREE_READONLY (decl) = 1;
|
||||
|
||||
value = d_array_value (build_ctype (Type::tchar->arrayOf ()),
|
||||
value = d_array_value (build_ctype (dmd::arrayOf (Type::tchar)),
|
||||
size_int (len), build_address (decl));
|
||||
this->layout_field (value);
|
||||
}
|
||||
|
@ -1137,7 +1137,7 @@ public:
|
|||
this->layout_base (Type::typeinfotypelist);
|
||||
|
||||
/* TypeInfo[] elements; */
|
||||
Type *satype = Type::tvoidptr->sarrayOf (ti->arguments->length);
|
||||
Type *satype = dmd::sarrayOf (Type::tvoidptr, ti->arguments->length);
|
||||
vec<constructor_elt, va_gc> *elms = NULL;
|
||||
for (size_t i = 0; i < ti->arguments->length; i++)
|
||||
{
|
||||
|
|
9
gcc/testsuite/gdc.test/compilable/issue24399.d
Normal file
9
gcc/testsuite/gdc.test/compilable/issue24399.d
Normal file
|
@ -0,0 +1,9 @@
|
|||
// REQUIRED_ARGS: -main
|
||||
// LINK:
|
||||
template rt_options()
|
||||
{
|
||||
__gshared string[] rt_options = [];
|
||||
string[] rt_options_tls = [];
|
||||
}
|
||||
|
||||
alias _ = rt_options!();
|
17
gcc/testsuite/gdc.test/compilable/issue24409.d
Normal file
17
gcc/testsuite/gdc.test/compilable/issue24409.d
Normal file
|
@ -0,0 +1,17 @@
|
|||
static struct S
|
||||
{
|
||||
union
|
||||
{
|
||||
int i;
|
||||
long l;
|
||||
}
|
||||
}
|
||||
|
||||
int f()
|
||||
{
|
||||
S* r = new S();
|
||||
r.i = 5;
|
||||
return r.i;
|
||||
}
|
||||
|
||||
enum X = f();
|
6
gcc/testsuite/gdc.test/runnable/issue24401.d
Normal file
6
gcc/testsuite/gdc.test/runnable/issue24401.d
Normal file
|
@ -0,0 +1,6 @@
|
|||
// PERMUTE_ARGS:
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24401
|
||||
int main()
|
||||
{
|
||||
return (() @trusted => 0)();
|
||||
}
|
15
gcc/testsuite/gdc.test/runnable/test24371.d
Normal file
15
gcc/testsuite/gdc.test/runnable/test24371.d
Normal file
|
@ -0,0 +1,15 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=24371
|
||||
|
||||
void main()
|
||||
{
|
||||
assert("b" ~ "c" == "bc");
|
||||
assert(["a"] ~ "b" == ["a", "b"]);
|
||||
assert(["a"] ~ ("b" ~ "c") == ["a", "bc"]);
|
||||
|
||||
auto strArr = ["a"];
|
||||
assert(strArr ~ ("b" ~ "c") == ["a", "bc"]);
|
||||
auto str = "c";
|
||||
assert(["a"] ~ ("b" ~ str) == ["a", "bc"]);
|
||||
|
||||
assert(strArr ~ ("b" ~ str) == ["a", "bc"]);
|
||||
}
|
|
@ -1,12 +1,5 @@
|
|||
// EXTRA_CPP_SOURCES: cpp7925.cpp
|
||||
|
||||
/*
|
||||
Exclude -O/-inline due to a codegen bug on OSX:
|
||||
https://issues.dlang.org/show_bug.cgi?id=22556
|
||||
|
||||
PERMUTE_ARGS(osx): -release -g
|
||||
*/
|
||||
|
||||
import core.vararg;
|
||||
|
||||
extern(C++) class C1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ceff48bf7db05503117f54fdc0cefcb89b711136
|
||||
f8bae0455851a1dfc8113d69323415f6de549e39
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -19,6 +19,19 @@ void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted
|
|||
assert(0, "No appropriate switch clause found");
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure template __switch_errorT is always instantiated when building
|
||||
* druntime. This works around https://issues.dlang.org/show_bug.cgi?id=20802.
|
||||
* When druntime and phobos are compiled with -release, the instance for
|
||||
* __switch_errorT is not needed. An application compiled with -release
|
||||
* could need the instance for __switch_errorT, but the compiler would
|
||||
* not generate code for it, because it assumes, that it was already
|
||||
* generated for druntime. Always including the instance in a compiled
|
||||
* druntime allows to use an application without -release with druntime
|
||||
* with -release.
|
||||
*/
|
||||
private alias dummy__switch_errorT = __switch_errorT!();
|
||||
|
||||
/**
|
||||
* Thrown on a range error.
|
||||
*/
|
||||
|
|
|
@ -39,11 +39,18 @@ struct ifaddrs
|
|||
union
|
||||
{
|
||||
/// Broadcast address of the interface
|
||||
sockaddr* ifu_broadaddr;
|
||||
sockaddr* ifa_broadaddr;
|
||||
|
||||
/// Point-to-point destination addresss
|
||||
sockaddr* if_dstaddr;
|
||||
sockaddr* ifa_dstaddr;
|
||||
}
|
||||
|
||||
deprecated("druntime declared this incorrectly before. The correct name is ifa_broadaddr.")
|
||||
alias ifu_broadaddr = ifa_broadaddr;
|
||||
|
||||
deprecated("druntime declared this incorrectly before. The correct name is ifa_dstaddr.")
|
||||
alias if_dstaddr = ifa_dstaddr;
|
||||
|
||||
/// Address specific data
|
||||
void* ifa_data;
|
||||
}
|
||||
|
|
|
@ -183,7 +183,8 @@ else version (FreeBSD)
|
|||
|
||||
struct fd_set
|
||||
{
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] fds_bits;
|
||||
deprecated("druntime incorrectly named fds_bits __fds_bits") alias __fds_bits = fds_bits;
|
||||
}
|
||||
|
||||
extern (D) __fd_mask __fdset_mask(uint n) pure
|
||||
|
@ -193,17 +194,17 @@ else version (FreeBSD)
|
|||
|
||||
extern (D) void FD_CLR( int n, fd_set* p ) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) bool FD_ISSET( int n, const(fd_set)* p ) pure
|
||||
{
|
||||
return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
return (p.fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
}
|
||||
|
||||
extern (D) void FD_SET( int n, fd_set* p ) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) void FD_ZERO( fd_set* p ) pure
|
||||
|
@ -214,7 +215,7 @@ else version (FreeBSD)
|
|||
_p = p;
|
||||
_n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
|
||||
while (_n > 0)
|
||||
_p.__fds_bits[--_n] = 0;
|
||||
_p.fds_bits[--_n] = 0;
|
||||
}
|
||||
|
||||
int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
|
||||
|
@ -232,7 +233,8 @@ else version (NetBSD)
|
|||
|
||||
struct fd_set
|
||||
{
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] fds_bits;
|
||||
deprecated("druntime incorrectly named fds_bits __fds_bits") alias __fds_bits = fds_bits;
|
||||
}
|
||||
|
||||
extern (D) __fd_mask __fdset_mask(uint n) pure
|
||||
|
@ -242,17 +244,17 @@ else version (NetBSD)
|
|||
|
||||
extern (D) void FD_CLR( int n, fd_set* p ) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) bool FD_ISSET( int n, const(fd_set)* p ) pure
|
||||
{
|
||||
return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
return (p.fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
}
|
||||
|
||||
extern (D) void FD_SET( int n, fd_set* p ) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) void FD_ZERO( fd_set* p ) pure
|
||||
|
@ -263,7 +265,7 @@ else version (NetBSD)
|
|||
_p = p;
|
||||
_n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
|
||||
while (_n > 0)
|
||||
_p.__fds_bits[--_n] = 0;
|
||||
_p.fds_bits[--_n] = 0;
|
||||
}
|
||||
|
||||
int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
|
||||
|
@ -281,7 +283,8 @@ else version (OpenBSD)
|
|||
|
||||
struct fd_set
|
||||
{
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] fds_bits;
|
||||
deprecated("druntime incorrectly named fds_bits __fds_bits") alias __fds_bits = fds_bits;
|
||||
}
|
||||
|
||||
extern (D) __fd_mask __fdset_mask(uint n) pure
|
||||
|
@ -291,17 +294,17 @@ else version (OpenBSD)
|
|||
|
||||
extern (D) void FD_CLR(int n, fd_set* p) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) bool FD_ISSET(int n, const(fd_set)* p) pure
|
||||
{
|
||||
return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
return (p.fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
}
|
||||
|
||||
extern (D) void FD_SET(int n, fd_set* p) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) void FD_ZERO(fd_set* p) pure
|
||||
|
@ -310,7 +313,7 @@ else version (OpenBSD)
|
|||
size_t _n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
|
||||
|
||||
while (_n > 0)
|
||||
_p.__fds_bits[--_n] = 0;
|
||||
_p.fds_bits[--_n] = 0;
|
||||
}
|
||||
|
||||
int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
|
||||
|
@ -328,7 +331,8 @@ else version (DragonFlyBSD)
|
|||
|
||||
struct fd_set
|
||||
{
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
|
||||
__fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] fds_bits;
|
||||
deprecated("druntime incorrectly named fds_bits __fds_bits") alias __fds_bits = fds_bits;
|
||||
}
|
||||
|
||||
extern (D) __fd_mask __fdset_mask(uint n) pure
|
||||
|
@ -338,17 +342,17 @@ else version (DragonFlyBSD)
|
|||
|
||||
extern (D) void FD_CLR( int n, fd_set* p ) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) bool FD_ISSET( int n, const(fd_set)* p ) pure
|
||||
{
|
||||
return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
return (p.fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
|
||||
}
|
||||
|
||||
extern (D) void FD_SET( int n, fd_set* p ) pure
|
||||
{
|
||||
p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
p.fds_bits[n / _NFDBITS] |= __fdset_mask(n);
|
||||
}
|
||||
|
||||
extern (D) void FD_ZERO( fd_set* p ) pure
|
||||
|
@ -359,7 +363,7 @@ else version (DragonFlyBSD)
|
|||
_p = p;
|
||||
_n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
|
||||
while (_n > 0)
|
||||
_p.__fds_bits[--_n] = 0;
|
||||
_p.fds_bits[--_n] = 0;
|
||||
}
|
||||
|
||||
int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
dcbfbd43ac321e81af60afd795bd0f3c3f47cfa0
|
||||
a2ade9dec49e70c6acd447df52321988a4c2fb9f
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/phobos repository.
|
||||
|
|
|
@ -9,9 +9,9 @@ module etc.c.zlib;
|
|||
import core.stdc.config;
|
||||
|
||||
/* zlib.h -- interface of the 'zlib' general purpose compression library
|
||||
version 1.2.12, March 11th, 2022
|
||||
version 1.3.1, January 22nd, 2024
|
||||
|
||||
Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
|
||||
Copyright (C) 1995-2024 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
|
||||
|
@ -43,8 +43,8 @@ nothrow:
|
|||
extern (C):
|
||||
|
||||
// Those are extern(D) as they should be mangled
|
||||
extern(D) immutable string ZLIB_VERSION = "1.2.12";
|
||||
extern(D) immutable ZLIB_VERNUM = 0x12c0;
|
||||
extern(D) immutable string ZLIB_VERSION = "1.3.1";
|
||||
extern(D) immutable ZLIB_VERNUM = 0x1310;
|
||||
|
||||
/*
|
||||
The 'zlib' compression library provides in-memory compression and
|
||||
|
@ -250,7 +250,7 @@ int deflateInit(z_streamp strm, int level)
|
|||
Initializes the internal stream state for compression. The fields
|
||||
zalloc, zfree and opaque must be initialized before by the caller. If
|
||||
zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
|
||||
allocation functions.
|
||||
allocation functions. total_in, total_out, adler, and msg are initialized.
|
||||
|
||||
The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
|
||||
1 gives best speed, 9 gives best compression, 0 gives no compression at all
|
||||
|
@ -296,7 +296,7 @@ int deflate(z_streamp strm, int flush);
|
|||
== 0), or after each call of deflate(). If deflate returns Z_OK and with
|
||||
zero avail_out, it must be called again after making room in the output
|
||||
buffer because there might be more output pending. See deflatePending(),
|
||||
which can be used if desired to determine whether or not there is more ouput
|
||||
which can be used if desired to determine whether or not there is more output
|
||||
in that case.
|
||||
|
||||
Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
|
||||
|
@ -340,8 +340,8 @@ int deflate(z_streamp strm, int flush);
|
|||
with the same value of the flush parameter and more output space (updated
|
||||
avail_out), until the flush is complete (deflate returns with non-zero
|
||||
avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
|
||||
avail_out is greater than six to avoid repeated flush markers due to
|
||||
avail_out == 0 on return.
|
||||
avail_out is greater than six when the flush marker begins, in order to avoid
|
||||
repeated flush markers upon calling deflate() again when avail_out == 0.
|
||||
|
||||
If the parameter flush is set to Z_FINISH, pending input is processed,
|
||||
pending output is flushed and deflate returns with Z_STREAM_END if there was
|
||||
|
@ -405,7 +405,8 @@ int inflateInit(z_streamp strm)
|
|||
read or consumed. The allocation of a sliding window will be deferred to
|
||||
the first call of inflate (if the decompression does not complete on the
|
||||
first call). If zalloc and zfree are set to Z_NULL, inflateInit updates
|
||||
them to use default allocation functions.
|
||||
them to use default allocation functions. total_in, total_out, adler, and
|
||||
msg are initialized.
|
||||
|
||||
inflateInit 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
|
||||
|
@ -680,7 +681,7 @@ int deflateGetDictionary(z_streamp strm, ubyte *dictionary, uint dictLength);
|
|||
to dictionary. dictionary must have enough space, where 32768 bytes is
|
||||
always enough. If deflateGetDictionary() is called with dictionary equal to
|
||||
Z_NULL, then only the dictionary length is returned, and nothing is copied.
|
||||
Similary, if dictLength is Z_NULL, then it is not set.
|
||||
Similarly, if dictLength is Z_NULL, then it is not set.
|
||||
|
||||
deflateGetDictionary() may return a length less than the window size, even
|
||||
when more than the window size in input has been provided. It may return up
|
||||
|
@ -715,7 +716,7 @@ int deflateReset(z_streamp strm);
|
|||
This function is equivalent to deflateEnd followed by deflateInit, but
|
||||
does not free and reallocate the internal compression state. The stream
|
||||
will leave the compression level and any other attributes that may have been
|
||||
set unchanged.
|
||||
set unchanged. total_in, total_out, adler, and msg are initialized.
|
||||
|
||||
deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
|
||||
stream state was inconsistent (such as zalloc or state being Z_NULL).
|
||||
|
@ -746,7 +747,7 @@ int deflateParams(z_streamp strm, int level, int strategy);
|
|||
Then no more input data should be provided before the deflateParams() call.
|
||||
If this is done, the old level and strategy will be applied to the data
|
||||
compressed before deflateParams(), and the new level and strategy will be
|
||||
applied to the the data compressed after deflateParams().
|
||||
applied to the data compressed after deflateParams().
|
||||
|
||||
deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream
|
||||
state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if
|
||||
|
@ -829,8 +830,9 @@ int deflateSetHeader(z_streamp strm, gz_headerp head);
|
|||
gzip file" and give up.
|
||||
|
||||
If deflateSetHeader is not used, the default gzip header has text false,
|
||||
the time set to zero, and os set to 255, with no extra, name, or comment
|
||||
fields. The gzip header is returned to the default state by deflateReset().
|
||||
the time set to zero, and os set to the current operating system, with no
|
||||
extra, name, or comment fields. The gzip header is returned to the default
|
||||
state by deflateReset().
|
||||
|
||||
deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
|
||||
stream state was inconsistent.
|
||||
|
@ -920,7 +922,7 @@ int inflateGetDictionary(z_streamp strm, ubyte* dictionary, uint* dictLength);
|
|||
to dictionary. dictionary must have enough space, where 32768 bytes is
|
||||
always enough. If inflateGetDictionary() is called with dictionary equal to
|
||||
Z_NULL, then only the dictionary length is returned, and nothing is copied.
|
||||
Similary, if dictLength is Z_NULL, then it is not set.
|
||||
Similarly, if dictLength is Z_NULL, then it is not set.
|
||||
|
||||
inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
|
||||
stream state is inconsistent.
|
||||
|
@ -939,10 +941,10 @@ int inflateSync(z_streamp strm);
|
|||
inflateSync returns Z_OK if a possible full flush point has been found,
|
||||
Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
|
||||
has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
|
||||
In the success case, the application may save the current current value of
|
||||
total_in which indicates where valid compressed data was found. In the
|
||||
error case, the application may repeatedly call inflateSync, providing more
|
||||
input each time, until success or end of the input data.
|
||||
In the success case, the application may save the current value of total_in
|
||||
which indicates where valid compressed data was found. In the error case,
|
||||
the application may repeatedly call inflateSync, providing more input each
|
||||
time, until success or end of the input data.
|
||||
*/
|
||||
|
||||
int inflateCopy(z_streamp dest, z_streamp source);
|
||||
|
@ -1446,12 +1448,12 @@ z_size_t gzfread(void* buf, z_size_t size, z_size_t nitems, gzFile file);
|
|||
|
||||
In the event that the end of file is reached and only a partial item is
|
||||
available at the end, i.e. the remaining uncompressed data length is not a
|
||||
multiple of size, then the final partial item is nevetheless read into buf
|
||||
multiple of size, then the final partial item is nevertheless read into buf
|
||||
and the end-of-file flag is set. The length of the partial item read is not
|
||||
provided, but could be inferred from the result of gztell(). This behavior
|
||||
is the same as the behavior of fread() implementations in common libraries,
|
||||
but it prevents the direct use of gzfread() to read a concurrently written
|
||||
file, reseting and retrying on end-of-file, when size is not 1.
|
||||
file, resetting and retrying on end-of-file, when size is not 1.
|
||||
*/
|
||||
|
||||
int gzwrite(gzFile file, void* buf, uint len);
|
||||
|
@ -1747,19 +1749,18 @@ uint crc32_z(uint crc, const(ubyte)* buf, z_size_t len);
|
|||
*/
|
||||
|
||||
uint crc32_combine(uint crc1, uint crc2, z_off_t len2);
|
||||
|
||||
/*
|
||||
Combine two CRC-32 check values into one. For two sequences of bytes,
|
||||
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
|
||||
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
|
||||
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
|
||||
len2.
|
||||
len2. len2 must be non-negative.
|
||||
*/
|
||||
|
||||
uint crc32_combine_gen(z_off_t len2);
|
||||
/*
|
||||
Return the operator corresponding to length len2, to be used with
|
||||
crc32_combine_op().
|
||||
crc32_combine_op(). len2 must be non-negative.
|
||||
*/
|
||||
|
||||
uint crc32_combine_op(uint crc1, uint crc2, uint op);
|
||||
|
|
Loading…
Add table
Reference in a new issue