d: Merge upstream dmd, druntime c57da0cf59, phobos ad8ee5587
D front-end changes: - Import latest fixes from dmd v2.110.0-beta.1. - The `align' attribute now allows to specify `default' explicitly. - Add primary expression of the form `__rvalue(expression)' which causes `expression' to be treated as an rvalue, even if it is an lvalue. - Shortened method syntax can now be used in constructors. D runtime changes: - Import latest fixes from druntime v2.110.0-beta.1. Phobos changes: - Import latest fixes from phobos v2.110.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd c57da0cf59. * d-codegen.cc (can_elide_copy_p): New. (d_build_call): Use it. * d-lang.cc (d_post_options): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime c57da0cf59. * src/MERGE: Merge upstream phobos ad8ee5587. * testsuite/libphobos.init_fini/custom_gc.d: Adjust test. gcc/testsuite/ChangeLog: * gdc.dg/copy1.d: New test.
This commit is contained in:
parent
a236f70617
commit
0dd21bce3a
124 changed files with 2872 additions and 1304 deletions
|
@ -631,6 +631,37 @@ force_target_expr (tree exp)
|
|||
return build_target_expr (decl, exp);
|
||||
}
|
||||
|
||||
/* Determine whether expression EXP can have a copy of its value elided. */
|
||||
|
||||
static bool
|
||||
can_elide_copy_p (Expression *exp)
|
||||
{
|
||||
/* Explicit `__rvalue(exp)'. */
|
||||
if (exp->rvalue)
|
||||
return true;
|
||||
|
||||
/* Look for variable expression. */
|
||||
Expression *last = exp;
|
||||
while (CommaExp *ce = last->isCommaExp ())
|
||||
last = ce->e2;
|
||||
|
||||
if (VarExp *ve = last->isVarExp ())
|
||||
{
|
||||
if (VarDeclaration *vd = ve->var->isVarDeclaration ())
|
||||
{
|
||||
/* Variable is an implicit copy of an lvalue. */
|
||||
if (vd->storage_class & STCrvalue)
|
||||
return true;
|
||||
|
||||
/* The destructor is going to run on the variable. */
|
||||
if (vd->isArgDtorVar ())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns the address of the expression EXP. */
|
||||
|
||||
tree
|
||||
|
@ -2280,8 +2311,10 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
|
|||
- The ABI of the function expects the callee to destroy its
|
||||
arguments; when the caller is handles destruction, then `targ'
|
||||
has already been made into a temporary. */
|
||||
if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor)
|
||||
|| target.isCalleeDestroyingArgs (tf))
|
||||
if (!can_elide_copy_p (arg)
|
||||
&& (arg->op == EXP::structLiteral
|
||||
|| (!sd->postblit && !sd->dtor)
|
||||
|| target.isCalleeDestroyingArgs (tf)))
|
||||
targ = force_target_expr (targ);
|
||||
|
||||
targ = convert (build_reference_type (TREE_TYPE (targ)),
|
||||
|
|
|
@ -925,7 +925,8 @@ d_post_options (const char ** fn)
|
|||
global.params.v.errorLimit = flag_max_errors;
|
||||
|
||||
global.params.v.showColumns = flag_show_column;
|
||||
global.params.v.printErrorContext = flag_diagnostics_show_caret;
|
||||
global.params.v.errorPrintMode = flag_diagnostics_show_caret
|
||||
? ErrorPrintMode::printErrorContext : ErrorPrintMode::simpleError;
|
||||
|
||||
/* Keep the front-end location type in sync with params. */
|
||||
Loc::set (global.params.v.showColumns, global.params.v.messageStyle);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
82a5d2a7c4dd3d270537bcede2981e047bfd0e6a
|
||||
c57da0cf5945cfb45eed06f1fd820435cda3ee3a
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -302,7 +302,7 @@ enum ThreeState : ubyte
|
|||
enum TRUST : ubyte
|
||||
{
|
||||
default_ = 0,
|
||||
system = 1, // @system (same as TRUST.default)
|
||||
system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled)
|
||||
trusted = 2, // @trusted
|
||||
safe = 3, // @safe
|
||||
}
|
||||
|
|
|
@ -104,16 +104,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
|
|||
return sc2;
|
||||
}
|
||||
|
||||
|
||||
override void addComment(const(char)* comment)
|
||||
{
|
||||
//printf("AttribDeclaration::addComment %s\n", comment);
|
||||
if (comment)
|
||||
{
|
||||
this.include(null).foreachDsymbol( s => s.addComment(comment) );
|
||||
}
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return "attribute";
|
||||
|
@ -653,20 +643,6 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
|
|||
}
|
||||
}
|
||||
|
||||
override final void addComment(const(char)* comment)
|
||||
{
|
||||
/* Because addComment is called by the parser, if we called
|
||||
* include() it would define a version before it was used.
|
||||
* But it's no problem to drill down to both decl and elsedecl,
|
||||
* so that's the workaround.
|
||||
*/
|
||||
if (comment)
|
||||
{
|
||||
decl .foreachDsymbol( s => s.addComment(comment) );
|
||||
elsedecl.foreachDsymbol( s => s.addComment(comment) );
|
||||
}
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
{
|
||||
v.visit(this);
|
||||
|
@ -762,12 +738,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
|
|||
return false;
|
||||
}
|
||||
|
||||
override void addComment(const(char)* comment)
|
||||
{
|
||||
// do nothing
|
||||
// change this to give semantics to documentation comments on static foreach declarations
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return "static foreach";
|
||||
|
|
|
@ -28,7 +28,6 @@ class AttribDeclaration : public Dsymbol
|
|||
{
|
||||
public:
|
||||
Dsymbols *decl; // array of Dsymbol's
|
||||
void addComment(const utf8_t *comment) override;
|
||||
const char *kind() const override;
|
||||
bool oneMember(Dsymbol *&ps, Identifier *ident) override;
|
||||
bool hasPointers() override final;
|
||||
|
@ -148,7 +147,6 @@ public:
|
|||
|
||||
ConditionalDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
bool oneMember(Dsymbol *&ps, Identifier *ident) override final;
|
||||
void addComment(const utf8_t *comment) override final;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -176,7 +174,6 @@ public:
|
|||
|
||||
StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override;
|
||||
bool oneMember(Dsymbol *&ps, Identifier *ident) override;
|
||||
void addComment(const utf8_t *comment) override;
|
||||
const char *kind() const override;
|
||||
void accept(Visitor *v) override { v->visit(this); }
|
||||
};
|
||||
|
|
|
@ -1610,13 +1610,15 @@ private Statement generateCopyCtorBody(StructDeclaration sd)
|
|||
* Params:
|
||||
* sd = the `struct` for which the copy constructor is generated
|
||||
* hasCpCtor = set to true if a copy constructor is already present
|
||||
* hasMoveCtor = set to true if a move constructor is already present
|
||||
*
|
||||
* Returns:
|
||||
* `true` if one needs to be generated
|
||||
* `false` otherwise
|
||||
*/
|
||||
bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
|
||||
bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor, out bool hasMoveCtor)
|
||||
{
|
||||
//printf("needCopyCtor() %s\n", sd.toChars());
|
||||
if (global.errors)
|
||||
return false;
|
||||
|
||||
|
@ -1648,14 +1650,17 @@ bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (isRvalueConstructor(sd, ctorDecl))
|
||||
if (ctorDecl.isMoveCtor)
|
||||
rvalueCtor = ctorDecl;
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (rvalueCtor)
|
||||
hasMoveCtor = true;
|
||||
|
||||
if (cpCtor)
|
||||
{
|
||||
if (rvalueCtor)
|
||||
if (0 && rvalueCtor)
|
||||
{
|
||||
.error(sd.loc, "`struct %s` may not define both a rvalue constructor and a copy constructor", sd.toChars());
|
||||
errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
|
||||
|
@ -1710,6 +1715,7 @@ LcheckFields:
|
|||
* Params:
|
||||
* sd = the `struct` for which the copy constructor is generated
|
||||
* sc = the scope where the copy constructor is generated
|
||||
* hasMoveCtor = set to true when a move constructor is also detected
|
||||
*
|
||||
* Returns:
|
||||
* `true` if `struct` sd defines a copy constructor (explicitly or generated),
|
||||
|
@ -1717,10 +1723,10 @@ LcheckFields:
|
|||
* References:
|
||||
* https://dlang.org/spec/struct.html#struct-copy-constructor
|
||||
*/
|
||||
bool buildCopyCtor(StructDeclaration sd, Scope* sc)
|
||||
bool buildCopyCtor(StructDeclaration sd, Scope* sc, out bool hasMoveCtor)
|
||||
{
|
||||
bool hasCpCtor;
|
||||
if (!needCopyCtor(sd, hasCpCtor))
|
||||
if (!needCopyCtor(sd, hasCpCtor, hasMoveCtor))
|
||||
return hasCpCtor;
|
||||
|
||||
//printf("generating copy constructor for %s\n", sd.toChars());
|
||||
|
|
|
@ -806,6 +806,7 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
|
|||
|
||||
UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
{
|
||||
//printf("Identity %s %s\n", e1.toChars(), e2.toChars());
|
||||
UnionExp ue = void;
|
||||
int cmp;
|
||||
if (e1.op == EXP.null_)
|
||||
|
@ -820,7 +821,17 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
|
|||
{
|
||||
SymOffExp es1 = e1.isSymOffExp();
|
||||
SymOffExp es2 = e2.isSymOffExp();
|
||||
cmp = (es1.var == es2.var && es1.offset == es2.offset);
|
||||
cmp = es1.offset == es2.offset;
|
||||
if (cmp)
|
||||
{
|
||||
cmp = es1.var == es2.var;
|
||||
if (!cmp && (es1.var.isParameter() || es2.var.isParameter()))
|
||||
{
|
||||
// because of ref's, they may still be the same, we cannot tell
|
||||
cantExp(ue);
|
||||
return ue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -30,6 +30,7 @@ import dmd.func;
|
|||
import dmd.funcsem : overloadApply, getLevelAndCheck;
|
||||
import dmd.globals;
|
||||
import dmd.gluelayer;
|
||||
import dmd.hdrgen;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
import dmd.init;
|
||||
|
@ -95,6 +96,7 @@ extern (C++) abstract class Declaration : Dsymbol
|
|||
enum ignoreRead = 2; // ignore any reads of AliasDeclaration
|
||||
enum nounderscore = 4; // don't prepend _ to mangled name
|
||||
enum hidden = 8; // don't print this in .di files
|
||||
enum nrvo = 0x10; /// forward to fd.nrvo_var when generating code
|
||||
|
||||
// overridden symbol with pragma(mangle, "...")
|
||||
const(char)[] mangleOverride;
|
||||
|
@ -441,8 +443,7 @@ extern (C++) final class AliasDeclaration : Declaration
|
|||
extern (D) this(const ref Loc loc, Identifier ident, Type type) @safe
|
||||
{
|
||||
super(loc, ident);
|
||||
//printf("AliasDeclaration(id = '%s', type = %p)\n", ident.toChars(), type);
|
||||
//printf("type = '%s'\n", type.toChars());
|
||||
//debug printf("AliasDeclaration(id = '%s', type = `%s`, %p)\n", ident.toChars(), dmd.hdrgen.toChars(type), type.isTypeIdentifier());
|
||||
this.type = type;
|
||||
assert(type);
|
||||
}
|
||||
|
@ -450,7 +451,7 @@ extern (C++) final class AliasDeclaration : Declaration
|
|||
extern (D) this(const ref Loc loc, Identifier ident, Dsymbol s) @safe
|
||||
{
|
||||
super(loc, ident);
|
||||
//printf("AliasDeclaration(id = '%s', s = %p)\n", ident.toChars(), s);
|
||||
//debug printf("AliasDeclaration(id = '%s', s = `%s`)\n", ident.toChars(), s.toChars());
|
||||
assert(s != this);
|
||||
this.aliassym = s;
|
||||
assert(s);
|
||||
|
@ -611,8 +612,9 @@ extern (C++) final class AliasDeclaration : Declaration
|
|||
|
||||
override Dsymbol toAlias()
|
||||
{
|
||||
//printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n",
|
||||
// loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym.kind() : "", inuse);
|
||||
static if (0)
|
||||
printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym: %s, kind: '%s', inuse = %d)\n",
|
||||
loc.toChars(), toChars(), this, aliassym ? aliassym.toChars() : "", aliassym ? aliassym.kind() : "", inuse);
|
||||
assert(this != aliassym);
|
||||
//static int count; if (++count == 10) *(char*)0=0;
|
||||
|
||||
|
|
|
@ -782,6 +782,7 @@ class CtorDeclaration final : public FuncDeclaration
|
|||
{
|
||||
public:
|
||||
d_bool isCpCtor;
|
||||
d_bool isMoveCtor;
|
||||
CtorDeclaration *syntaxCopy(Dsymbol *) override;
|
||||
const char *kind() const override;
|
||||
const char *toChars() const override;
|
||||
|
|
|
@ -24,6 +24,7 @@ import dmd.dclass;
|
|||
import dmd.declaration;
|
||||
import dmd.dmodule;
|
||||
import dmd.doc;
|
||||
import dmd.dstruct;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem;
|
||||
import dmd.dtemplate;
|
||||
|
@ -146,6 +147,7 @@ extern (C++) struct Scope
|
|||
|
||||
AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value,
|
||||
/// do not set wasRead for it
|
||||
StructDeclaration argStruct; /// elimiate recursion when looking for rvalue construction
|
||||
|
||||
extern (D) __gshared Scope* freelist;
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
|
|||
bool hasIdentityEquals; // true if has identity opEquals
|
||||
bool hasNoFields; // has no fields
|
||||
bool hasCopyCtor; // copy constructor
|
||||
bool hasMoveCtor; // move constructor
|
||||
bool hasPointerField; // members with indirections
|
||||
bool hasVoidInitPointers; // void-initialized unsafe fields
|
||||
bool hasUnsafeBitpatterns; // @system members, pointers, bool
|
||||
|
@ -171,11 +172,12 @@ extern (C++) class StructDeclaration : AggregateDeclaration
|
|||
{
|
||||
Dsymbol s = (*members)[i];
|
||||
s.setFieldOffset(this, &fieldState, isunion);
|
||||
}
|
||||
if (type.ty == Terror)
|
||||
{
|
||||
errors = true;
|
||||
return;
|
||||
if (type.ty == Terror)
|
||||
{
|
||||
errorSupplemental(s.loc, "error on member `%s`", s.toPrettyChars);
|
||||
errors = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (structsize == 0)
|
||||
|
@ -320,11 +322,16 @@ extern (C++) class StructDeclaration : AggregateDeclaration
|
|||
import dmd.clone;
|
||||
|
||||
bool hasCpCtorLocal;
|
||||
needCopyCtor(this, hasCpCtorLocal);
|
||||
bool hasMoveCtorLocal;
|
||||
needCopyCtor(this, hasCpCtorLocal, hasMoveCtorLocal);
|
||||
|
||||
if (enclosing || // is nested
|
||||
search(this, loc, Id.postblit) || // has postblit
|
||||
search(this, loc, Id.dtor) || // has destructor
|
||||
/* This is commented out because otherwise buildkite vibe.d:
|
||||
`canCAS!Task` fails to compile
|
||||
*/
|
||||
//hasMoveCtorLocal || // has move constructor
|
||||
hasCpCtorLocal) // has copy constructor
|
||||
{
|
||||
ispod = ThreeState.no;
|
||||
|
|
|
@ -925,22 +925,8 @@ extern (C++) class Dsymbol : ASTNode
|
|||
*/
|
||||
void addComment(const(char)* comment)
|
||||
{
|
||||
if (!comment || !*comment)
|
||||
return;
|
||||
|
||||
//printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
|
||||
void* h = cast(void*)this; // just the pointer is the key
|
||||
auto p = h in commentHashTable;
|
||||
if (!p)
|
||||
{
|
||||
commentHashTable[h] = comment;
|
||||
return;
|
||||
}
|
||||
if (strcmp(*p, comment) != 0)
|
||||
{
|
||||
// Concatenate the two
|
||||
*p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
|
||||
}
|
||||
import dmd.dsymbolsem;
|
||||
dmd.dsymbolsem.addComment(this, comment);
|
||||
}
|
||||
|
||||
/// get documentation comment for this Dsymbol
|
||||
|
@ -958,7 +944,7 @@ extern (C++) class Dsymbol : ASTNode
|
|||
/* Shell around addComment() to avoid disruption for the moment */
|
||||
final void comment(const(char)* comment) { addComment(comment); }
|
||||
|
||||
private extern (D) __gshared const(char)*[void*] commentHashTable;
|
||||
extern (D) __gshared const(char)*[void*] commentHashTable;
|
||||
|
||||
|
||||
/**********************************
|
||||
|
|
|
@ -433,4 +433,5 @@ namespace dmd
|
|||
Dsymbols *include(Dsymbol *d, Scope *sc);
|
||||
void setScope(Dsymbol *d, Scope *sc);
|
||||
void importAll(Dsymbol *d, Scope *sc);
|
||||
void addComment(Dsymbol *d, const char *comment);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import dmd.init;
|
|||
import dmd.initsem;
|
||||
import dmd.intrange;
|
||||
import dmd.hdrgen;
|
||||
import dmd.lexer;
|
||||
import dmd.location;
|
||||
import dmd.mtype;
|
||||
import dmd.mustuse;
|
||||
|
@ -64,6 +65,7 @@ import dmd.parse;
|
|||
debug import dmd.printast;
|
||||
import dmd.root.array;
|
||||
import dmd.root.filename;
|
||||
import dmd.root.string;
|
||||
import dmd.common.outbuffer;
|
||||
import dmd.root.rmem;
|
||||
import dmd.rootobject;
|
||||
|
@ -256,6 +258,10 @@ Return:
|
|||
*/
|
||||
bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, TemplateInstance ti)
|
||||
{
|
||||
//printf("checkHasBothRvalueAndCpCtor() sd: %s ctor: %s ti: %s\n", sd.toChars(), ctor.toChars(), ti.toChars());
|
||||
/* cannot use ctor.isMoveCtor because semantic pass may not have been run yet,
|
||||
* so use isRvalueConstructor()
|
||||
*/
|
||||
if (sd && sd.hasCopyCtor && isRvalueConstructor(sd, ctor))
|
||||
{
|
||||
.error(ctor.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars());
|
||||
|
@ -280,6 +286,7 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem
|
|||
*/
|
||||
bool isRvalueConstructor(StructDeclaration sd, CtorDeclaration ctor)
|
||||
{
|
||||
// note commonality with setting isMoveCtor in the semantic code for CtorDeclaration
|
||||
auto tf = ctor.type.isTypeFunction();
|
||||
const dim = tf.parameterList.length;
|
||||
if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
|
||||
|
@ -306,6 +313,7 @@ bool isRvalueConstructor(StructDeclaration sd, CtorDeclaration ctor)
|
|||
*/
|
||||
Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
|
||||
{
|
||||
//printf("resolveAliasThis() %s\n", toChars(e));
|
||||
import dmd.typesem : dotExp;
|
||||
for (AggregateDeclaration ad = isAggregate(e.type); ad;)
|
||||
{
|
||||
|
@ -2399,7 +2407,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
|
||||
override void visit(CtorDeclaration ctd)
|
||||
{
|
||||
//printf("CtorDeclaration::semantic() %s\n", toChars());
|
||||
//printf("CtorDeclaration::semantic() %p %s\n", ctd, ctd.toChars());
|
||||
if (ctd.semanticRun >= PASS.semanticdone)
|
||||
return;
|
||||
if (ctd._scope)
|
||||
|
@ -2432,6 +2440,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
sc.stc &= ~STC.static_; // not a static constructor
|
||||
|
||||
funcDeclarationSemantic(sc, ctd);
|
||||
// Check short constructor: this() => expr;
|
||||
if (ctd.fbody)
|
||||
{
|
||||
if (auto s = ctd.fbody.isExpStatement())
|
||||
{
|
||||
if (s.exp)
|
||||
{
|
||||
auto ce = s.exp.isCallExp();
|
||||
// check this/super before semantic
|
||||
if (!ce || (!ce.e1.isThisExp() && !ce.e1.isSuperExp()))
|
||||
{
|
||||
s.exp = s.exp.expressionSemantic(sc);
|
||||
if (s.exp.type.ty != Tvoid)
|
||||
error(s.loc, "can only return void expression, `this` call or `super` call from constructor");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sc.pop();
|
||||
|
||||
|
@ -2482,12 +2508,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
}
|
||||
else if ((dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)))
|
||||
{
|
||||
//printf("tf: %s\n", tf.toChars());
|
||||
//printf("tf: %s\n", toChars(tf));
|
||||
auto param = tf.parameterList[0];
|
||||
if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
|
||||
if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
|
||||
{
|
||||
//printf("copy constructor\n");
|
||||
ctd.isCpCtor = true;
|
||||
//printf("copy constructor %p\n", ctd);
|
||||
if (param.storageClass & STC.ref_)
|
||||
ctd.isCpCtor = true; // copy constructor
|
||||
else
|
||||
ctd.isMoveCtor = true; // move constructor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2978,7 +3007,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
|
||||
buildDtors(sd, sc2);
|
||||
|
||||
sd.hasCopyCtor = buildCopyCtor(sd, sc2);
|
||||
bool hasMoveCtor;
|
||||
sd.hasCopyCtor = buildCopyCtor(sd, sc2, hasMoveCtor);
|
||||
sd.hasMoveCtor = hasMoveCtor;
|
||||
|
||||
sd.postblit = buildPostBlit(sd, sc2);
|
||||
|
||||
buildOpAssign(sd, sc2);
|
||||
|
@ -5211,7 +5243,7 @@ void aliasInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclara
|
|||
// function used to perform semantic on AliasDeclaration
|
||||
void aliasSemantic(AliasDeclaration ds, Scope* sc)
|
||||
{
|
||||
//printf("AliasDeclaration::semantic() %s\n", ds.toChars());
|
||||
//printf("AliasDeclaration::semantic() %s %p\n", ds.toChars(), ds.aliassym);
|
||||
|
||||
// as DsymbolSemanticVisitor::visit(AliasDeclaration), in case we're called first.
|
||||
// see https://issues.dlang.org/show_bug.cgi?id=21001
|
||||
|
@ -7782,7 +7814,6 @@ private Expression callScopeDtor(VarDeclaration vd, Scope* sc)
|
|||
Expression ec;
|
||||
ec = new VarExp(vd.loc, vd);
|
||||
e = new DeleteExp(vd.loc, ec, true);
|
||||
e.type = Type.tvoid;
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
|
@ -7845,3 +7876,57 @@ Lfail:
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern (C++) void addComment(Dsymbol d, const(char)* comment)
|
||||
{
|
||||
scope v = new AddCommentVisitor(comment);
|
||||
d.accept(v);
|
||||
}
|
||||
|
||||
extern (C++) class AddCommentVisitor: Visitor
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
|
||||
const(char)* comment;
|
||||
|
||||
this(const(char)* comment)
|
||||
{
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
override void visit(Dsymbol d)
|
||||
{
|
||||
if (!comment || !*comment)
|
||||
return;
|
||||
|
||||
//printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
|
||||
void* h = cast(void*)d; // just the pointer is the key
|
||||
auto p = h in d.commentHashTable;
|
||||
if (!p)
|
||||
{
|
||||
d.commentHashTable[h] = comment;
|
||||
return;
|
||||
}
|
||||
if (strcmp(*p, comment) != 0)
|
||||
{
|
||||
// Concatenate the two
|
||||
*p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
|
||||
}
|
||||
}
|
||||
override void visit(AttribDeclaration atd)
|
||||
{
|
||||
if (comment)
|
||||
{
|
||||
atd.include(null).foreachDsymbol( s => s.addComment(comment) );
|
||||
}
|
||||
}
|
||||
override void visit(ConditionalDeclaration cd)
|
||||
{
|
||||
if (comment)
|
||||
{
|
||||
cd.decl .foreachDsymbol( s => s.addComment(comment) );
|
||||
cd.elsedecl.foreachDsymbol( s => s.addComment(comment) );
|
||||
}
|
||||
}
|
||||
override void visit(StaticForeachDeclaration sfd) {}
|
||||
}
|
||||
|
|
|
@ -293,10 +293,16 @@ enum WANTexpand = 1; // expand const/immutable variables if possible
|
|||
*/
|
||||
extern (C++) abstract class Expression : ASTNode
|
||||
{
|
||||
Type type; // !=null means that semantic() has been run
|
||||
/// Usually, this starts out as `null` and gets set to the final expression type by
|
||||
/// `expressionSemantic`. However, for some expressions (such as `TypeExp`,`RealExp`,
|
||||
/// `VarExp`), the field can get set to an assigned type before running semantic.
|
||||
/// See `expressionSemanticDone`
|
||||
Type type;
|
||||
|
||||
Loc loc; // file location
|
||||
const EXP op; // to minimize use of dynamic_cast
|
||||
bool parens; // if this is a parenthesized expression
|
||||
bool rvalue; // true if this is considered to be an rvalue, even if it is an lvalue
|
||||
|
||||
extern (D) this(const ref Loc loc, EXP op) scope @safe
|
||||
{
|
||||
|
@ -724,7 +730,7 @@ extern (C++) abstract class Expression : ASTNode
|
|||
inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
|
||||
inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
|
||||
inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
|
||||
inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
|
||||
inout(IsExp) isIsExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
|
||||
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; }
|
||||
|
@ -1307,7 +1313,7 @@ extern (C++) class IdentifierExp : Expression
|
|||
|
||||
override final bool isLvalue()
|
||||
{
|
||||
return true;
|
||||
return !this.rvalue;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -1351,7 +1357,7 @@ extern (C++) final class DsymbolExp : Expression
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
return true;
|
||||
return !rvalue;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -1397,7 +1403,7 @@ extern (C++) class ThisExp : Expression
|
|||
override final bool isLvalue()
|
||||
{
|
||||
// Class `this` should be an rvalue; struct `this` should be an lvalue.
|
||||
return type.toBasetype().ty != Tclass;
|
||||
return !rvalue && type.toBasetype().ty != Tclass;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -1782,7 +1788,7 @@ extern (C++) final class StringExp : Expression
|
|||
/* string literal is rvalue in default, but
|
||||
* conversion to reference of static array is only allowed.
|
||||
*/
|
||||
return (type && type.toBasetype().ty == Tsarray);
|
||||
return !rvalue && (type && type.toBasetype().ty == Tsarray);
|
||||
}
|
||||
|
||||
/********************************
|
||||
|
@ -2719,7 +2725,7 @@ extern (C++) final class VarExp : SymbolExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
|
||||
if (rvalue || var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -3098,7 +3104,7 @@ extern (C++) class BinAssignExp : BinExp
|
|||
|
||||
override final bool isLvalue()
|
||||
{
|
||||
return true;
|
||||
return !rvalue;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -3212,7 +3218,6 @@ extern (C++) final class ThrowExp : UnaExp
|
|||
extern (D) this(const ref Loc loc, Expression e)
|
||||
{
|
||||
super(loc, EXP.throw_, e);
|
||||
this.type = Type.tnoreturn;
|
||||
}
|
||||
|
||||
override ThrowExp syntaxCopy()
|
||||
|
@ -3303,6 +3308,8 @@ extern (C++) final class DotVarExp : UnaExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
if (rvalue)
|
||||
return false;
|
||||
if (e1.op != EXP.structLiteral)
|
||||
return true;
|
||||
auto vd = var.isVarDeclaration();
|
||||
|
@ -3530,6 +3537,8 @@ extern (C++) final class CallExp : UnaExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
if (rvalue)
|
||||
return false;
|
||||
Type tb = e1.type.toBasetype();
|
||||
if (tb.ty == Tdelegate || tb.ty == Tpointer)
|
||||
tb = tb.nextOf();
|
||||
|
@ -3648,7 +3657,7 @@ extern (C++) final class PtrExp : UnaExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
return true;
|
||||
return !rvalue;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -3777,7 +3786,7 @@ extern (C++) final class CastExp : UnaExp
|
|||
override bool isLvalue()
|
||||
{
|
||||
//printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
|
||||
if (!e1.isLvalue())
|
||||
if (rvalue || !e1.isLvalue())
|
||||
return false;
|
||||
return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
|
||||
e1.type.mutableOf.unSharedOf().equals(to.mutableOf().unSharedOf());
|
||||
|
@ -3834,7 +3843,7 @@ extern (C++) final class VectorArrayExp : UnaExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
return e1.isLvalue();
|
||||
return !rvalue && e1.isLvalue();
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -3891,7 +3900,7 @@ extern (C++) final class SliceExp : UnaExp
|
|||
/* slice expression is rvalue in default, but
|
||||
* conversion to reference of static array is only allowed.
|
||||
*/
|
||||
return (type && type.toBasetype().ty == Tsarray);
|
||||
return !rvalue && (type && type.toBasetype().ty == Tsarray);
|
||||
}
|
||||
|
||||
override Optional!bool toBool()
|
||||
|
@ -3956,6 +3965,8 @@ extern (C++) final class ArrayExp : UnaExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
if (rvalue)
|
||||
return false;
|
||||
if (type && type.toBasetype().ty == Tvoid)
|
||||
return false;
|
||||
return true;
|
||||
|
@ -4005,7 +4016,7 @@ extern (C++) final class CommaExp : BinExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
return e2.isLvalue();
|
||||
return !rvalue && e2.isLvalue();
|
||||
}
|
||||
|
||||
override Optional!bool toBool()
|
||||
|
@ -4080,7 +4091,7 @@ extern (C++) final class DelegatePtrExp : UnaExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
return e1.isLvalue();
|
||||
return !rvalue && e1.isLvalue();
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -4103,7 +4114,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
return e1.isLvalue();
|
||||
return !rvalue && e1.isLvalue();
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -4143,6 +4154,8 @@ extern (C++) final class IndexExp : BinExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
if (rvalue)
|
||||
return false;
|
||||
auto t1b = e1.type.toBasetype();
|
||||
if (t1b.isTypeAArray() || t1b.isTypeSArray() ||
|
||||
(e1.isIndexExp() && t1b != t1b.isTypeDArray()))
|
||||
|
@ -4251,7 +4264,7 @@ extern (C++) class AssignExp : BinExp
|
|||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !rvalue;
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
@ -4982,7 +4995,7 @@ extern (C++) final class CondExp : BinExp
|
|||
|
||||
override bool isLvalue()
|
||||
{
|
||||
return e1.isLvalue() && e2.isLvalue();
|
||||
return !rvalue && e1.isLvalue() && e2.isLvalue();
|
||||
}
|
||||
|
||||
override void accept(Visitor v)
|
||||
|
|
|
@ -78,6 +78,7 @@ public:
|
|||
Loc loc; // file location
|
||||
EXP op; // to minimize use of dynamic_cast
|
||||
d_bool parens; // if this is a parenthesized expression
|
||||
d_bool rvalue; // consider this an rvalue, even if it is an lvalue
|
||||
|
||||
size_t size() const;
|
||||
static void _init();
|
||||
|
@ -138,7 +139,7 @@ public:
|
|||
TypeidExp* isTypeidExp();
|
||||
TraitsExp* isTraitsExp();
|
||||
HaltExp* isHaltExp();
|
||||
IsExp* isExp();
|
||||
IsExp* isIsExp();
|
||||
MixinExp* isMixinExp();
|
||||
ImportExp* isImportExp();
|
||||
AssertExp* isAssertExp();
|
||||
|
|
|
@ -816,21 +816,58 @@ extern(D) bool arrayExpressionSemantic(
|
|||
* Params:
|
||||
* sc = the scope where the expression is encountered
|
||||
* e = the expression the needs to be moved or copied (source)
|
||||
* t = if the struct defines a copy constructor, the type of the destination
|
||||
*
|
||||
* t = if the struct defines a copy constructor, the type of the destination (can be NULL)
|
||||
* nrvo = true if the generated copy can be treated as NRVO
|
||||
* move = true to allow a move constructor to be used, false to prevent infinite recursion
|
||||
* Returns:
|
||||
* The expression that copy constructs or moves the value.
|
||||
*/
|
||||
extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
|
||||
extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t, bool nrvo, bool move = false)
|
||||
{
|
||||
//printf("doCopyOrMove() %s\n", toChars(e));
|
||||
StructDeclaration sd;
|
||||
if (t)
|
||||
{
|
||||
if (auto ts = t.isTypeStruct())
|
||||
sd = ts.sym;
|
||||
}
|
||||
|
||||
if (auto ce = e.isCondExp())
|
||||
{
|
||||
ce.e1 = doCopyOrMove(sc, ce.e1);
|
||||
ce.e2 = doCopyOrMove(sc, ce.e2);
|
||||
ce.e1 = doCopyOrMove(sc, ce.e1, null, nrvo);
|
||||
ce.e2 = doCopyOrMove(sc, ce.e2, null, nrvo);
|
||||
}
|
||||
else if (e.isLvalue())
|
||||
{
|
||||
e = callCpCtor(sc, e, t, nrvo);
|
||||
}
|
||||
else if (move && sd && sd.hasMoveCtor && !e.isCallExp() && !e.isStructLiteralExp())
|
||||
{
|
||||
// #move
|
||||
/* Rewrite as:
|
||||
* S __copyrvalue;
|
||||
* __copyrvalue.moveCtor(e);
|
||||
* __copyrvalue;
|
||||
*/
|
||||
VarDeclaration vd = new VarDeclaration(e.loc, e.type, Identifier.generateId("__copyrvalue"), null);
|
||||
if (nrvo)
|
||||
vd.adFlags |= Declaration.nrvo;
|
||||
vd.storage_class |= STC.nodtor;
|
||||
vd.dsymbolSemantic(sc);
|
||||
Expression de = new DeclarationExp(e.loc, vd);
|
||||
Expression ve = new VarExp(e.loc, vd);
|
||||
|
||||
Expression er;
|
||||
er = new DotIdExp(e.loc, ve, Id.ctor); // ve.ctor
|
||||
er = new CallExp(e.loc, er, e); // ve.ctor(e)
|
||||
er = new CommaExp(e.loc, er, new VarExp(e.loc, vd)); // ve.ctor(e),vd
|
||||
er = Expression.combine(de, er); // de,ve.ctor(e),vd
|
||||
|
||||
e = er.expressionSemantic(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
|
||||
e = valueNoDtor(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
@ -839,13 +876,15 @@ extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
|
|||
* If e is an instance of a struct, and that struct has a copy constructor,
|
||||
* rewrite e as:
|
||||
* (tmp = e),tmp
|
||||
* Input:
|
||||
* Params:
|
||||
* sc = just used to specify the scope of created temporary variable
|
||||
* destinationType = the type of the object on which the copy constructor is called;
|
||||
* may be null if the struct defines a postblit
|
||||
* nrvo = true if the generated copy can be treated as NRVO
|
||||
*/
|
||||
private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
|
||||
private Expression callCpCtor(Scope* sc, Expression e, Type destinationType, bool nrvo)
|
||||
{
|
||||
//printf("callCpCtor(e: %s et: %s destinationType: %s\n", toChars(e), toChars(e.type), toChars(destinationType));
|
||||
auto ts = e.type.baseElemOf().isTypeStruct();
|
||||
|
||||
if (!ts)
|
||||
|
@ -860,7 +899,9 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
|
|||
* This is not the most efficient, ideally tmp would be constructed
|
||||
* directly onto the stack.
|
||||
*/
|
||||
auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
|
||||
VarDeclaration tmp = copyToTemp(STC.rvalue, "__copytmp", e);
|
||||
if (nrvo)
|
||||
tmp.adFlags |= Declaration.nrvo;
|
||||
if (sd.hasCopyCtor && destinationType)
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22619
|
||||
|
@ -888,6 +929,7 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
|
|||
*/
|
||||
Expression valueNoDtor(Expression e)
|
||||
{
|
||||
//printf("valueNoDtor() %s\n", toChars(e));
|
||||
auto ex = lastComma(e);
|
||||
|
||||
if (auto ce = ex.isCallExp())
|
||||
|
@ -2706,7 +2748,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
|
|||
continue;
|
||||
}
|
||||
|
||||
e = doCopyOrMove(sc, e);
|
||||
e = doCopyOrMove(sc, e, null, false);
|
||||
|
||||
if (!foundType && t0 && !t0.equals(e.type))
|
||||
{
|
||||
|
@ -2952,7 +2994,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
|||
Type* prettype, Expression* peprefix)
|
||||
{
|
||||
Expressions* arguments = argumentList.arguments;
|
||||
//printf("functionParameters() %s\n", fd ? fd.toChars() : "");
|
||||
//printf("functionParameters() fd: %s tf: %s\n", fd ? fd.ident.toChars() : "", toChars(tf));
|
||||
assert(arguments);
|
||||
assert(fd || tf.next);
|
||||
const size_t nparams = tf.parameterList.length;
|
||||
|
@ -3677,7 +3719,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
|||
*/
|
||||
Type tv = arg.type.baseElemOf();
|
||||
if (!isRef && tv.ty == Tstruct)
|
||||
arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
|
||||
arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null, false);
|
||||
}
|
||||
|
||||
(*arguments)[i] = arg;
|
||||
|
@ -3886,11 +3928,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
|
||||
}
|
||||
if (exp.type) // This is used as the dummy expression
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
scope (exit) result.rvalue = exp.rvalue;
|
||||
|
||||
Dsymbol scopesym;
|
||||
Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
|
||||
|
@ -4109,11 +4148,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("ThisExp::semantic()\n");
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
|
||||
AggregateDeclaration ad;
|
||||
|
@ -4174,11 +4208,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("SuperExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
FuncDeclaration fd = hasThis(sc);
|
||||
ClassDeclaration cd;
|
||||
|
@ -4255,11 +4284,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
printf("NullExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
// NULL is the same as (void *)0
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
e.type = Type.tnull;
|
||||
result = e;
|
||||
}
|
||||
|
@ -4348,11 +4372,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("StringExp::semantic() %s\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
OutBuffer buffer;
|
||||
size_t newlen = 0;
|
||||
|
@ -4461,11 +4480,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("+TupleExp::semantic(%s)\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (exp.e0)
|
||||
exp.e0 = exp.e0.expressionSemantic(sc);
|
||||
|
@ -4503,11 +4517,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perhaps an empty array literal [ ] should be rewritten as null?
|
||||
*/
|
||||
|
@ -4550,11 +4559,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
// Run semantic() on each element
|
||||
bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
|
||||
|
@ -4593,11 +4597,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("StructLiteralExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
e.sd.size(e.loc);
|
||||
if (e.sd.sizeok != Sizeok.done)
|
||||
|
@ -4702,11 +4701,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
ScopeDsymbol sds2 = exp.sds;
|
||||
TemplateInstance ti = sds2.isTemplateInstance();
|
||||
|
@ -4895,11 +4889,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
printf("\tthisexp = %s\n", exp.thisexp.toChars());
|
||||
printf("\tnewtype: %s\n", exp.newtype.toChars());
|
||||
}
|
||||
if (exp.type) // if semantic() already run
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
//for error messages if the argument in [] is not convertible to size_t
|
||||
const originalNewtype = exp.newtype;
|
||||
|
@ -5677,7 +5666,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
symtab = sds.symtab;
|
||||
}
|
||||
assert(symtab);
|
||||
Identifier id = Identifier.generateIdWithLoc(s, exp.loc);
|
||||
Identifier id = Identifier.generateIdWithLoc(s, exp.loc, cast(string) toDString(sc.parent.toPrettyChars()));
|
||||
exp.fd.ident = id;
|
||||
if (exp.td)
|
||||
exp.td.ident = id;
|
||||
|
@ -5693,11 +5682,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
printf(" treq = %s\n", exp.fd.treq.toChars());
|
||||
}
|
||||
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
Expression e = exp;
|
||||
|
||||
|
@ -5891,11 +5875,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("CallExp::semantic() %s\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return; // semantic() already run
|
||||
}
|
||||
|
||||
Objects* tiargs = null; // initial list of template arguments
|
||||
Expression ethis = null;
|
||||
|
@ -6718,7 +6697,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
errorSupplemental(exp.loc, "%s", failMessage);
|
||||
}
|
||||
|
||||
if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
|
||||
if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
|
||||
return setError();
|
||||
|
||||
// Purity and safety check should run after testing arguments matching
|
||||
|
@ -6801,7 +6780,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
exp.f = null;
|
||||
}
|
||||
|
||||
if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
|
||||
if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
|
||||
exp.f = null;
|
||||
}
|
||||
if (!exp.f || exp.f.errors)
|
||||
|
@ -6954,11 +6933,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(DeclarationExp e)
|
||||
{
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
static if (LOGSEMANTIC)
|
||||
{
|
||||
printf("DeclarationExp::semantic() %s\n", e.toChars());
|
||||
|
@ -7575,11 +7549,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(BinAssignExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
Expression e = exp.op_overload(sc);
|
||||
if (e)
|
||||
|
@ -8157,6 +8126,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
import dmd.statementsem;
|
||||
|
||||
te.type = Type.tnoreturn;
|
||||
if (throwSemantic(te.loc, te.e1, sc))
|
||||
result = te;
|
||||
else
|
||||
|
@ -8168,7 +8138,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));
|
||||
printAST(exp);
|
||||
}
|
||||
|
||||
if (sc.inCfile)
|
||||
|
@ -8251,11 +8221,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(DotTemplateExp e)
|
||||
{
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
if (Expression ex = unaSemantic(e, sc))
|
||||
{
|
||||
result = ex;
|
||||
|
@ -8272,11 +8237,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("DotVarExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
exp.var = exp.var.toAlias().isDeclaration();
|
||||
|
||||
|
@ -8444,11 +8404,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
// Indicate we need to resolve by UFCS.
|
||||
Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
|
||||
if (!e)
|
||||
|
@ -8464,11 +8419,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("DelegateExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
e.e1 = e.e1.expressionSemantic(sc);
|
||||
|
||||
|
@ -8530,11 +8480,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("DotTypeExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto e = unaSemantic(exp, sc))
|
||||
{
|
||||
|
@ -8552,11 +8497,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("AddrExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = unaSemantic(exp, sc))
|
||||
{
|
||||
|
@ -8853,11 +8793,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("PtrExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
Expression e = exp.op_overload(sc);
|
||||
if (e)
|
||||
|
@ -8916,11 +8851,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("NegExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
Expression e = exp.op_overload(sc);
|
||||
if (e)
|
||||
|
@ -8962,7 +8892,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("UAddExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
assert(!exp.type);
|
||||
|
||||
Expression e = exp.op_overload(sc);
|
||||
if (e)
|
||||
|
@ -8989,11 +8918,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(ComExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
Expression e = exp.op_overload(sc);
|
||||
if (e)
|
||||
|
@ -9031,11 +8955,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(NotExp e)
|
||||
{
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
e.setNoderefOperand();
|
||||
|
||||
|
@ -9140,11 +9059,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
printf("CastExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
//static int x; assert(++x < 10);
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sc && sc.inCfile) &&
|
||||
exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
|
||||
|
@ -9429,11 +9343,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("VectorExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
exp.e1 = exp.e1.expressionSemantic(sc);
|
||||
exp.type = exp.to.typeSemantic(exp.loc, sc);
|
||||
|
@ -9502,11 +9411,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("SliceExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
// operator overloading should be handled in ArrayExp already.
|
||||
if (Expression ex = unaSemantic(exp, sc))
|
||||
|
@ -9789,11 +9693,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = unaSemantic(e, sc))
|
||||
{
|
||||
|
@ -9812,7 +9711,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("ArrayExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
assert(!exp.type);
|
||||
|
||||
if (sc.inCfile)
|
||||
{
|
||||
|
@ -9886,11 +9784,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
override void visit(CommaExp e)
|
||||
{
|
||||
//printf("Semantic.CommaExp() %s\n", e.toChars());
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow `((a,b),(x,y))`
|
||||
if (e.allowCommaExp)
|
||||
|
@ -9936,11 +9829,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("IntervalExp::semantic('%s')\n", e.toChars());
|
||||
}
|
||||
if (e.type)
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
}
|
||||
|
||||
Expression le = e.lwr;
|
||||
le = le.expressionSemantic(sc);
|
||||
|
@ -10015,11 +9903,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("IndexExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
// operator overloading should be handled in ArrayExp already.
|
||||
if (!exp.e1.type)
|
||||
|
@ -10242,11 +10125,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("PostExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc.inCfile)
|
||||
{
|
||||
|
@ -10404,9 +10282,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
static if (LOGSEMANTIC)
|
||||
{
|
||||
if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
|
||||
if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
|
||||
if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
|
||||
if (exp.op == EXP.blit) printf("BlitExp.semantic('%s')\n", exp.toChars());
|
||||
if (exp.op == EXP.assign) printf("AssignExp.semantic('%s')\n", exp.toChars());
|
||||
if (exp.op == EXP.construct) printf("ConstructExp.semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
|
||||
void setResult(Expression e, int line = __LINE__)
|
||||
|
@ -10415,11 +10293,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
result = e;
|
||||
}
|
||||
|
||||
if (exp.type)
|
||||
{
|
||||
return setResult(exp);
|
||||
}
|
||||
|
||||
Expression e1old = exp.e1;
|
||||
|
||||
if (auto e2comma = exp.e2.isCommaExp())
|
||||
|
@ -10876,6 +10749,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
/* We have a copy constructor for this
|
||||
*/
|
||||
|
||||
//printf("exp: %s\n", toChars(exp));
|
||||
//printf("e2x: %s\n", toChars(e2x));
|
||||
if (e2x.isLvalue())
|
||||
{
|
||||
if (sd.hasCopyCtor)
|
||||
|
@ -10922,6 +10797,38 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
return;
|
||||
}
|
||||
}
|
||||
else if (sd.hasMoveCtor && !e2x.isCallExp() && !e2x.isStructLiteralExp())
|
||||
{
|
||||
// #move
|
||||
/* The !e2x.isCallExp() is because it is already an rvalue
|
||||
and the move constructor is unnecessary:
|
||||
struct S {
|
||||
alias TT this;
|
||||
long TT();
|
||||
this(T)(int x) {}
|
||||
this(S);
|
||||
this(ref S);
|
||||
~this();
|
||||
}
|
||||
S fun(ref S arg);
|
||||
void test() { S st; fun(st); }
|
||||
*/
|
||||
/* Rewrite as:
|
||||
* e1 = init, e1.moveCtor(e2);
|
||||
*/
|
||||
Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
|
||||
einit.type = e1x.type;
|
||||
|
||||
Expression e;
|
||||
e = new DotIdExp(exp.loc, e1x, Id.ctor);
|
||||
e = new CallExp(exp.loc, e, e2x);
|
||||
e = new CommaExp(exp.loc, einit, e);
|
||||
|
||||
//printf("e: %s\n", e.toChars());
|
||||
|
||||
result = e.expressionSemantic(sc);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The struct value returned from the function is transferred
|
||||
|
@ -11815,11 +11722,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(PowAssignExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
Expression e = exp.op_overload(sc);
|
||||
if (e)
|
||||
|
@ -11899,11 +11801,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(CatAssignExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
//printf("CatAssignExp::semantic() %s\n", exp.toChars());
|
||||
Expression e = exp.op_overload(sc);
|
||||
|
@ -11985,7 +11882,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
ce.trusted = true;
|
||||
|
||||
exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, ecast);
|
||||
exp.e2 = doCopyOrMove(sc, exp.e2);
|
||||
exp.e2 = doCopyOrMove(sc, exp.e2, null, false);
|
||||
}
|
||||
else if (tb1.ty == Tarray &&
|
||||
(tb1next.ty == Tchar || tb1next.ty == Twchar) &&
|
||||
|
@ -12195,11 +12092,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("AddExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -12302,11 +12194,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("MinExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -12554,11 +12441,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
// https://dlang.org/spec/expression.html#cat_expressions
|
||||
//printf("CatExp.semantic() %s\n", toChars());
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -12610,7 +12492,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
if (exp.e1.op == EXP.arrayLiteral)
|
||||
{
|
||||
exp.e2 = doCopyOrMove(sc, exp.e2);
|
||||
exp.e2 = doCopyOrMove(sc, exp.e2, null, false);
|
||||
// https://issues.dlang.org/show_bug.cgi?id=14686
|
||||
// Postblit call appears in AST, and this is
|
||||
// finally translated to an ArrayLiteralExp in below optimize().
|
||||
|
@ -12649,7 +12531,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
if (exp.e2.op == EXP.arrayLiteral)
|
||||
{
|
||||
exp.e1 = doCopyOrMove(sc, exp.e1);
|
||||
exp.e1 = doCopyOrMove(sc, exp.e1, null, false);
|
||||
}
|
||||
else if (exp.e2.op == EXP.string_)
|
||||
{
|
||||
|
@ -12741,11 +12623,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("MulExp::semantic() %s\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -12841,11 +12718,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(DivExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -12942,11 +12814,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(ModExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -13000,11 +12867,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(PowExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
//printf("PowExp::semantic() %s\n", toChars());
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
|
@ -13080,11 +12942,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
private void visitShift(BinExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -13133,11 +12990,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
private void visitBinaryBitOp(BinExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -13206,11 +13058,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
printf("LogicalExp::semantic() %s\n", exp.toChars());
|
||||
}
|
||||
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
exp.setNoderefOperands();
|
||||
|
||||
|
@ -13292,11 +13139,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("CmpExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
exp.setNoderefOperands();
|
||||
|
||||
|
@ -13461,11 +13303,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(InExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expression ex = binSemanticProp(exp, sc))
|
||||
{
|
||||
|
@ -13531,11 +13368,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
override void visit(EqualExp exp)
|
||||
{
|
||||
//printf("EqualExp::semantic('%s')\n", exp.toChars());
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
exp.setNoderefOperands();
|
||||
|
||||
|
@ -13754,11 +13586,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
override void visit(IdentityExp exp)
|
||||
{
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
exp.setNoderefOperands();
|
||||
|
||||
|
@ -13822,11 +13649,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
printf("CondExp::semantic('%s')\n", exp.toChars());
|
||||
}
|
||||
if (exp.type)
|
||||
{
|
||||
result = exp;
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto die = exp.econd.isDotIdExp())
|
||||
die.noderef = true;
|
||||
|
@ -14188,9 +14010,25 @@ Expression binSemanticProp(BinExp e, Scope* sc)
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Returns: whether expressionSemantic() has been run on expression `e`
|
||||
private bool expressionSemanticDone(Expression e)
|
||||
{
|
||||
// Usually, Expression.type gets set by expressionSemantic and is `null` beforehand
|
||||
// There are some exceptions however:
|
||||
return e.type !is null && !(
|
||||
e.isRealExp() // type sometimes gets set already before semantic
|
||||
|| e.isTypeExp() // stores its type in the Expression.type field
|
||||
|| e.isCompoundLiteralExp() // stores its `(type) {}` in type field, gets rewritten to struct literal
|
||||
|| e.isVarExp() // type sometimes gets set already before semantic
|
||||
);
|
||||
}
|
||||
|
||||
// entrypoint for semantic ExpressionSemanticVisitor
|
||||
Expression expressionSemantic(Expression e, Scope* sc)
|
||||
{
|
||||
if (e.expressionSemanticDone)
|
||||
return e;
|
||||
|
||||
scope v = new ExpressionSemanticVisitor(sc);
|
||||
e.accept(v);
|
||||
return v.result;
|
||||
|
@ -14198,7 +14036,7 @@ Expression expressionSemantic(Expression e, Scope* sc)
|
|||
|
||||
private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
|
||||
{
|
||||
//printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
|
||||
//printf("dotIdSemanticPropX() %s\n", toChars(exp));
|
||||
if (Expression ex = unaSemantic(exp, sc))
|
||||
return ex;
|
||||
|
||||
|
@ -14326,7 +14164,7 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
|
|||
*/
|
||||
Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
|
||||
{
|
||||
//printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
|
||||
//printf("dotIdSemanticProp('%s')\n", exp.toChars());
|
||||
|
||||
//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
|
||||
|
||||
|
@ -14664,7 +14502,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
|
|||
|
||||
const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
|
||||
|
||||
Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
|
||||
Expression e = dotExp(exp.e1.type, sc, exp.e1, exp.ident, flag);
|
||||
if (e)
|
||||
{
|
||||
e = e.expressionSemantic(sc);
|
||||
|
@ -15482,6 +15320,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
|
|||
*/
|
||||
Expression addDtorHook(Expression e, Scope* sc)
|
||||
{
|
||||
//printf("addDtorHook() %s\n", toChars(e));
|
||||
Expression visit(Expression exp)
|
||||
{
|
||||
return exp;
|
||||
|
@ -16510,7 +16349,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
|
|||
if (e.op == EXP.error)
|
||||
return false;
|
||||
|
||||
(*elements)[i] = doCopyOrMove(sc, e);
|
||||
(*elements)[i] = doCopyOrMove(sc, e, null, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -269,6 +269,10 @@ extern (C++) class FuncDeclaration : Declaration
|
|||
*/
|
||||
VarDeclarations outerVars;
|
||||
|
||||
// Most recent encountered `main` (`WinMain` or `DllMain`) function.
|
||||
// Track it to give error messages for multiple entrypoints
|
||||
__gshared FuncDeclaration lastMain;
|
||||
|
||||
/// Sibling nested functions which called this one
|
||||
FuncDeclarations siblingCallers;
|
||||
|
||||
|
@ -1366,11 +1370,13 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
|
|||
*/
|
||||
extern (C++) final class CtorDeclaration : FuncDeclaration
|
||||
{
|
||||
bool isCpCtor;
|
||||
extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
|
||||
bool isCpCtor; // copy constructor
|
||||
bool isMoveCtor; // move constructor (aka rvalue constructor)
|
||||
extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false, bool isMoveCtor = false)
|
||||
{
|
||||
super(loc, endloc, Id.ctor, stc, type);
|
||||
this.isCpCtor = isCpCtor;
|
||||
this.isMoveCtor = isMoveCtor;
|
||||
//printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
|
||||
}
|
||||
|
||||
|
|
|
@ -154,6 +154,28 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* Only one entry point function is allowed. Print error if more than one.
|
||||
* Params:
|
||||
* fd = a "main" function
|
||||
* Returns:
|
||||
* true if haven't seen "main" before
|
||||
*/
|
||||
extern (C++) bool onlyOneMain(FuncDeclaration fd)
|
||||
{
|
||||
if (auto lastMain = FuncDeclaration.lastMain)
|
||||
{
|
||||
const format = (target.os == Target.OS.Windows)
|
||||
? "only one entry point `main`, `WinMain` or `DllMain` is allowed"
|
||||
: "only one entry point `main` is allowed";
|
||||
error(fd.loc, format.ptr);
|
||||
errorSupplemental(lastMain.loc, "previously found `%s` here", lastMain.toFullSignature());
|
||||
return false;
|
||||
}
|
||||
FuncDeclaration.lastMain = fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Main semantic routine for functions.
|
||||
*/
|
||||
|
@ -1507,6 +1529,7 @@ enum FuncResolveFlag : ubyte
|
|||
FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
|
||||
Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
|
||||
{
|
||||
//printf("resolveFuncCall() %s\n", s.toChars());
|
||||
auto fargs = argumentList.arguments;
|
||||
if (!s)
|
||||
return null; // no match
|
||||
|
@ -2066,7 +2089,7 @@ MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* name
|
|||
args.push(e);
|
||||
}
|
||||
|
||||
MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
|
||||
MATCH m = callMatch(g, tg, null, ArgumentList(&args, names), 1);
|
||||
if (m > MATCH.nomatch)
|
||||
{
|
||||
/* A variadic parameter list is less specialized than a
|
||||
|
@ -2939,6 +2962,7 @@ extern (D) void checkMain(FuncDeclaration fd)
|
|||
*/
|
||||
extern (D) bool checkNRVO(FuncDeclaration fd)
|
||||
{
|
||||
//printf("checkNRVO*() %s\n", fd.ident.toChars());
|
||||
if (!fd.isNRVO() || fd.returns is null)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -82,6 +82,13 @@ enum CLIIdentifierTable : ubyte
|
|||
All = 4, /// The least restrictive set of all other tables
|
||||
}
|
||||
|
||||
/// Specifies the mode for error printing
|
||||
enum ErrorPrintMode : ubyte
|
||||
{
|
||||
simpleError, // Print errors without squiggles and carets
|
||||
printErrorContext, // Print errors with context (source line and caret)
|
||||
}
|
||||
|
||||
extern(C++) struct Output
|
||||
{
|
||||
bool doOutput; // Output is enabled
|
||||
|
@ -126,10 +133,10 @@ extern(C++) struct Verbose
|
|||
bool complex = true; // identify complex/imaginary type usage
|
||||
bool vin; // identify 'in' parameters
|
||||
bool showGaggedErrors; // print gagged errors anyway
|
||||
bool printErrorContext; // print errors with the error context (the error line in the source file)
|
||||
bool logo; // print compiler logo
|
||||
bool color; // use ANSI colors in console output
|
||||
bool cov; // generate code coverage data
|
||||
ErrorPrintMode errorPrintMode; // enum for error printing mode
|
||||
MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages
|
||||
uint errorLimit = 20;
|
||||
uint errorSupplementLimit = 6; // Limit the number of supplemental messages for each error (0 means unlimited)
|
||||
|
|
|
@ -94,6 +94,13 @@ enum class CLIIdentifierTable : unsigned char
|
|||
All = 4, /// The least restrictive set of all other tables
|
||||
};
|
||||
|
||||
/// Specifies the mode for error printing
|
||||
enum class ErrorPrintMode : unsigned char
|
||||
{
|
||||
simpleError, // Print errors without squiggles and carets
|
||||
printErrorContext, // Print errors with the error line and caret
|
||||
};
|
||||
|
||||
struct Output
|
||||
{
|
||||
/// Configuration for the compiler generator
|
||||
|
@ -138,10 +145,10 @@ struct Verbose
|
|||
d_bool complex = true; // identify complex/imaginary type usage
|
||||
d_bool vin; // identify 'in' parameters
|
||||
d_bool showGaggedErrors; // print gagged errors anyway
|
||||
d_bool printErrorContext; // print errors with the error context (the error line in the source file)
|
||||
d_bool logo; // print compiler logo
|
||||
d_bool color; // use ANSI colors in console output
|
||||
d_bool cov; // generate code coverage data
|
||||
ErrorPrintMode errorPrintMode; // enum for error printing mode
|
||||
MessageStyle messageStyle; // style of file/line annotations on messages
|
||||
unsigned errorLimit;
|
||||
unsigned errorSupplementLimit; // Limit the number of supplemental messages for each error (0 means unlimited)
|
||||
|
@ -192,7 +199,7 @@ struct Param
|
|||
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
|
||||
// Implementation: https://github.com/dlang/dmd/pull/9817
|
||||
FeatureState safer; // safer by default (more @safe checks in unattributed code)
|
||||
// https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md
|
||||
// https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md
|
||||
|
||||
FeatureState noSharedAccess; // read/write access to shared memory objects
|
||||
d_bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
|
||||
|
|
|
@ -305,10 +305,9 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
|
|||
buf.writenl();
|
||||
}
|
||||
|
||||
void visitWhile(WhileStatement s)
|
||||
void printConditionAssignment(Parameter p, Expression condition)
|
||||
{
|
||||
buf.writestring("while (");
|
||||
if (auto p = s.param)
|
||||
if (p)
|
||||
{
|
||||
// Print condition assignment
|
||||
StorageClass stc = p.storageClass;
|
||||
|
@ -322,7 +321,13 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
|
|||
buf.writestring(p.ident.toString());
|
||||
buf.writestring(" = ");
|
||||
}
|
||||
s.condition.expressionToBuffer(buf, hgs);
|
||||
condition.expressionToBuffer(buf, hgs);
|
||||
}
|
||||
|
||||
void visitWhile(WhileStatement s)
|
||||
{
|
||||
buf.writestring("while (");
|
||||
printConditionAssignment(s.param, s.condition);
|
||||
buf.writeByte(')');
|
||||
buf.writenl();
|
||||
if (s._body)
|
||||
|
@ -460,20 +465,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
|
|||
void visitIf(IfStatement s)
|
||||
{
|
||||
buf.writestring("if (");
|
||||
if (Parameter p = s.prm)
|
||||
{
|
||||
StorageClass stc = p.storageClass;
|
||||
if (!p.type && !stc)
|
||||
stc = STC.auto_;
|
||||
if (stcToBuffer(buf, stc))
|
||||
buf.writeByte(' ');
|
||||
if (p.type)
|
||||
typeToBuffer(p.type, p.ident, buf, hgs);
|
||||
else
|
||||
buf.writestring(p.ident.toString());
|
||||
buf.writestring(" = ");
|
||||
}
|
||||
s.condition.expressionToBuffer(buf, hgs);
|
||||
printConditionAssignment(s.prm, s.condition);
|
||||
buf.writeByte(')');
|
||||
buf.writenl();
|
||||
if (s.ifbody.isScopeStatement())
|
||||
|
@ -572,21 +564,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
|
|||
void visitSwitch(SwitchStatement s)
|
||||
{
|
||||
buf.writestring(s.isFinal ? "final switch (" : "switch (");
|
||||
if (auto p = s.param)
|
||||
{
|
||||
// Print condition assignment
|
||||
StorageClass stc = p.storageClass;
|
||||
if (!p.type && !stc)
|
||||
stc = STC.auto_;
|
||||
if (stcToBuffer(buf, stc))
|
||||
buf.writeByte(' ');
|
||||
if (p.type)
|
||||
typeToBuffer(p.type, p.ident, buf, hgs);
|
||||
else
|
||||
buf.writestring(p.ident.toString());
|
||||
buf.writestring(" = ");
|
||||
}
|
||||
s.condition.expressionToBuffer(buf, hgs);
|
||||
printConditionAssignment(s.param, s.condition);
|
||||
buf.writeByte(')');
|
||||
buf.writenl();
|
||||
if (s._body)
|
||||
|
@ -1718,7 +1696,10 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
|
|||
void visitFuncDeclaration(FuncDeclaration f)
|
||||
{
|
||||
//printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars());
|
||||
if (stcToBuffer(buf, f.storage_class))
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24891
|
||||
// return/scope storage classes are printed as part of function type
|
||||
if (stcToBuffer(buf, f.storage_class & ~(STC.scope_ | STC.return_ | STC.returnScope)))
|
||||
buf.writeByte(' ');
|
||||
typeToBuffer(f.type, f.ident, buf, hgs);
|
||||
auto tf = f.type.isTypeFunction();
|
||||
|
@ -2888,6 +2869,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
|
|||
buf.writestring(e.value.toChars());
|
||||
}
|
||||
|
||||
if (e.rvalue)
|
||||
buf.writestring("__rvalue(");
|
||||
|
||||
scope (exit)
|
||||
if (e.rvalue)
|
||||
buf.writeByte(')');
|
||||
|
||||
switch (e.op)
|
||||
{
|
||||
default:
|
||||
|
@ -2929,7 +2917,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
|
|||
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.is_: return visitIs(e.isIsExp());
|
||||
case EXP.comma: return visitComma(e.isCommaExp());
|
||||
case EXP.mixin_: return visitMixin(e.isMixinExp());
|
||||
case EXP.import_: return visitImport(e.isImportExp());
|
||||
|
|
|
@ -519,6 +519,7 @@ immutable Msgtable[] msgtable =
|
|||
{ "getLocation" },
|
||||
{ "hasPostblit" },
|
||||
{ "hasCopyConstructor" },
|
||||
{ "hasMoveConstructor" },
|
||||
{ "isCopyable" },
|
||||
{ "toType" },
|
||||
{ "parameters" },
|
||||
|
|
|
@ -211,11 +211,14 @@ nothrow:
|
|||
* Params:
|
||||
* prefix = first part of the identifier name.
|
||||
* loc = source location to use in the identifier name.
|
||||
* parent = (optional) extra part to be used in uniqueness check,
|
||||
* if (prefix1, loc1) == (prefix2, loc2), but
|
||||
* parent1 != parent2, no new name will be generated.
|
||||
* Returns:
|
||||
* Identifier (inside Identifier.idPool) with deterministic name based
|
||||
* on the source location.
|
||||
*/
|
||||
extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc)
|
||||
extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc, string parent = "")
|
||||
{
|
||||
// generate `<prefix>_L<line>_C<col>`
|
||||
OutBuffer idBuf;
|
||||
|
@ -234,14 +237,20 @@ nothrow:
|
|||
* https://issues.dlang.org/show_bug.cgi?id=18880
|
||||
* https://issues.dlang.org/show_bug.cgi?id=18868
|
||||
* https://issues.dlang.org/show_bug.cgi?id=19058
|
||||
*
|
||||
* It is a bit trickier for lambdas/dgliterals: we want them to be unique per
|
||||
* module/mixin + function/template instantiation context. So we use extra parent
|
||||
* argument for that when dealing with lambdas. We could have added it to prefix
|
||||
* directly, but that would unnecessary lengthen symbols names. See issue:
|
||||
* https://issues.dlang.org/show_bug.cgi?id=23722
|
||||
*/
|
||||
static struct Key { Loc loc; string prefix; }
|
||||
static struct Key { Loc loc; string prefix; string parent; }
|
||||
__gshared uint[Key] counters;
|
||||
|
||||
static if (__traits(compiles, counters.update(Key.init, () => 0u, (ref uint a) => 0u)))
|
||||
{
|
||||
// 2.082+
|
||||
counters.update(Key(loc, prefix),
|
||||
counters.update(Key(loc, prefix, parent),
|
||||
() => 1u, // insertion
|
||||
(ref uint counter) // update
|
||||
{
|
||||
|
@ -253,7 +262,7 @@ nothrow:
|
|||
}
|
||||
else
|
||||
{
|
||||
const key = Key(loc, prefix);
|
||||
const key = Key(loc, prefix, parent);
|
||||
if (auto pCounter = key in counters)
|
||||
{
|
||||
idBuf.writestring("_");
|
||||
|
|
|
@ -1630,7 +1630,7 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope*
|
|||
continue;
|
||||
}
|
||||
|
||||
elems[fieldi] = doCopyOrMove(sc, ex);
|
||||
elems[fieldi] = doCopyOrMove(sc, ex, null, false);
|
||||
++fieldi;
|
||||
}
|
||||
if (errors)
|
||||
|
|
|
@ -42,7 +42,8 @@ import dmd.target;
|
|||
import dmd.visitor;
|
||||
|
||||
version(Windows) {
|
||||
extern (C) char* getcwd(char* buffer, size_t maxlen);
|
||||
extern (C) char* _getcwd(char* buffer, size_t maxlen);
|
||||
alias getcwd = _getcwd;
|
||||
} else {
|
||||
import core.sys.posix.unistd : getcwd;
|
||||
}
|
||||
|
|
|
@ -1609,7 +1609,7 @@ extern (C++) abstract class TypeNext : Type
|
|||
|
||||
/*******************************
|
||||
* For TypeFunction, nextOf() can return NULL if the function return
|
||||
* type is meant to be inferred, and semantic() hasn't yet ben run
|
||||
* type is meant to be inferred, and semantic() hasn't yet been run
|
||||
* on the function. After semantic(), it must no longer be NULL.
|
||||
*/
|
||||
override final Type nextOf() @safe
|
||||
|
@ -3543,17 +3543,19 @@ extern (C++) final class TypeTuple : Type
|
|||
extern (D) this(Expressions* exps)
|
||||
{
|
||||
super(Ttuple);
|
||||
auto arguments = new Parameters(exps ? exps.length : 0);
|
||||
if (exps)
|
||||
if (!exps)
|
||||
{
|
||||
for (size_t i = 0; i < exps.length; i++)
|
||||
{
|
||||
Expression e = (*exps)[i];
|
||||
if (e.type.ty == Ttuple)
|
||||
error(e.loc, "cannot form sequence of sequences");
|
||||
auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null);
|
||||
(*arguments)[i] = arg;
|
||||
}
|
||||
this.arguments = new Parameters(0);
|
||||
return;
|
||||
}
|
||||
auto arguments = new Parameters(exps.length);
|
||||
|
||||
for (size_t i = 0; i < exps.length; i++)
|
||||
{
|
||||
Expression e = (*exps)[i];
|
||||
assert(e.type.ty != Ttuple);
|
||||
auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null);
|
||||
(*arguments)[i] = arg;
|
||||
}
|
||||
this.arguments = arguments;
|
||||
//printf("TypeTuple() %p, %s\n", this, toChars());
|
||||
|
|
|
@ -469,7 +469,7 @@ enum RET
|
|||
enum class TRUST : unsigned char
|
||||
{
|
||||
default_ = 0,
|
||||
system = 1, // @system (same as TRUSTdefault)
|
||||
system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled)
|
||||
trusted = 2, // @trusted
|
||||
safe = 3 // @safe
|
||||
};
|
||||
|
|
|
@ -93,39 +93,66 @@ struct ObjcSelector
|
|||
return sel;
|
||||
}
|
||||
|
||||
static const(char)[] toPascalCase(const(char)[] id) {
|
||||
OutBuffer buf;
|
||||
char firstChar = id[0];
|
||||
if (firstChar >= 'a' && firstChar <= 'z')
|
||||
firstChar = cast(char)(firstChar - 'a' + 'A');
|
||||
|
||||
buf.writeByte(firstChar);
|
||||
buf.writestring(id[1..$]);
|
||||
return cast(const(char)[])buf.extractSlice(false);
|
||||
}
|
||||
|
||||
extern (C++) static ObjcSelector* create(FuncDeclaration fdecl)
|
||||
{
|
||||
OutBuffer buf;
|
||||
auto ftype = cast(TypeFunction)fdecl.type;
|
||||
const id = fdecl.ident.toString();
|
||||
const nparams = ftype.parameterList.length;
|
||||
|
||||
// Special case: property setter
|
||||
if (ftype.isProperty && nparams == 1)
|
||||
{
|
||||
// rewrite "identifier" as "setIdentifier"
|
||||
char firstChar = id[0];
|
||||
if (firstChar >= 'a' && firstChar <= 'z')
|
||||
firstChar = cast(char)(firstChar - 'a' + 'A');
|
||||
buf.writestring("set");
|
||||
buf.writeByte(firstChar);
|
||||
buf.write(id[1 .. id.length - 1]);
|
||||
|
||||
// Special case: "isXYZ:"
|
||||
if (id.length >= 2 && id[0..2] == "is")
|
||||
{
|
||||
buf.writestring("set");
|
||||
buf.write(toPascalCase(id[2..$]));
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.writestring("set");
|
||||
buf.write(toPascalCase(id));
|
||||
}
|
||||
buf.writeByte(':');
|
||||
goto Lcomplete;
|
||||
}
|
||||
|
||||
// write identifier in selector
|
||||
buf.write(id[]);
|
||||
// add mangled type and colon for each parameter
|
||||
if (nparams)
|
||||
|
||||
// To make it easier to match the selectors of objects nicely,
|
||||
// the implementation has been replaced so that the parameter name followed by a colon
|
||||
// is used instead.
|
||||
// eg. void myFunction(int a, int b, int c) would be mangled to a selector as `myFunction:b:c:
|
||||
if (nparams > 1)
|
||||
{
|
||||
buf.writeByte('_');
|
||||
foreach (i, fparam; ftype.parameterList)
|
||||
buf.writeByte(':');
|
||||
foreach(i; 1..nparams)
|
||||
{
|
||||
mangleToBuffer(fparam.type, buf);
|
||||
buf.write(ftype.parameterList[i].ident.toString());
|
||||
buf.writeByte(':');
|
||||
}
|
||||
}
|
||||
else if (nparams == 1)
|
||||
{
|
||||
buf.writeByte(':');
|
||||
}
|
||||
Lcomplete:
|
||||
buf.writeByte('\0');
|
||||
|
||||
// the slice is not expected to include a terminating 0
|
||||
return lookup(cast(const(char)*)buf[].ptr, buf.length - 1, nparams);
|
||||
}
|
||||
|
@ -565,6 +592,16 @@ extern(C++) private final class Supported : Objc
|
|||
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Avoid attempting to generate selectors for template instances.
|
||||
if (fd.parent && fd.parent.isTemplateInstance())
|
||||
return;
|
||||
|
||||
// No selector declared, generate one.
|
||||
if (fd._linkage == LINK.objc && !fd.objc.selector)
|
||||
{
|
||||
fd.objc.selector = ObjcSelector.create(fd);
|
||||
}
|
||||
}
|
||||
|
||||
override void validateSelector(FuncDeclaration fd)
|
||||
|
|
|
@ -932,22 +932,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
{
|
||||
const attrLoc = token.loc;
|
||||
|
||||
nextToken();
|
||||
|
||||
AST.Expression e = null; // default
|
||||
if (token.value == TOK.leftParenthesis)
|
||||
{
|
||||
nextToken();
|
||||
e = parseAssignExp();
|
||||
check(TOK.rightParenthesis);
|
||||
}
|
||||
AST.Expression e = parseAlign();
|
||||
|
||||
if (pAttrs.setAlignment)
|
||||
{
|
||||
if (e)
|
||||
error("redundant alignment attribute `align(%s)`", e.toChars());
|
||||
else
|
||||
error("redundant alignment attribute `align`");
|
||||
error("redundant alignment attribute `align(default)`");
|
||||
}
|
||||
|
||||
pAttrs.setAlignment = true;
|
||||
|
@ -4371,14 +4363,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
}
|
||||
case TOK.align_:
|
||||
{
|
||||
nextToken();
|
||||
setAlignment = true;
|
||||
if (token.value == TOK.leftParenthesis)
|
||||
{
|
||||
nextToken();
|
||||
ealign = parseExpression();
|
||||
check(TOK.rightParenthesis);
|
||||
}
|
||||
ealign = parseAlign();
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
|
@ -4388,6 +4374,27 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse `align` or `align(n)`
|
||||
* Returns:
|
||||
* expression `n` if it is present, or `null` otherwise.
|
||||
*/
|
||||
private AST.Expression parseAlign()
|
||||
{
|
||||
assert(token.value == TOK.align_);
|
||||
AST.Expression e = null;
|
||||
nextToken();
|
||||
if (token.value == TOK.leftParenthesis)
|
||||
{
|
||||
nextToken();
|
||||
if (token.value == TOK.default_)
|
||||
nextToken();
|
||||
else
|
||||
e = parseAssignExp();
|
||||
check(TOK.rightParenthesis);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
/**********************************
|
||||
* Parse Declarations.
|
||||
* These can be:
|
||||
|
@ -5252,7 +5259,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
error("missing `do { ... }` after `in` or `out`");
|
||||
const returnloc = token.loc;
|
||||
nextToken();
|
||||
f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
|
||||
if (f.isCtorDeclaration)
|
||||
f.fbody = new AST.ExpStatement(returnloc, parseExpression());
|
||||
else
|
||||
f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
|
||||
f.endloc = token.loc;
|
||||
check(TOK.semicolon);
|
||||
break;
|
||||
|
@ -5877,6 +5887,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
case TOK.moduleString:
|
||||
case TOK.functionString:
|
||||
case TOK.prettyFunction:
|
||||
case TOK.rvalue:
|
||||
Lexp:
|
||||
{
|
||||
AST.Expression exp = parseExpression();
|
||||
|
@ -8423,6 +8434,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
e = new AST.TypeidExp(loc, o);
|
||||
break;
|
||||
}
|
||||
case TOK.rvalue:
|
||||
{
|
||||
nextToken();
|
||||
check(TOK.leftParenthesis, "`__rvalue`");
|
||||
e = parseAssignExp();
|
||||
e.rvalue = true;
|
||||
check(TOK.rightParenthesis);
|
||||
break;
|
||||
}
|
||||
case TOK.traits:
|
||||
{
|
||||
/* __traits(identifier, args...)
|
||||
|
|
|
@ -51,6 +51,12 @@ extern (C++) final class PrintASTVisitor : Visitor
|
|||
printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "");
|
||||
}
|
||||
|
||||
override void visit(IdentifierExp e)
|
||||
{
|
||||
printIndent(indent);
|
||||
printf("Identifier `%s` %s\n", e.ident.toChars(), e.type ? e.type.toChars() : "");
|
||||
}
|
||||
|
||||
override void visit(IntegerExp e)
|
||||
{
|
||||
printIndent(indent);
|
||||
|
|
|
@ -42,7 +42,8 @@ version (Windows)
|
|||
|
||||
extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc;
|
||||
extern (Windows) void SetLastError(DWORD) nothrow @nogc;
|
||||
extern (C) char* getcwd(char* buffer, size_t maxlen) nothrow;
|
||||
extern (C) char* _getcwd(char* buffer, size_t maxlen) nothrow;
|
||||
alias getcwd = _getcwd;
|
||||
}
|
||||
|
||||
version (CRuntime_Glibc)
|
||||
|
|
|
@ -143,6 +143,7 @@ struct Scope final
|
|||
|
||||
AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value,
|
||||
// do not set wasRead for it
|
||||
StructDeclaration *argStruct; // elimiate recursion when looking for rvalue construction
|
||||
|
||||
Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol *&pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
|
||||
};
|
||||
|
|
|
@ -940,7 +940,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
|||
* If NRVO is not possible, all returned lvalues should call their postblits.
|
||||
*/
|
||||
if (!funcdecl.isNRVO())
|
||||
exp = doCopyOrMove(sc2, exp, f.next);
|
||||
exp = doCopyOrMove(sc2, exp, f.next, true, true);
|
||||
|
||||
if (tret.hasPointers())
|
||||
checkReturnEscape(*sc2, exp, false);
|
||||
|
|
|
@ -2460,7 +2460,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
|
|||
/* https://dlang.org/spec/statement.html#return-statement
|
||||
*/
|
||||
|
||||
//printf("ReturnStatement.dsymbolSemantic() %p, %s\n", rs, rs.toChars());
|
||||
//printf("ReturnStatement.dsymbolSemantic() %s\n", toChars(rs));
|
||||
|
||||
FuncDeclaration fd = sc.parent.isFuncDeclaration();
|
||||
if (fd.fes)
|
||||
|
|
|
@ -623,7 +623,7 @@ MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td, TemplateDeclaration
|
|||
enum LOG_LEASTAS = 0;
|
||||
static if (LOG_LEASTAS)
|
||||
{
|
||||
printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
|
||||
printf("%s.leastAsSpecialized(%s)\n", td.toChars(), td2.toChars());
|
||||
}
|
||||
|
||||
/* This works by taking the template parameters to this template
|
||||
|
@ -1890,23 +1890,22 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
|||
{
|
||||
version (none)
|
||||
{
|
||||
printf("functionResolve() dstart = %s\n", dstart.toChars());
|
||||
printf(" tiargs:\n");
|
||||
if (tiargs)
|
||||
printf("functionResolve() dstart: %s (", dstart.toChars());
|
||||
for (size_t i = 0; i < (tiargs ? (*tiargs).length : 0); i++)
|
||||
{
|
||||
for (size_t i = 0; i < tiargs.length; i++)
|
||||
{
|
||||
RootObject arg = (*tiargs)[i];
|
||||
printf("\t%s\n", arg.toChars());
|
||||
}
|
||||
if (i) printf(", ");
|
||||
RootObject arg = (*tiargs)[i];
|
||||
printf("%s", arg.toChars());
|
||||
}
|
||||
printf(" fargs:\n");
|
||||
for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
|
||||
printf(")(");
|
||||
for (size_t i = 0; i < (argumentList.arguments ? (*argumentList.arguments).length : 0); i++)
|
||||
{
|
||||
Expression arg = (*fargs)[i];
|
||||
printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
|
||||
if (i) printf(", ");
|
||||
Expression arg = (*argumentList.arguments)[i];
|
||||
printf("%s %s", arg.type.toChars(), arg.toChars());
|
||||
//printf("\tty = %d\n", arg.type.ty);
|
||||
}
|
||||
printf(")\n");
|
||||
//printf("stc = %llx\n", dstart._scope.stc);
|
||||
//printf("match:t/f = %d/%d\n", ta_last, m.last);
|
||||
}
|
||||
|
@ -1993,7 +1992,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
|||
tf.mod = tthis_fd.mod;
|
||||
}
|
||||
const(char)* failMessage;
|
||||
MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc);
|
||||
MATCH mfa = callMatch(fd, tf, tthis_fd, argumentList, 0, errorHelper, sc);
|
||||
//printf("test1: mfa = %d\n", mfa);
|
||||
if (failMessage)
|
||||
errorHelper(failMessage);
|
||||
|
@ -2198,7 +2197,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
|||
Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
|
||||
|
||||
auto tf = fd.type.isTypeFunction();
|
||||
MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc);
|
||||
MATCH mfa = callMatch(fd, tf, tthis_fd, argumentList, 0, null, sc);
|
||||
if (mfa < m.last)
|
||||
return 0;
|
||||
|
||||
|
@ -2300,8 +2299,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
|||
// Disambiguate by tf.callMatch
|
||||
auto tf1 = fd.type.isTypeFunction();
|
||||
auto tf2 = m.lastf.type.isTypeFunction();
|
||||
MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc);
|
||||
MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc);
|
||||
MATCH c1 = callMatch(fd, tf1, tthis_fd, argumentList, 0, null, sc);
|
||||
MATCH c2 = callMatch(m.lastf, tf2, tthis_best, argumentList, 0, null, sc);
|
||||
//printf("2: c1 = %d, c2 = %d\n", c1, c2);
|
||||
if (c1 > c2) goto Ltd;
|
||||
if (c1 < c2) goto Ltd_best;
|
||||
|
@ -2404,7 +2403,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
|||
if (m.lastf.type.ty == Terror)
|
||||
goto Lerror;
|
||||
auto tf = m.lastf.type.isTypeFunction();
|
||||
if (!tf.callMatch(tthis_best, argumentList, 0, null, sc))
|
||||
if (callMatch(m.lastf, tf, tthis_best, argumentList, 0, null, sc) == MATCH.nomatch)
|
||||
goto Lnomatch;
|
||||
|
||||
/* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
|
||||
|
|
|
@ -27,6 +27,9 @@ enum TOK : ubyte
|
|||
{
|
||||
reserved,
|
||||
|
||||
// if this list changes, update
|
||||
// tokens.h, ../tests/cxxfrontend.cc and ../../test/unit/lexer/location_offset.d to match
|
||||
|
||||
// Other
|
||||
leftParenthesis,
|
||||
rightParenthesis,
|
||||
|
@ -249,6 +252,7 @@ enum TOK : ubyte
|
|||
wchar_tLiteral,
|
||||
endOfLine, // \n, \r, \u2028, \u2029
|
||||
whitespace,
|
||||
rvalue,
|
||||
|
||||
// C only keywords
|
||||
inline,
|
||||
|
@ -425,6 +429,7 @@ enum EXP : ubyte
|
|||
interval,
|
||||
|
||||
loweredAssignExp,
|
||||
rvalue,
|
||||
}
|
||||
|
||||
enum FirstCKeyword = TOK.inline;
|
||||
|
@ -556,6 +561,7 @@ private immutable TOK[] keywords =
|
|||
TOK.prettyFunction,
|
||||
TOK.shared_,
|
||||
TOK.immutable_,
|
||||
TOK.rvalue,
|
||||
|
||||
// C only keywords
|
||||
TOK.inline,
|
||||
|
@ -680,6 +686,7 @@ extern (C++) struct Token
|
|||
TOK.pragma_: "pragma",
|
||||
TOK.typeof_: "typeof",
|
||||
TOK.typeid_: "typeid",
|
||||
TOK.rvalue: "__rvalue",
|
||||
TOK.template_: "template",
|
||||
TOK.void_: "void",
|
||||
TOK.int8: "byte",
|
||||
|
|
|
@ -258,6 +258,7 @@ enum class TOK : unsigned char
|
|||
wchar_tLiteral,
|
||||
endOfLine, // \n, \r, \u2028, \u2029
|
||||
whitespace,
|
||||
rvalue,
|
||||
|
||||
// C only keywords
|
||||
inline_,
|
||||
|
|
|
@ -544,7 +544,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
|||
}
|
||||
return True();
|
||||
}
|
||||
if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit)
|
||||
if (e.ident == Id.hasCopyConstructor ||
|
||||
e.ident == Id.hasMoveConstructor ||
|
||||
e.ident == Id.hasPostblit)
|
||||
{
|
||||
if (dim != 1)
|
||||
return dimError(1);
|
||||
|
@ -562,8 +564,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
|||
auto ts = tb.isTypeStruct();
|
||||
if (auto sd = ts ? ts.sym : null)
|
||||
{
|
||||
return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False())
|
||||
: (sd.hasCopyCtor ? True() : False());
|
||||
bool result;
|
||||
if (e.ident == Id.hasPostblit)
|
||||
result = sd.postblit !is null;
|
||||
else if (e.ident == Id. hasCopyConstructor)
|
||||
result = sd.hasCopyCtor;
|
||||
else
|
||||
result = sd.hasMoveCtor;
|
||||
return result ? True() : False();
|
||||
}
|
||||
return False();
|
||||
}
|
||||
|
|
|
@ -681,6 +681,7 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
|
|||
* 'args' are being matched to function type 'tf'
|
||||
* Determine match level.
|
||||
* Params:
|
||||
* fd = function being called, if a symbol
|
||||
* tf = function type
|
||||
* tthis = type of `this` pointer, null if not member function
|
||||
* argumentList = arguments to function call
|
||||
|
@ -690,9 +691,10 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
|
|||
* Returns:
|
||||
* MATCHxxxx
|
||||
*/
|
||||
extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
|
||||
extern (D) MATCH callMatch(FuncDeclaration fd, TypeFunction tf, Type tthis, ArgumentList argumentList,
|
||||
int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
|
||||
{
|
||||
//printf("TypeFunction::callMatch() %s\n", tf.toChars());
|
||||
//printf("callMatch() fd: %s, tf: %s\n", fd ? fd.ident.toChars() : "null", toChars(tf));
|
||||
MATCH match = MATCH.exact; // assume exact match
|
||||
ubyte wildmatch = 0;
|
||||
|
||||
|
@ -820,7 +822,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
|
|||
Expression arg = args[u];
|
||||
if (!arg)
|
||||
continue; // default argument
|
||||
m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
|
||||
m = argumentMatchParameter(fd, tf, p, arg, wildmatch, flag, sc, pMessage);
|
||||
if (failMessage)
|
||||
{
|
||||
buf.reset();
|
||||
|
@ -887,14 +889,15 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
|
|||
*
|
||||
* This is done by seeing if a call to the copy constructor can be made:
|
||||
* ```
|
||||
* typeof(tprm) __copytmp;
|
||||
* copytmp.__copyCtor(arg);
|
||||
* typeof(tprm) __copytemp;
|
||||
* copytemp.__copyCtor(arg);
|
||||
* ```
|
||||
*/
|
||||
private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
|
||||
Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
|
||||
{
|
||||
auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
|
||||
//printf("isCopyConstructorCallable() argStruct: %s arg: %s tprm: %s\n", argStruct.toChars(), toChars(arg), toChars(tprm));
|
||||
auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytemp"), null);
|
||||
tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
|
||||
tmp.dsymbolSemantic(sc);
|
||||
Expression ve = new VarExp(arg.loc, tmp);
|
||||
|
@ -980,25 +983,28 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
|
|||
*
|
||||
* This function is called by `TypeFunction.callMatch` while iterating over
|
||||
* the list of parameter. Here we check if `arg` is a match for `p`,
|
||||
* which is mostly about checking if `arg.type` converts to `p`'s type
|
||||
* which is mostly about checking if `arg.type` converts to type of `p`
|
||||
* and some check about value reference.
|
||||
*
|
||||
* Params:
|
||||
* fd = the function being called if symbol, null if not
|
||||
* tf = The `TypeFunction`, only used for error reporting
|
||||
* p = The parameter of `tf` being matched
|
||||
* arg = Argument being passed (bound) to `p`
|
||||
* wildmatch = Wild (`inout`) matching level, derived from the full argument list
|
||||
* flag = A non-zero value means we're doing a partial ordering check
|
||||
* flag = A non-zero value means we are doing a partial ordering check
|
||||
* (no value semantic check)
|
||||
* sc = Scope we are in
|
||||
* pMessage = A buffer to write the error in, or `null`
|
||||
*
|
||||
* Returns: Whether `trailingArgs` match `p`.
|
||||
*/
|
||||
private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
|
||||
private extern(D) MATCH argumentMatchParameter (FuncDeclaration fd, TypeFunction tf, Parameter p,
|
||||
Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
|
||||
{
|
||||
//printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
|
||||
static if (0)
|
||||
printf("argumentMatchParameter() sc: %p, fd: %s, tf: %s, p: %s, arg: %s, arg.type: %s\n",
|
||||
sc, fd ? fd.ident.toChars() : "null", tf.toChars(), parameterToChars(p, tf, false), arg.toChars(), arg.type.toChars());
|
||||
MATCH m;
|
||||
Type targ = arg.type;
|
||||
Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
|
||||
|
@ -1013,18 +1019,47 @@ private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
|
|||
else
|
||||
{
|
||||
const isRef = p.isReference();
|
||||
StructDeclaration argStruct, prmStruct;
|
||||
|
||||
// first look for a copy constructor
|
||||
if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
|
||||
StructDeclaration argStruct, prmStruct;
|
||||
if (targ.ty == Tstruct && tprm.ty == Tstruct)
|
||||
{
|
||||
// if the argument and the parameter are of the same unqualified struct type
|
||||
argStruct = (cast(TypeStruct)targ).sym;
|
||||
prmStruct = (cast(TypeStruct)tprm).sym;
|
||||
|
||||
/* if both a copy constructor and move constructor exist, then match
|
||||
* the lvalue to the copy constructor only and the rvalue to the move constructor
|
||||
* only
|
||||
*/
|
||||
if (argStruct == prmStruct && fd)
|
||||
{
|
||||
if (auto cfd = fd.isCtorDeclaration())
|
||||
{
|
||||
/* Get struct that constructor is making
|
||||
*/
|
||||
|
||||
auto t1 = cfd.type.toBasetype();
|
||||
auto t2 = t1.nextOf();
|
||||
auto t3 = t2.isTypeStruct();
|
||||
if (t3)
|
||||
{
|
||||
auto ctorStruct = t3.sym;
|
||||
// StructDeclaration ctorStruct = cfd.type.toBasetype().nextOf().isTypeStruct().sym;
|
||||
|
||||
if (prmStruct == ctorStruct && ctorStruct.hasCopyCtor && ctorStruct.hasMoveCtor)
|
||||
{
|
||||
if (cfd.isCpCtor && !arg.isLvalue())
|
||||
return MATCH.nomatch; // copy constructor is only for lvalues
|
||||
else if (cfd.isMoveCtor && arg.isLvalue())
|
||||
return MATCH.nomatch; // move constructor is only for rvalues
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the copy constructor may be called to copy the argument
|
||||
if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
|
||||
if (arg.isLvalue() && !isRef && argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
|
||||
{
|
||||
if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
|
||||
return MATCH.nomatch;
|
||||
|
@ -4427,6 +4462,10 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
|
|||
*/
|
||||
Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
|
||||
{
|
||||
enum LOGDOTEXP = false;
|
||||
if (LOGDOTEXP)
|
||||
printf("dotExp()\n");
|
||||
|
||||
Expression visitType(Type mt)
|
||||
{
|
||||
VarDeclaration v = null;
|
||||
|
@ -5047,8 +5086,41 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
|
|||
return noMember(mt, sc, e, ident, flag);
|
||||
}
|
||||
// check before alias resolution; the alias itself might be deprecated!
|
||||
if (s.isAliasDeclaration)
|
||||
if (auto ad = s.isAliasDeclaration)
|
||||
{
|
||||
s.checkDeprecated(e.loc, sc);
|
||||
|
||||
// Fix for https://github.com/dlang/dmd/issues/20610
|
||||
if (ad.originalType)
|
||||
{
|
||||
if (auto tid = ad.originalType.isTypeIdentifier())
|
||||
{
|
||||
if (tid.idents.length)
|
||||
{
|
||||
static if (0)
|
||||
{
|
||||
printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
|
||||
printf("AliasDeclaration: %s\n", ad.toChars());
|
||||
if (ad.aliassym)
|
||||
printf("aliassym: %s\n", ad.aliassym.toChars());
|
||||
printf("tid type: %s\n", toChars(tid));
|
||||
}
|
||||
/* Rewrite e.s as e.(tid.ident).(tid.idents)
|
||||
*/
|
||||
Expression die = new DotIdExp(e.loc, e, tid.ident);
|
||||
foreach (id; tid.idents) // maybe use typeToExpressionHelper()
|
||||
die = new DotIdExp(e.loc, die, cast(Identifier)id);
|
||||
/* Ambiguous syntax, only way to disambiguate it to try it
|
||||
*/
|
||||
die = dmd.expressionsem.trySemantic(die, sc);
|
||||
if (die && die.isDotVarExp()) // shrink wrap around DotVarExp()
|
||||
{
|
||||
return die;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s = s.toAlias();
|
||||
|
||||
if (auto em = s.isEnumMember())
|
||||
|
@ -6039,7 +6111,7 @@ Dsymbol toDsymbol(Type type, Scope* sc)
|
|||
|
||||
Dsymbol visitIdentifier(TypeIdentifier type)
|
||||
{
|
||||
//printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
|
||||
//printf("TypeIdentifier::toDsymbol('%s')\n", toChars(type));
|
||||
if (!sc)
|
||||
return null;
|
||||
|
||||
|
@ -6051,7 +6123,6 @@ Dsymbol toDsymbol(Type type, Scope* sc)
|
|||
s = t.toDsymbol(sc);
|
||||
if (e)
|
||||
s = getDsymbol(e);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
19
gcc/testsuite/gdc.dg/copy1.d
Normal file
19
gcc/testsuite/gdc.dg/copy1.d
Normal file
|
@ -0,0 +1,19 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-fno-moduleinfo -fdump-tree-original" }
|
||||
struct S
|
||||
{
|
||||
int i;
|
||||
this(ref S);
|
||||
void opAssign(S s)
|
||||
{
|
||||
i = s.i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void test_opAssign()
|
||||
{
|
||||
S s;
|
||||
S t;
|
||||
// { dg-final { scan-tree-dump-not "&TARGET_EXPR" "original" } }
|
||||
t = s;
|
||||
}
|
28
gcc/testsuite/gdc.test/compilable/aligndefault.d
Normal file
28
gcc/testsuite/gdc.test/compilable/aligndefault.d
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
struct S
|
||||
{
|
||||
align(1)
|
||||
{
|
||||
short x1;
|
||||
int y1;
|
||||
long z1;
|
||||
|
||||
align(default)
|
||||
{
|
||||
short x;
|
||||
int y;
|
||||
long z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fun()
|
||||
{
|
||||
static assert(S.x1.alignof == 1);
|
||||
static assert(S.y1.alignof == 1);
|
||||
static assert(S.z1.alignof == 1);
|
||||
|
||||
static assert(S.x.alignof == short.alignof);
|
||||
static assert(S.y.alignof == int.alignof);
|
||||
static assert(S.z.alignof == long.alignof);
|
||||
}
|
|
@ -564,6 +564,11 @@ ref int* foo(scope return ref int* a) @safe
|
|||
|
||||
struct SafeS
|
||||
{
|
||||
this(int[1] x) scope {}
|
||||
this(int[2] x) return scope {}
|
||||
this(int[3] x) scope return {}
|
||||
this(int[4] x) return {}
|
||||
|
||||
@safe:
|
||||
ref SafeS foo() return
|
||||
{
|
||||
|
|
22
gcc/testsuite/gdc.test/compilable/rvalue2.d
Normal file
22
gcc/testsuite/gdc.test/compilable/rvalue2.d
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* PERMUTE_ARGS: -preview=rvaluerefparam
|
||||
*/
|
||||
|
||||
struct S
|
||||
{
|
||||
alias TT this;
|
||||
long TT();
|
||||
this(T)(int x) {} // works if `int` is `long`
|
||||
|
||||
this(S);
|
||||
this(ref S);
|
||||
|
||||
~this();
|
||||
}
|
||||
|
||||
S fun(ref S arg);
|
||||
|
||||
void test()
|
||||
{
|
||||
S st;
|
||||
fun(st);
|
||||
}
|
|
@ -13,6 +13,10 @@ class A {
|
|||
|
||||
// or normal method defintions
|
||||
bool isNull() => this is null;
|
||||
|
||||
this() {}
|
||||
this(int x) { _x = x; }
|
||||
this(float y) => this(cast(int) y);
|
||||
}
|
||||
|
||||
class B : A{
|
||||
|
@ -36,3 +40,12 @@ void func() {
|
|||
// Issue 24088 - https://issues.dlang.org/show_bug.cgi?id=24088
|
||||
S!int f() => S!int();
|
||||
}
|
||||
|
||||
struct T
|
||||
{
|
||||
void inc() {}
|
||||
this(this) => inc();
|
||||
|
||||
void free() {}
|
||||
~this() => free();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=19227
|
||||
/* TEST_OUTPUT:
|
||||
---
|
||||
compilable/test19227.d(18): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
|
||||
Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
|
||||
Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
|
||||
compilable/test19227.d(16): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
|
||||
Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
|
||||
---
|
||||
*/
|
||||
|
|
|
@ -137,6 +137,8 @@ struct DisabledPostblit
|
|||
struct NoCpCtor { }
|
||||
class C19902 { }
|
||||
|
||||
struct MoveCtor { this(MoveCtor) { } }
|
||||
|
||||
static assert(__traits(hasCopyConstructor, S));
|
||||
static assert(__traits(hasCopyConstructor, OuterS.S));
|
||||
static assert(__traits(hasCopyConstructor, OuterS));
|
||||
|
@ -147,6 +149,8 @@ static assert(__traits(hasCopyConstructor, U!S));
|
|||
static assert(!__traits(hasPostblit, U!S));
|
||||
static assert(__traits(hasPostblit, SPostblit));
|
||||
static assert(!__traits(hasCopyConstructor, SPostblit));
|
||||
static assert(__traits(hasMoveConstructor, MoveCtor));
|
||||
static assert(!__traits(hasMoveConstructor, NoCpCtor));
|
||||
|
||||
static assert(!__traits(hasCopyConstructor, NoCpCtor));
|
||||
static assert(!__traits(hasCopyConstructor, C19902));
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail19871.d(10): Error: `struct Struct` may not define both a rvalue constructor and a copy constructor
|
||||
fail_compilation/fail19871.d(19): rvalue constructor defined here
|
||||
fail_compilation/fail19871.d(13): copy constructor defined here
|
||||
---
|
||||
*/
|
||||
|
||||
struct Struct
|
||||
{
|
||||
@disable this();
|
||||
this(ref Struct other)
|
||||
{
|
||||
const Struct s = void;
|
||||
this(s);
|
||||
}
|
||||
|
||||
this(Struct) {}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail19931.d(10): Error: `struct S` may not define both a rvalue constructor and a copy constructor
|
||||
fail_compilation/fail19931.d(12): rvalue constructor defined here
|
||||
fail_compilation/fail19931.d(13): copy constructor defined here
|
||||
---
|
||||
*/
|
||||
|
||||
struct S
|
||||
{
|
||||
this(S s) {}
|
||||
this(ref S s) {}
|
||||
this(this) {}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=23036
|
||||
|
||||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail23036.d(12): Error: `struct S` may not define both a rvalue constructor and a copy constructor
|
||||
fail_compilation/fail23036.d(15): rvalue constructor defined here
|
||||
fail_compilation/fail23036.d(14): copy constructor defined here
|
||||
---
|
||||
*/
|
||||
|
||||
struct S
|
||||
{
|
||||
this(ref S) {}
|
||||
this(S, int a = 2) {}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S a;
|
||||
S b = a;
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/ice14642.d(47): Error: undefined identifier `errorValue`
|
||||
fail_compilation/ice14642.d(23): Error: template instance `ice14642.X.NA!()` error instantiating
|
||||
fail_compilation/ice14642.d(48): Error: undefined identifier `errorValue`
|
||||
fail_compilation/ice14642.d(52): error on member `ice14642.Z.v`
|
||||
fail_compilation/ice14642.d(24): Error: template instance `ice14642.X.NA!()` error instantiating
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
EXTRA_FILES: imports/ice9865b.d
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/ice9865.d(9): Error: alias `ice9865.Baz` recursive alias declaration
|
||||
fail_compilation/ice9865.d(10): Error: alias `ice9865.Baz` recursive alias declaration
|
||||
fail_compilation/ice9865.d(11): error on member `ice9865.Foo.f`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -53,10 +53,10 @@ public private void f10() {}
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/parseStc2.d(63): Error: redundant alignment attribute `align`
|
||||
fail_compilation/parseStc2.d(63): Error: redundant alignment attribute `align(default)`
|
||||
fail_compilation/parseStc2.d(64): Error: redundant alignment attribute `align(1)`
|
||||
fail_compilation/parseStc2.d(65): Error: redundant alignment attribute `align(1)`
|
||||
fail_compilation/parseStc2.d(66): Error: redundant alignment attribute `align`
|
||||
fail_compilation/parseStc2.d(66): Error: redundant alignment attribute `align(default)`
|
||||
fail_compilation/parseStc2.d(67): Error: redundant alignment attribute `align(2)`
|
||||
---
|
||||
*/
|
||||
|
|
15
gcc/testsuite/gdc.test/fail_compilation/short_fn.d
Normal file
15
gcc/testsuite/gdc.test/fail_compilation/short_fn.d
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/short_fn.d(13): Error: can only return void expression, `this` call or `super` call from constructor
|
||||
fail_compilation/short_fn.d(14): Error: can only return void expression, `this` call or `super` call from constructor
|
||||
---
|
||||
*/
|
||||
|
||||
struct Number
|
||||
{
|
||||
int x;
|
||||
|
||||
this(int x) => this.x = x;
|
||||
this(byte x) => Number();
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test19473.d(14): Error: union `test19473.P` no size because of forward reference
|
||||
fail_compilation/test19473.d(15): Error: union `test19473.P` no size because of forward reference
|
||||
fail_compilation/test19473.d(31): error on member `test19473.P.p`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test20719.d(13): Error: struct `test20719.SumType` no size because of forward reference
|
||||
fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda_L32_C22.foo` - size of type `SumType` is invalid
|
||||
fail_compilation/test20719.d(18): Error: template instance `test20719.isCopyable!(SumType)` error instantiating
|
||||
fail_compilation/test20719.d(14): Error: struct `test20719.SumType` no size because of forward reference
|
||||
fail_compilation/test20719.d(17): error on member `test20719.SumType.storage`
|
||||
fail_compilation/test20719.d(33): Error: variable `test20719.isCopyable!(SumType).__lambda_L33_C22.foo` - size of type `SumType` is invalid
|
||||
fail_compilation/test20719.d(19): Error: template instance `test20719.isCopyable!(SumType)` error instantiating
|
||||
---
|
||||
*/
|
||||
struct SumType
|
||||
|
|
|
@ -15,7 +15,7 @@ template Qual(alias T)
|
|||
alias Qual = T;
|
||||
}
|
||||
|
||||
void test()
|
||||
void test1()
|
||||
{
|
||||
int x = 3;
|
||||
int y = 4;
|
||||
|
@ -25,7 +25,33 @@ void test()
|
|||
assert(XY[1] == 4);
|
||||
}
|
||||
|
||||
void main()
|
||||
/**********************************************/
|
||||
|
||||
struct T
|
||||
{
|
||||
test();
|
||||
int k,i = 2;
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
int x;
|
||||
T t;
|
||||
alias ti = t.i;
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
T t = T(1, 2);
|
||||
S s;
|
||||
assert(s.ti == 2);
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
|
||||
int main()
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
13
gcc/testsuite/gdc.test/runnable/imports/test23722_2b.d
Normal file
13
gcc/testsuite/gdc.test/runnable/imports/test23722_2b.d
Normal file
|
@ -0,0 +1,13 @@
|
|||
module imports.test23722_2b;
|
||||
|
||||
struct T(alias fun) { }
|
||||
|
||||
struct S(int i) {
|
||||
auto t = T!(x => i)();
|
||||
}
|
||||
|
||||
string g() {
|
||||
S!0 s0;
|
||||
S!1 s1;
|
||||
return s1.t.init.mangleof;
|
||||
}
|
|
@ -2491,6 +2491,62 @@ void testDoWhileContinue()
|
|||
while(--i > 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// https://github.com/dlang/dmd/issues/20574
|
||||
|
||||
int test20574x(int i, int y)
|
||||
{
|
||||
return i ? y : y;
|
||||
}
|
||||
|
||||
void test20574()
|
||||
{
|
||||
assert(test20574x(1, 2) == 2);
|
||||
assert(test20574x(0, 2) == 2);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct S8
|
||||
{
|
||||
int x,y,z;
|
||||
}
|
||||
|
||||
int test8x(S8 s)
|
||||
{
|
||||
s = s;
|
||||
return s.y;
|
||||
}
|
||||
|
||||
void test8()
|
||||
{
|
||||
S8 s;
|
||||
s.y = 2;
|
||||
assert(test8x(s) == 2);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct S9
|
||||
{
|
||||
int a,b;
|
||||
~this() { }
|
||||
}
|
||||
|
||||
|
||||
S9 test9x(ref S9 arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
void test9()
|
||||
{
|
||||
S9 s;
|
||||
s.b = 3;
|
||||
S9 t = test9x(s);
|
||||
assert(t.b == 3);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int main()
|
||||
|
@ -2592,6 +2648,9 @@ int main()
|
|||
test21816();
|
||||
test21835();
|
||||
testDoWhileContinue();
|
||||
test20574();
|
||||
test8();
|
||||
test9();
|
||||
|
||||
printf("Success\n");
|
||||
return 0;
|
||||
|
|
|
@ -22,9 +22,35 @@ void test1()
|
|||
assert(&r == s1ptr);
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
// https://github.com/dlang/dmd/issues/20567
|
||||
|
||||
struct S2
|
||||
{
|
||||
int x;
|
||||
this(ref S2 s) { x = s.x; }
|
||||
}
|
||||
|
||||
S2 returnRval(ref S2 arg1, ref S2 arg2, int i)
|
||||
{
|
||||
return i ? arg1 : arg2;
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
S2 s1, s2;
|
||||
s1.x = 3;
|
||||
s2.x = 4;
|
||||
S2 s = returnRval(s1, s2, 0);
|
||||
assert(s.x == 4);
|
||||
s = returnRval(s1, s2, 1);
|
||||
assert(s.x == 3);
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
}
|
||||
|
|
209
gcc/testsuite/gdc.test/runnable/rvalue1.d
Normal file
209
gcc/testsuite/gdc.test/runnable/rvalue1.d
Normal file
|
@ -0,0 +1,209 @@
|
|||
/* PERMUTE_ARGS: -preview=rvaluerefparam
|
||||
/* testing __rvalue */
|
||||
|
||||
import core.stdc.stdio;
|
||||
|
||||
/********************************/
|
||||
|
||||
int foo(int) { printf("foo(int)\n"); return 1; }
|
||||
int foo(ref int) { printf("foo(ref int)\n"); return 2; }
|
||||
|
||||
void test1()
|
||||
{
|
||||
int s;
|
||||
assert(foo(s) == 2);
|
||||
assert(foo(__rvalue(s)) == 1);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
struct S
|
||||
{
|
||||
nothrow:
|
||||
~this() { printf("~this() %p\n", &this); }
|
||||
this(ref S) { printf("this(ref S)\n"); }
|
||||
void opAssign(S) { printf("opAssign(S)\n"); }
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
S s;
|
||||
S t;
|
||||
|
||||
t = __rvalue(s);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
struct S3
|
||||
{
|
||||
int a, b, c;
|
||||
|
||||
this(S3) {}
|
||||
this(ref S3) {}
|
||||
}
|
||||
|
||||
void test3()
|
||||
{
|
||||
S3 s;
|
||||
S3 x = s; // this line causes the compiler to crash
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
struct S4
|
||||
{
|
||||
void* p;
|
||||
|
||||
this(ref S4) { }
|
||||
|
||||
this(S4 s)
|
||||
{
|
||||
assert(&s is &x); // confirm the rvalue reference
|
||||
}
|
||||
}
|
||||
|
||||
__gshared S4 x;
|
||||
|
||||
void test4()
|
||||
{
|
||||
S4 t = __rvalue(x);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
struct S5
|
||||
{
|
||||
this(S5 s) { printf("this(S5 s)\n"); }
|
||||
this(ref inout S5 s) inout { printf("this(ref inout S5 s) inout\n"); }
|
||||
}
|
||||
|
||||
void test5()
|
||||
{
|
||||
S5 t;
|
||||
S5 t1 = t;
|
||||
S5 t2 = __rvalue(t);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
int moveCtor, copyCtor, moveAss, copyAss;
|
||||
|
||||
struct S6
|
||||
{
|
||||
this(S6 s) { ++moveCtor; }
|
||||
this(ref S6 s) { ++copyCtor; }
|
||||
void opAssign(S6 s) { ++moveAss; }
|
||||
void opAssign(ref S6 s) { ++copyAss; }
|
||||
}
|
||||
|
||||
void test6()
|
||||
{
|
||||
S6 x;
|
||||
S6 s = x;
|
||||
// printf("S6 s = x; moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
|
||||
assert(copyCtor == 1);
|
||||
S6 s2 = __rvalue(x);
|
||||
// printf("S6 s2 = __rvalue(x); moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
|
||||
assert(moveCtor == 1);
|
||||
s2 = s;
|
||||
// printf("s2 = s; moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
|
||||
assert(copyAss == 1);
|
||||
s2 = __rvalue(s);
|
||||
// printf("s2 = __rvalue(s); moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
|
||||
assert(moveAss == 1);
|
||||
assert(copyCtor == 1 && moveCtor == 1 && copyAss == 1 && moveAss == 1);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
// https://github.com/dlang/dmd/pull/17050#issuecomment-2543370370
|
||||
|
||||
struct MutableString(size_t E) {}
|
||||
|
||||
struct StringTest
|
||||
{
|
||||
alias toString this;
|
||||
const(char)[] toString() const pure
|
||||
=> null;
|
||||
|
||||
this(StringTest rhs) {}
|
||||
this(ref inout StringTest rhs) inout pure {}
|
||||
|
||||
this(typeof(null)) inout pure {}
|
||||
this(size_t Embed)(MutableString!Embed str) inout {}
|
||||
|
||||
~this() {}
|
||||
}
|
||||
|
||||
|
||||
void test7()
|
||||
{
|
||||
StringTest s = StringTest(null);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
// https://github.com/dlang/dmd/issues/20562
|
||||
|
||||
struct S8
|
||||
{
|
||||
int a,b;
|
||||
this(S8) { printf("this(S)\n"); b = 4; }
|
||||
this(ref S8) { printf("this(ref S)\n"); assert(0); }
|
||||
}
|
||||
|
||||
|
||||
S8 returnRval(ref S8 arg)
|
||||
{
|
||||
static if (0)
|
||||
{
|
||||
/* __copytmp2 = 0 ;
|
||||
_D7rvalue51S6__ctorMFNcKSQxQrZQg call (arg param #__copytmp2);
|
||||
* __HID1 streq 1 __copytmp2;
|
||||
__HID1;
|
||||
*/
|
||||
return arg;
|
||||
}
|
||||
else static if (1)
|
||||
{
|
||||
/* * __HID1 streq 1 * arg;
|
||||
__HID1;
|
||||
*/
|
||||
return __rvalue(arg); // should move-construct the NRVO value
|
||||
}
|
||||
else
|
||||
{
|
||||
/* * t = 0 ;
|
||||
t;
|
||||
_TMP0 = t;
|
||||
_D7rvalue51S6__ctorMFNcSQwQqZQg call (arg param _TMP0);
|
||||
t;
|
||||
*/
|
||||
S8 t = __rvalue(arg);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test8()
|
||||
{
|
||||
S8 s;
|
||||
S8 t = returnRval(s);
|
||||
printf("t.b: %d\n", t.b);
|
||||
assert(t.b == 4);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
int main()
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
test8();
|
||||
|
||||
return 0;
|
||||
}
|
13
gcc/testsuite/gdc.test/runnable/test23036.d
Normal file
13
gcc/testsuite/gdc.test/runnable/test23036.d
Normal file
|
@ -0,0 +1,13 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=23036
|
||||
|
||||
struct S
|
||||
{
|
||||
this(ref S) {}
|
||||
this(S, int a = 2) {}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S a;
|
||||
S b = a;
|
||||
}
|
10
gcc/testsuite/gdc.test/runnable/test23722_2.d
Normal file
10
gcc/testsuite/gdc.test/runnable/test23722_2.d
Normal file
|
@ -0,0 +1,10 @@
|
|||
// COMPILE_SEPARATELY:
|
||||
// EXTRA_SOURCES: imports/test23722_2b.d
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23722
|
||||
// Lambdas are mangled incorrectly when using multiple compilation units, resulting in incorrect code
|
||||
import imports.test23722_2b;
|
||||
|
||||
void main() {
|
||||
S!1 s1;
|
||||
assert(s1.t.init.mangleof == g);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
82a5d2a7c4dd3d270537bcede2981e047bfd0e6a
|
||||
c57da0cf5945cfb45eed06f1fd820435cda3ee3a
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -78,6 +78,8 @@ else version (DigitalMars)
|
|||
return val;
|
||||
}
|
||||
|
||||
/// Execute target dependent trap instruction, if supported.
|
||||
/// Otherwise, abort execution.
|
||||
pragma(inline, true)
|
||||
void trap()
|
||||
{
|
||||
|
@ -90,7 +92,8 @@ else version (DigitalMars)
|
|||
}
|
||||
}
|
||||
|
||||
/// Provide static branch hints
|
||||
/// Provide static branch and value hints for the LDC/GDC compilers.
|
||||
/// DMD ignores these hints.
|
||||
pragma(inline, true) bool likely(bool b) { return !!expect(b, true); }
|
||||
///
|
||||
/// ditto
|
||||
pragma(inline, true) bool unlikely(bool b) { return !!expect(b, false); }
|
||||
|
|
|
@ -190,4 +190,73 @@ interface GC
|
|||
* GC.stats().allocatedInCurrentThread, but faster.
|
||||
*/
|
||||
ulong allocatedInCurrentThread() nothrow;
|
||||
|
||||
// ARRAY FUNCTIONS
|
||||
/**
|
||||
* Get the current used capacity of an array block. Note that this is only
|
||||
* needed if you are about to change the array used size and need to deal
|
||||
* with the memory that is about to go away. For appending or shrinking
|
||||
* arrays that have no destructors, you probably don't need this function.
|
||||
* Params:
|
||||
* ptr = The pointer to check. This can be an interior pointer, but if it
|
||||
* is beyond the end of the used space, the return value may not be
|
||||
* valid.
|
||||
* atomic = If true, the value is fetched atomically (for shared arrays)
|
||||
* Returns: Current array slice, or null if the pointer does not point to a
|
||||
* valid appendable GC block.
|
||||
*/
|
||||
void[] getArrayUsed(void *ptr, bool atomic = false) nothrow;
|
||||
|
||||
/**
|
||||
* Expand the array used size. Used for appending and expanding the length
|
||||
* of the array slice. If the operation can be performed without
|
||||
* reallocating, the function succeeds. Newly expanded data is not
|
||||
* initialized.
|
||||
*
|
||||
* slices that do not point at expandable GC blocks cannot be affected, and
|
||||
* this function will always return false.
|
||||
* Params:
|
||||
* slice = the slice to attempt expanding in place.
|
||||
* newUsed = the size that should be stored as used.
|
||||
* atomic = if true, the array may be shared between threads, and this
|
||||
* operation should be done atomically.
|
||||
* Returns: true if successful.
|
||||
*/
|
||||
bool expandArrayUsed(void[] slice, size_t newUsed, bool atomic = false) nothrow @safe;
|
||||
|
||||
/**
|
||||
* Expand the array capacity. Used for reserving space that can be used for
|
||||
* appending. If the operation can be performed without reallocating, the
|
||||
* function succeeds. The used size is not changed.
|
||||
*
|
||||
* slices that do not point at expandable GC blocks cannot be affected, and
|
||||
* this function will always return zero.
|
||||
* Params:
|
||||
* slice = the slice to attempt reserving capacity for.
|
||||
* request = the requested size to expand to. Includes the existing data.
|
||||
* Passing a value less than the current array size will result in no
|
||||
* changes, but will return the current capacity.
|
||||
* atomic = if true, the array may be shared between threads, and this
|
||||
* operation should be done atomically.
|
||||
* Returns: resulting capacity size, 0 if the operation could not be performed.
|
||||
*/
|
||||
size_t reserveArrayCapacity(void[] slice, size_t request, bool atomic = false) nothrow @safe;
|
||||
|
||||
/**
|
||||
* Shrink used space of a slice. Unlike the other array functions, the
|
||||
* array slice passed in is the target slice, and the existing used space
|
||||
* is passed separately. This is to discourage code that ends up with a
|
||||
* slice to dangling valid data.
|
||||
* If slice.ptr[0 .. existingUsed] does not point to the end of a valid GC
|
||||
* appendable slice, then the operation fails.
|
||||
* Params:
|
||||
* slice = The proposed valid slice data.
|
||||
* existingUsed = The amount of data in the block (starting at slice.ptr)
|
||||
* that is currently valid in the array. If this amount does not match
|
||||
* the current used size, the operation fails.
|
||||
* atomic = If true, the slice may be shared between threads, and the
|
||||
* operation should be atomic.
|
||||
* Returns: true if successful.
|
||||
*/
|
||||
bool shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic = false) nothrow;
|
||||
}
|
||||
|
|
|
@ -264,6 +264,8 @@ void *__arrayStart()(return scope BlkInfo info) nothrow pure
|
|||
bool __setArrayAllocLength(T)(ref BlkInfo info, size_t newLength, bool isShared, size_t oldLength = ~0)
|
||||
{
|
||||
import core.lifetime : TypeInfoSize;
|
||||
import core.internal.gc.blockmeta : __setArrayAllocLengthImpl;
|
||||
return __setArrayAllocLengthImpl(info, newLength, isShared, typeid(T), oldLength, TypeInfoSize!T);
|
||||
import core.internal.gc.blockmeta : __setArrayAllocLengthImpl, __setBlockFinalizerInfo;
|
||||
static if (TypeInfoSize!T)
|
||||
__setBlockFinalizerInfo(info, typeid(T));
|
||||
return __setArrayAllocLengthImpl(info, newLength, isShared, oldLength, TypeInfoSize!T);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ else
|
|||
int __nextBlkIdx;
|
||||
}
|
||||
|
||||
@property BlkInfo *__blkcache() nothrow
|
||||
@property BlkInfo *__blkcache() nothrow @nogc
|
||||
{
|
||||
if (!__blkcache_storage)
|
||||
{
|
||||
|
@ -135,7 +135,7 @@ unittest
|
|||
so any use of the returned BlkInfo should copy it and then check the
|
||||
base ptr of the copy before actually using it.
|
||||
*/
|
||||
BlkInfo *__getBlkInfo(void *interior) nothrow
|
||||
BlkInfo *__getBlkInfo(void *interior) nothrow @nogc
|
||||
{
|
||||
BlkInfo *ptr = __blkcache;
|
||||
if (ptr is null)
|
||||
|
@ -175,7 +175,7 @@ BlkInfo *__getBlkInfo(void *interior) nothrow
|
|||
return null; // not in cache.
|
||||
}
|
||||
|
||||
void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow
|
||||
void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow @nogc
|
||||
{
|
||||
auto cache = __blkcache;
|
||||
if (cache is null)
|
||||
|
@ -241,3 +241,16 @@ void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug(PRINTF)
|
||||
{
|
||||
extern(C) void printArrayCache()
|
||||
{
|
||||
auto ptr = __blkcache;
|
||||
printf("CACHE: \n");
|
||||
foreach (i; 0 .. N_CACHE_BLOCKS)
|
||||
{
|
||||
printf(" %d\taddr:% .8x\tsize:% .10d\tflags:% .8x\n", i, ptr[i].base, ptr[i].size, ptr[i].attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,12 +71,15 @@ size_t structTypeInfoSize(const TypeInfo ti) pure nothrow @nogc
|
|||
*/
|
||||
bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength = ~0) pure nothrow
|
||||
{
|
||||
size_t typeInfoSize = structTypeInfoSize(tinext);
|
||||
return __setArrayAllocLengthImpl(info, newlength, isshared, tinext, oldlength, typeInfoSize);
|
||||
size_t typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
|
||||
if (typeInfoSize)
|
||||
__setBlockFinalizerInfo(info, tinext);
|
||||
|
||||
return __setArrayAllocLengthImpl(info, newlength, isshared, oldlength, typeInfoSize);
|
||||
}
|
||||
|
||||
// the impl function, used both above and in core.internal.array.utils
|
||||
bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength, size_t typeInfoSize) pure nothrow
|
||||
bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared, size_t oldlength, size_t typeInfoSize) pure nothrow
|
||||
{
|
||||
import core.atomic;
|
||||
|
||||
|
@ -113,11 +116,6 @@ bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared
|
|||
// setting the initial length, no cas needed
|
||||
*length = cast(ubyte)newlength;
|
||||
}
|
||||
if (typeInfoSize)
|
||||
{
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
|
||||
*typeInfo = cast() tinext;
|
||||
}
|
||||
}
|
||||
else if (info.size < PAGESIZE)
|
||||
{
|
||||
|
@ -144,11 +142,6 @@ bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared
|
|||
// setting the initial length, no cas needed
|
||||
*length = cast(ushort)newlength;
|
||||
}
|
||||
if (typeInfoSize)
|
||||
{
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
|
||||
*typeInfo = cast() tinext;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -175,29 +168,80 @@ bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared
|
|||
// setting the initial length, no cas needed
|
||||
*length = newlength;
|
||||
}
|
||||
if (typeInfoSize)
|
||||
{
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof);
|
||||
*typeInfo = cast()tinext;
|
||||
}
|
||||
}
|
||||
return true; // resize succeeded
|
||||
}
|
||||
|
||||
/**
|
||||
get the allocation size of the array for the given block (without padding or type info)
|
||||
The block finalizer info is set separately from the array length, as that is
|
||||
only needed on the initial setup of the block. No shared is needed, since
|
||||
this should only happen when the block is new.
|
||||
*/
|
||||
size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow
|
||||
void __setBlockFinalizerInfo(ref BlkInfo info, const TypeInfo ti) pure nothrow
|
||||
{
|
||||
if ((info.attr & BlkAttr.APPENDABLE) && info.size >= PAGESIZE)
|
||||
{
|
||||
// array used size goes at the beginning. We can stuff the typeinfo
|
||||
// right after it, as we need to use 16 bytes anyway.
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof);
|
||||
*typeInfo = cast() ti;
|
||||
}
|
||||
else
|
||||
{
|
||||
// all other cases the typeinfo gets put at the end of the block
|
||||
auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
|
||||
*typeInfo = cast() ti;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
get the used size of the array for the given block
|
||||
*/
|
||||
size_t __arrayAllocLength(ref BlkInfo info) pure nothrow
|
||||
in(info.attr & BlkAttr.APPENDABLE)
|
||||
{
|
||||
auto typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
|
||||
if (info.size <= 256)
|
||||
return *cast(ubyte *)(info.base + info.size - structTypeInfoSize(tinext) - SMALLPAD);
|
||||
return *cast(ubyte *)(info.base + info.size - typeInfoSize - SMALLPAD);
|
||||
|
||||
if (info.size < PAGESIZE)
|
||||
return *cast(ushort *)(info.base + info.size - structTypeInfoSize(tinext) - MEDPAD);
|
||||
return *cast(ushort *)(info.base + info.size - typeInfoSize - MEDPAD);
|
||||
|
||||
return *cast(size_t *)(info.base);
|
||||
}
|
||||
|
||||
/**
|
||||
Atomically get the used size of the array for the given block
|
||||
*/
|
||||
size_t __arrayAllocLengthAtomic(ref BlkInfo info) pure nothrow
|
||||
in(info.attr & BlkAttr.APPENDABLE)
|
||||
{
|
||||
import core.atomic;
|
||||
auto typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
|
||||
if (info.size <= 256)
|
||||
return atomicLoad(*cast(shared(ubyte)*)(info.base + info.size - typeInfoSize - SMALLPAD));
|
||||
|
||||
if (info.size < PAGESIZE)
|
||||
return atomicLoad(*cast(shared(ushort)*)(info.base + info.size - typeInfoSize - MEDPAD));
|
||||
|
||||
return atomicLoad(*cast(shared(size_t)*)(info.base));
|
||||
}
|
||||
|
||||
/**
|
||||
Get the maximum bytes that can be stored in the given block.
|
||||
*/
|
||||
size_t __arrayAllocCapacity(ref BlkInfo info) pure nothrow
|
||||
in(info.attr & BlkAttr.APPENDABLE)
|
||||
{
|
||||
// Capacity is a calculation based solely on the block info.
|
||||
if (info.size >= PAGESIZE)
|
||||
return info.size - LARGEPAD;
|
||||
|
||||
auto typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
|
||||
auto padsize = info.size <= 256 ? SMALLPAD : MEDPAD;
|
||||
return info.size - typeInfoSize - padsize;
|
||||
}
|
||||
|
||||
/**
|
||||
get the padding required to allocate size bytes. Note that the padding is
|
||||
NOT included in the passed in size. Therefore, do NOT call this function
|
||||
|
|
|
@ -1377,6 +1377,193 @@ class ConservativeGC : GC
|
|||
stats.freeSize += freeListSize;
|
||||
stats.allocatedInCurrentThread = bytesAllocated;
|
||||
}
|
||||
|
||||
// ARRAY FUNCTIONS
|
||||
void[] getArrayUsed(void *ptr, bool atomic = false) nothrow
|
||||
{
|
||||
import core.internal.gc.blockmeta;
|
||||
import core.internal.gc.blkcache;
|
||||
import core.internal.array.utils;
|
||||
|
||||
// lookup the block info, using the cache if possible.
|
||||
auto bic = atomic ? null : __getBlkInfo(ptr);
|
||||
auto info = bic ? *bic : query(ptr);
|
||||
|
||||
if (!(info.attr & BlkAttr.APPENDABLE))
|
||||
// not appendable
|
||||
return null;
|
||||
|
||||
assert(info.base); // sanity check.
|
||||
if (!bic && !atomic)
|
||||
// cache the lookup for next time
|
||||
__insertBlkInfoCache(info, null);
|
||||
|
||||
auto usedSize = atomic ? __arrayAllocLengthAtomic(info) : __arrayAllocLength(info);
|
||||
return __arrayStart(info)[0 .. usedSize];
|
||||
}
|
||||
|
||||
/* NOTE about @trusted in these functions:
|
||||
* These functions do a lot of pointer manipulation, and has writeable
|
||||
* access to BlkInfo which is used to interface with other parts of the GC,
|
||||
* including the block metadata and block cache. Marking these functions as
|
||||
* @safe would mean that any modification of BlkInfo fields should be
|
||||
* considered @safe, which is not the case. For example, it would be
|
||||
* perfectly legal to change the BlkInfo size to some huge number, and then
|
||||
* store it in the block cache to blow up later. The utility functions
|
||||
* count on the BlkInfo representing the correct information inside the GC.
|
||||
*
|
||||
* In order to mark these @safe, we would need a BlkInfo that has
|
||||
* restrictive access (i.e. @system only) to the information inside the
|
||||
* BlkInfo. Until then any use of these structures needs to be @trusted,
|
||||
* and therefore the entire functions are @trusted. The API is still @safe
|
||||
* because the information is stored and looked up by the GC, not the
|
||||
* caller.
|
||||
*/
|
||||
bool expandArrayUsed(void[] slice, size_t newUsed, bool atomic = false) nothrow @trusted
|
||||
{
|
||||
import core.internal.gc.blockmeta;
|
||||
import core.internal.gc.blkcache;
|
||||
import core.internal.array.utils;
|
||||
|
||||
if (newUsed < slice.length)
|
||||
// cannot "expand" by shrinking.
|
||||
return false;
|
||||
|
||||
// lookup the block info, using the cache if possible
|
||||
auto bic = atomic ? null : __getBlkInfo(slice.ptr);
|
||||
auto info = bic ? *bic : query(slice.ptr);
|
||||
|
||||
if (!(info.attr & BlkAttr.APPENDABLE))
|
||||
// not appendable
|
||||
return false;
|
||||
|
||||
assert(info.base); // sanity check.
|
||||
|
||||
immutable offset = slice.ptr - __arrayStart(info);
|
||||
newUsed += offset;
|
||||
auto existingUsed = slice.length + offset;
|
||||
|
||||
size_t typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
|
||||
if (__setArrayAllocLengthImpl(info, offset + newUsed, atomic, existingUsed, typeInfoSize))
|
||||
{
|
||||
// could expand without extending
|
||||
if (!bic && !atomic)
|
||||
// cache the lookup for next time
|
||||
__insertBlkInfoCache(info, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if we got here, just setting the used size did not work.
|
||||
if (info.size < PAGESIZE)
|
||||
// nothing else we can do
|
||||
return false;
|
||||
|
||||
// try extending the block into subsequent pages.
|
||||
immutable requiredExtension = newUsed - info.size - LARGEPAD;
|
||||
auto extendedSize = extend(info.base, requiredExtension, requiredExtension, null);
|
||||
if (extendedSize == 0)
|
||||
// could not extend, can't satisfy the request
|
||||
return false;
|
||||
|
||||
info.size = extendedSize;
|
||||
if (bic)
|
||||
*bic = info;
|
||||
else if (!atomic)
|
||||
__insertBlkInfoCache(info, null);
|
||||
|
||||
// this should always work.
|
||||
return __setArrayAllocLengthImpl(info, newUsed, atomic, existingUsed, typeInfoSize);
|
||||
}
|
||||
|
||||
bool shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic = false) nothrow
|
||||
{
|
||||
import core.internal.gc.blockmeta;
|
||||
import core.internal.gc.blkcache;
|
||||
import core.internal.array.utils;
|
||||
|
||||
if (existingUsed < slice.length)
|
||||
// cannot "shrink" by growing.
|
||||
return false;
|
||||
|
||||
// lookup the block info, using the cache if possible.
|
||||
auto bic = atomic ? null : __getBlkInfo(slice.ptr);
|
||||
auto info = bic ? *bic : query(slice.ptr);
|
||||
|
||||
if (!(info.attr & BlkAttr.APPENDABLE))
|
||||
// not appendable
|
||||
return false;
|
||||
|
||||
assert(info.base); // sanity check
|
||||
|
||||
immutable offset = slice.ptr - __arrayStart(info);
|
||||
existingUsed += offset;
|
||||
auto newUsed = slice.length + offset;
|
||||
|
||||
size_t typeInfoSize = (info.attr & BlkAttr.STRUCTFINAL) ? size_t.sizeof : 0;
|
||||
|
||||
if (__setArrayAllocLengthImpl(info, newUsed, atomic, existingUsed, typeInfoSize))
|
||||
{
|
||||
if (!bic && !atomic)
|
||||
__insertBlkInfoCache(info, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t reserveArrayCapacity(void[] slice, size_t request, bool atomic = false) nothrow @trusted
|
||||
{
|
||||
import core.internal.gc.blockmeta;
|
||||
import core.internal.gc.blkcache;
|
||||
import core.internal.array.utils;
|
||||
|
||||
// lookup the block info, using the cache if possible.
|
||||
auto bic = atomic ? null : __getBlkInfo(slice.ptr);
|
||||
auto info = bic ? *bic : query(slice.ptr);
|
||||
|
||||
if (!(info.attr & BlkAttr.APPENDABLE))
|
||||
// not appendable
|
||||
return 0;
|
||||
|
||||
assert(info.base); // sanity check
|
||||
|
||||
immutable offset = slice.ptr - __arrayStart(info);
|
||||
request += offset;
|
||||
auto existingUsed = slice.length + offset;
|
||||
|
||||
// make sure this slice ends at the used space
|
||||
auto blockUsed = atomic ? __arrayAllocLengthAtomic(info) : __arrayAllocLength(info);
|
||||
if (existingUsed != blockUsed)
|
||||
// not an expandable slice.
|
||||
return 0;
|
||||
|
||||
// see if the capacity can contain the existing data
|
||||
auto existingCapacity = __arrayAllocCapacity(info);
|
||||
if (existingCapacity < request)
|
||||
{
|
||||
if (info.size < PAGESIZE)
|
||||
// no possibility to extend
|
||||
return 0;
|
||||
|
||||
immutable requiredExtension = request - existingCapacity;
|
||||
auto extendedSize = extend(info.base, requiredExtension, requiredExtension, null);
|
||||
if (extendedSize == 0)
|
||||
// could not extend, can't satisfy the request
|
||||
return 0;
|
||||
|
||||
info.size = extendedSize;
|
||||
|
||||
// update the block info cache if it was used
|
||||
if (bic)
|
||||
*bic = info;
|
||||
else if (!atomic)
|
||||
__insertBlkInfoCache(info, null);
|
||||
|
||||
existingCapacity = __arrayAllocCapacity(info);
|
||||
}
|
||||
|
||||
return existingCapacity - offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -267,4 +267,24 @@ class ManualGC : GC
|
|||
{
|
||||
return typeof(return).init;
|
||||
}
|
||||
|
||||
void[] getArrayUsed(void *ptr, bool atomic = false) nothrow
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
bool expandArrayUsed(void[] slice, size_t newUsed, bool atomic = false) nothrow @safe
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t reserveArrayCapacity(void[] slice, size_t request, bool atomic = false) nothrow @safe
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic = false) nothrow
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,4 +241,24 @@ class ProtoGC : GC
|
|||
{
|
||||
return stats().allocatedInCurrentThread;
|
||||
}
|
||||
|
||||
void[] getArrayUsed(void *ptr, bool atomic = false) nothrow
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
bool expandArrayUsed(void[] slice, size_t newUsed, bool atomic = false) nothrow @safe
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t reserveArrayCapacity(void[] slice, size_t request, bool atomic = false) nothrow @safe
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic = false) nothrow
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,6 +246,26 @@ extern (C)
|
|||
return instance.allocatedInCurrentThread();
|
||||
}
|
||||
|
||||
void[] gc_getArrayUsed(void *ptr, bool atomic) nothrow
|
||||
{
|
||||
return instance.getArrayUsed( ptr, atomic );
|
||||
}
|
||||
|
||||
bool gc_expandArrayUsed(void[] slice, size_t newUsed, bool atomic) nothrow
|
||||
{
|
||||
return instance.expandArrayUsed( slice, newUsed, atomic );
|
||||
}
|
||||
|
||||
size_t gc_reserveArrayCapacity(void[] slice, size_t request, bool atomic) nothrow
|
||||
{
|
||||
return instance.reserveArrayCapacity( slice, request, atomic );
|
||||
}
|
||||
|
||||
bool gc_shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic) nothrow
|
||||
{
|
||||
return instance.shrinkArrayUsed( slice, existingUsed, atomic );
|
||||
}
|
||||
|
||||
GC gc_getProxy() nothrow
|
||||
{
|
||||
return instance;
|
||||
|
|
|
@ -538,18 +538,173 @@ unittest
|
|||
|
||||
template hasIndirections(T)
|
||||
{
|
||||
static if (is(T == struct) || is(T == union))
|
||||
static if (is(T == enum))
|
||||
enum hasIndirections = hasIndirections!(OriginalType!T);
|
||||
else static if (is(T == struct) || is(T == union))
|
||||
enum hasIndirections = anySatisfy!(.hasIndirections, typeof(T.tupleof));
|
||||
else static if (__traits(isAssociativeArray, T) || is(T == class) || is(T == interface))
|
||||
enum hasIndirections = true;
|
||||
else static if (is(T == E[N], E, size_t N))
|
||||
enum hasIndirections = T.sizeof && is(E == void) ? true : hasIndirections!(BaseElemOf!E);
|
||||
enum hasIndirections = T.sizeof && (is(E == void) || hasIndirections!(BaseElemOf!E));
|
||||
else static if (isFunctionPointer!T)
|
||||
enum hasIndirections = false;
|
||||
else
|
||||
enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T;
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
static assert(!hasIndirections!int);
|
||||
static assert(!hasIndirections!(const int));
|
||||
|
||||
static assert( hasIndirections!(int*));
|
||||
static assert( hasIndirections!(const int*));
|
||||
|
||||
static assert( hasIndirections!(int[]));
|
||||
static assert(!hasIndirections!(int[42]));
|
||||
static assert(!hasIndirections!(int[0]));
|
||||
|
||||
static assert( hasIndirections!(int*));
|
||||
static assert( hasIndirections!(int*[]));
|
||||
static assert( hasIndirections!(int*[42]));
|
||||
static assert(!hasIndirections!(int*[0]));
|
||||
|
||||
static assert( hasIndirections!string);
|
||||
static assert( hasIndirections!(string[]));
|
||||
static assert( hasIndirections!(string[42]));
|
||||
static assert(!hasIndirections!(string[0]));
|
||||
|
||||
static assert( hasIndirections!(void[]));
|
||||
static assert( hasIndirections!(void[17]));
|
||||
static assert(!hasIndirections!(void[0]));
|
||||
|
||||
static assert( hasIndirections!(string[int]));
|
||||
static assert( hasIndirections!(string[int]*));
|
||||
static assert( hasIndirections!(string[int][]));
|
||||
static assert( hasIndirections!(string[int][12]));
|
||||
static assert(!hasIndirections!(string[int][0]));
|
||||
|
||||
static assert(!hasIndirections!(int function(string)));
|
||||
static assert( hasIndirections!(int delegate(string)));
|
||||
static assert(!hasIndirections!(const(int function(string))));
|
||||
static assert( hasIndirections!(const(int delegate(string))));
|
||||
static assert(!hasIndirections!(immutable(int function(string))));
|
||||
static assert( hasIndirections!(immutable(int delegate(string))));
|
||||
|
||||
static class C {}
|
||||
static assert( hasIndirections!C);
|
||||
|
||||
static interface I {}
|
||||
static assert( hasIndirections!I);
|
||||
|
||||
{
|
||||
enum E : int { a }
|
||||
static assert(!hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : int* { a }
|
||||
static assert( hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : string { a = "" }
|
||||
static assert( hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : int[] { a = null }
|
||||
static assert( hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : int[3] { a = [1, 2, 3] }
|
||||
static assert(!hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : int*[3] { a = [null, null, null] }
|
||||
static assert( hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : int*[0] { a = int*[0].init }
|
||||
static assert(!hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : C { a = null }
|
||||
static assert( hasIndirections!E);
|
||||
}
|
||||
{
|
||||
enum E : I { a = null }
|
||||
static assert( hasIndirections!E);
|
||||
}
|
||||
|
||||
{
|
||||
static struct S {}
|
||||
static assert(!hasIndirections!S);
|
||||
|
||||
enum E : S { a = S.init }
|
||||
static assert(!hasIndirections!S);
|
||||
}
|
||||
{
|
||||
static struct S { int i; }
|
||||
static assert(!hasIndirections!S);
|
||||
|
||||
enum E : S { a = S.init }
|
||||
static assert(!hasIndirections!S);
|
||||
}
|
||||
{
|
||||
static struct S { C c; }
|
||||
static assert( hasIndirections!S);
|
||||
|
||||
enum E : S { a = S.init }
|
||||
static assert( hasIndirections!S);
|
||||
}
|
||||
{
|
||||
static struct S { int[] arr; }
|
||||
static assert( hasIndirections!S);
|
||||
|
||||
enum E : S { a = S.init }
|
||||
static assert( hasIndirections!S);
|
||||
}
|
||||
{
|
||||
int local;
|
||||
struct S { void foo() { ++local; } }
|
||||
static assert( hasIndirections!S);
|
||||
|
||||
enum E : S { a = S.init }
|
||||
static assert( hasIndirections!S);
|
||||
}
|
||||
|
||||
{
|
||||
static union U {}
|
||||
static assert(!hasIndirections!U);
|
||||
}
|
||||
{
|
||||
static union U { int i; }
|
||||
static assert(!hasIndirections!U);
|
||||
}
|
||||
{
|
||||
static union U { C c; }
|
||||
static assert( hasIndirections!U);
|
||||
}
|
||||
{
|
||||
static union U { int[] arr; }
|
||||
static assert( hasIndirections!U);
|
||||
}
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=12000
|
||||
@safe unittest
|
||||
{
|
||||
static struct S(T)
|
||||
{
|
||||
static assert(hasIndirections!T);
|
||||
}
|
||||
|
||||
static class A(T)
|
||||
{
|
||||
S!A a;
|
||||
}
|
||||
|
||||
A!int dummy;
|
||||
}
|
||||
|
||||
template hasUnsharedIndirections(T)
|
||||
{
|
||||
static if (is(T == immutable))
|
||||
|
|
|
@ -475,6 +475,7 @@ else version (Darwin)
|
|||
enum F_UNLCK = 2;
|
||||
enum F_WRLCK = 3;
|
||||
|
||||
enum O_NOFOLLOW = 0x0100;
|
||||
enum O_CREAT = 0x0200;
|
||||
enum O_EXCL = 0x0800;
|
||||
enum O_NOCTTY = 0;
|
||||
|
|
|
@ -15,7 +15,7 @@ pragma(lib, "advapi32");
|
|||
|
||||
import core.sys.windows.accctrl, core.sys.windows.basetyps, core.sys.windows.w32api, core.sys.windows.winnt;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
VOID BuildExplicitAccessWithNameA(PEXPLICIT_ACCESS_A, LPSTR, DWORD,
|
||||
ACCESS_MODE, DWORD);
|
||||
VOID BuildExplicitAccessWithNameW(PEXPLICIT_ACCESS_W, LPWSTR, DWORD,
|
||||
|
|
|
@ -114,7 +114,7 @@ alias ISecurityInformation LPSECURITYINFO;
|
|||
// FIXME: linkage attribute?
|
||||
extern (C) /+DECLSPEC_IMPORT+/ extern const IID IID_ISecurityInformation;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
HPROPSHEETPAGE CreateSecurityPage(LPSECURITYINFO psi);
|
||||
BOOL EditSecurity(HWND hwndOwner, LPSECURITYINFO psi);
|
||||
}
|
||||
|
|
|
@ -5014,7 +5014,7 @@ BOOL Animate_Seek(HWND hwnd, int frame) {
|
|||
return Animate_Play(hwnd, frame, frame, 1);
|
||||
}
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
HBITMAP CreateMappedBitmap(HINSTANCE, INT_PTR, UINT, LPCOLORMAP, int);
|
||||
HWND CreateStatusWindowA(LONG, LPCSTR, HWND, UINT);
|
||||
HWND CreateStatusWindowW(LONG, LPCWSTR, HWND, UINT);
|
||||
|
@ -5068,7 +5068,7 @@ BOOL DateTime_SetSystemtime(HWND hwnd, WPARAM flag, LPSYSTEMTIME lpSysTime) {
|
|||
cast(LPARAM) lpSysTime);
|
||||
}
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
void DrawInsert(HWND, HWND, int);
|
||||
void DrawStatusTextA(HDC, LPRECT, LPCSTR, UINT);
|
||||
void DrawStatusTextW(HDC, LPRECT, LPCWSTR, UINT);
|
||||
|
@ -5142,7 +5142,7 @@ static if (_WIN32_IE >= 0x400) {
|
|||
}
|
||||
}
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
HDSA DSA_Create(INT, INT);
|
||||
BOOL DSA_Destroy(HDSA);
|
||||
VOID DSA_DestroyCallback(HDSA, PFNDSAENUMCALLBACK, PVOID);
|
||||
|
@ -5758,7 +5758,7 @@ BOOL MonthCal_SetRange(HWND w, DWORD f, LPSYSTEMTIME st) {
|
|||
cast(LPARAM) st);
|
||||
}
|
||||
|
||||
extern (Windows) BOOL ShowHideMenuCtl(HWND, UINT_PTR, PINT);
|
||||
extern (Windows) nothrow @nogc BOOL ShowHideMenuCtl(HWND, UINT_PTR, PINT);
|
||||
|
||||
BOOL TabCtrl_GetItem(HWND w, int i, LPTCITEM p) {
|
||||
return cast(BOOL) SendMessage(w, TCM_GETITEM, i, cast(LPARAM) p);
|
||||
|
@ -6069,7 +6069,7 @@ static if (_WIN32_IE >= 0x300) {
|
|||
return cast(BOOL) SendMessage(w, LVM_SETITEMCOUNT, i, cast(LPARAM) f);
|
||||
}
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
WINBOOL ImageList_SetImageCount(HIMAGELIST, UINT);
|
||||
WINBOOL ImageList_Copy(HIMAGELIST, int, HIMAGELIST, int, UINT);
|
||||
WINBOOL ImageList_DrawIndirect(IMAGELISTDRAWPARAMS*);
|
||||
|
|
|
@ -99,6 +99,7 @@ extern (Windows) {
|
|||
alias INT function(DWORD, DWORD, HFONT, LPWSTR) LPFNCCSIZETOTEXTW;
|
||||
alias UINT function(LPCCINFOA) LPFNCCINFOA;
|
||||
alias UINT function(LPCCINFOW) LPFNCCINFOW;
|
||||
nothrow @nogc:
|
||||
UINT CustomControlInfoA(LPCCINFOA acci);
|
||||
UINT CustomControlInfoW(LPCCINFOW acci);
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ deprecated struct DDEUP {
|
|||
@property bool fAckReq(bool f) { _bf = cast(ushort) ((_bf & ~0x8000) | (f << 15)); return f; }
|
||||
}
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
BOOL DdeSetQualityOfService(HWND, const(SECURITY_QUALITY_OF_SERVICE)*,
|
||||
PSECURITY_QUALITY_OF_SERVICE);
|
||||
BOOL ImpersonateDdeClientWindow(HWND, HWND);
|
||||
|
|
|
@ -332,7 +332,7 @@ struct MONMSGSTRUCT {
|
|||
}
|
||||
alias MONMSGSTRUCT* PMONMSGSTRUCT;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
BOOL DdeAbandonTransaction(DWORD, HCONV, DWORD);
|
||||
PBYTE DdeAccessData(HDDEDATA, PDWORD);
|
||||
HDDEDATA DdeAddData(HDDEDATA, PBYTE, DWORD, DWORD);
|
||||
|
|
|
@ -45,7 +45,7 @@ struct DHCPCAPI_PARAMS_ARRAY {
|
|||
}
|
||||
alias DHCPCAPI_PARAMS_ARRAY* PDHCPCAPI_PARAMS_ARRAY, LPDHCPCAPI_PARAMS_ARRAY;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
void DhcpCApiCleanup();
|
||||
DWORD DhcpCApiInitialize(LPDWORD);
|
||||
DWORD DhcpDeRegisterParamChange(DWORD, LPVOID, LPVOID);
|
||||
|
|
|
@ -29,7 +29,7 @@ enum EFaultRepRetVal {
|
|||
frrvOkHeadless // = 7
|
||||
}
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
BOOL AddERExcludedApplicationA(LPCSTR);
|
||||
BOOL AddERExcludedApplicationW(LPCWSTR);
|
||||
EFaultRepRetVal ReportFault(LPEXCEPTION_POINTERS, DWORD);
|
||||
|
|
|
@ -109,7 +109,7 @@ struct HSE_SEND_HEADER_EX_INFO {
|
|||
}
|
||||
alias HSE_SEND_HEADER_EX_INFO* LPHSE_SEND_HEADER_EX_INF;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
BOOL GetExtensionVersion(HSE_VERSION_INFO*);
|
||||
DWORD HttpExtensionProc(EXTENSION_CONTROL_BLOCK*);
|
||||
BOOL TerminateExtension(DWORD);
|
||||
|
|
|
@ -295,6 +295,7 @@ extern (Windows) {
|
|||
alias BOOL function(DIGEST_HANDLE refdata, PBYTE pData, DWORD dwLength)
|
||||
DIGEST_FUNCTION;
|
||||
|
||||
nothrow @nogc:
|
||||
PIMAGE_NT_HEADERS CheckSumMappedFile(LPVOID, DWORD, LPDWORD, LPDWORD);
|
||||
DWORD MapFileAndCheckSumA(LPSTR, LPDWORD, LPDWORD);
|
||||
DWORD MapFileAndCheckSumW(PWSTR, LPDWORD, LPDWORD);
|
||||
|
|
|
@ -70,7 +70,7 @@ interface IUniformResourceLocator : IUnknown {
|
|||
alias IUniformResourceLocator PIUniformResourceLocator,
|
||||
PCIUniformResourceLocator;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
BOOL InetIsOffline(DWORD);
|
||||
HRESULT MIMEAssociationDialogA(HWND, DWORD, PCSTR, PCSTR, PSTR, UINT);
|
||||
HRESULT MIMEAssociationDialogW(HWND, DWORD, PCWSTR, PCWSTR, PWSTR, UINT);
|
||||
|
|
|
@ -13,7 +13,7 @@ version (Windows):
|
|||
import core.sys.windows.ipexport, core.sys.windows.iprtrmib, core.sys.windows.iptypes;
|
||||
import core.sys.windows.winbase, core.sys.windows.windef;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
DWORD AddIPAddress(IPAddr, IPMask, DWORD, PULONG, PULONG);
|
||||
DWORD CreateIpForwardEntry(PMIB_IPFORWARDROW);
|
||||
DWORD CreateIpNetEntry(PMIB_IPNETROW);
|
||||
|
|
|
@ -708,7 +708,7 @@ struct NETLOGON_INFO_3{
|
|||
}
|
||||
alias NETLOGON_INFO_3* PNETLOGON_INFO_3;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
deprecated {
|
||||
/* These are obsolete */
|
||||
NET_API_STATUS NetAccessAdd(LPCWSTR,DWORD,PBYTE,PDWORD);
|
||||
|
|
|
@ -71,7 +71,7 @@ struct USER_OTHER_INFO{
|
|||
}
|
||||
alias USER_OTHER_INFO* PUSER_OTHER_INFO, LPUSER_OTHER_INFO;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
NET_API_STATUS NetAlertRaise(LPCWSTR,PVOID,DWORD);
|
||||
NET_API_STATUS NetAlertRaiseEx(LPCWSTR,PVOID,DWORD,LPCWSTR);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ pragma(lib, "netapi32");
|
|||
|
||||
import core.sys.windows.lmcons, core.sys.windows.windef;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
NET_API_STATUS NetApiBufferAllocate(DWORD, PVOID*);
|
||||
NET_API_STATUS NetApiBufferFree(PVOID);
|
||||
NET_API_STATUS NetApiBufferReallocate(PVOID, DWORD, PVOID*);
|
||||
|
|
|
@ -32,7 +32,7 @@ struct MSG_INFO_1 {
|
|||
}
|
||||
alias MSG_INFO_1* PMSG_INFO_1, LPMSG_INFO_1;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
NET_API_STATUS NetMessageBufferSend(LPCWSTR, LPCWSTR, LPCWSTR, PBYTE,
|
||||
DWORD);
|
||||
NET_API_STATUS NetMessageNameAdd(LPCWSTR, LPCWSTR);
|
||||
|
|
|
@ -52,7 +52,7 @@ struct TIME_OF_DAY_INFO {
|
|||
}
|
||||
alias TIME_OF_DAY_INFO* PTIME_OF_DAY_INFO, LPTIME_OF_DAY_INFO;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
NET_API_STATUS NetRemoteTOD(LPCWSTR, PBYTE*);
|
||||
NET_API_STATUS NetRemoteComputerSupports(LPCWSTR, DWORD, PDWORD);
|
||||
NET_API_STATUS RxRemoteApi(DWORD, LPCWSTR, LPDESC, LPDESC, LPDESC,
|
||||
|
|
|
@ -29,7 +29,7 @@ enum MGMCTL_SETAGENTPORT = 1;
|
|||
|
||||
alias PVOID LPSNMP_MGR_SESSION;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
BOOL SnmpMgrClose(LPSNMP_MGR_SESSION);
|
||||
BOOL SnmpMgrCtl(LPSNMP_MGR_SESSION, DWORD, LPVOID, DWORD, LPVOID, DWORD,
|
||||
LPDWORD);
|
||||
|
|
|
@ -19,4 +19,4 @@ enum SHUTDOWN_ACTION {
|
|||
ShutdownPowerOff
|
||||
}
|
||||
|
||||
extern (Windows) uint NtShutdownSystem(SHUTDOWN_ACTION Action);
|
||||
extern (Windows) nothrow @nogc uint NtShutdownSystem(SHUTDOWN_ACTION Action);
|
||||
|
|
|
@ -726,7 +726,7 @@ struct TRUSTED_DOMAIN_FULL_INFORMATION {
|
|||
}
|
||||
alias TRUSTED_DOMAIN_FULL_INFORMATION* PTRUSTED_DOMAIN_FULL_INFORMATION;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
NTSTATUS LsaAddAccountRights(LSA_HANDLE, PSID, PLSA_UNICODE_STRING,
|
||||
ULONG);
|
||||
NTSTATUS LsaCallAuthenticationPackage(HANDLE, ULONG, PVOID, ULONG,
|
||||
|
|
|
@ -283,7 +283,7 @@ struct OLESERVERDOC {
|
|||
}
|
||||
alias OLESERVERDOC* LPOLESERVERDOC;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
OLESTATUS OleDelete(LPOLEOBJECT);
|
||||
OLESTATUS OleRelease(LPOLEOBJECT);
|
||||
OLESTATUS OleSaveToStream(LPOLEOBJECT, LPOLESTREAM);
|
||||
|
|
|
@ -48,7 +48,7 @@ extern (Windows) {
|
|||
}
|
||||
alias OLESTREAMVTBL* LPOLESTREAMVTBL;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
HRESULT CreateDataAdviseHolder(LPDATAADVISEHOLDER*);
|
||||
DWORD OleBuildVersion();
|
||||
HRESULT ReadClassStg(LPSTORAGE, CLSID*);
|
||||
|
|
|
@ -186,7 +186,7 @@ interface IAccessible : IDispatch {
|
|||
|
||||
alias IAccessible LPACCESSIBLE;
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
HRESULT AccessibleChildren(IAccessible, LONG, LONG, VARIANT*, LONG*);
|
||||
HRESULT AccessibleObjectFromEvent(HWND, DWORD, DWORD, IAccessible, VARIANT*);
|
||||
HRESULT AccessibleObjectFromPoint(POINT, IAccessible*, VARIANT*);
|
||||
|
|
|
@ -226,7 +226,7 @@ deprecated { // not actually deprecated, but they aren't converted yet.
|
|||
alias ICreateTypeLib2 LPCREATETYPELIB2;
|
||||
}
|
||||
|
||||
extern (Windows) {
|
||||
extern (Windows) nothrow @nogc {
|
||||
BSTR SysAllocString(const(OLECHAR)*);
|
||||
int SysReAllocString(BSTR*, const(OLECHAR)*);
|
||||
BSTR SysAllocStringLen(const(OLECHAR)*, uint);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue