mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-02 16:23:56 +08:00
d: Merge upstream dmd 47871363d, druntime, c52e28b7, phobos 99e9c1b77.
D front-end changes: - Import dmd v2.099.1-beta.1. - The address of NRVO variables is now stored in scoped closures when they have nested references. - Using `__traits(parameters)' in foreach loops now always returns the parameters to the function the foreach appears within. Previously, when used inside a `foreach' using an overloaded `opApply', the trait would yield the parameters to the delegate. - The deprecation period of unannotated `asm' blocks has been ended. - The `inout' attribute no longer implies the `return' attribute. - Added new `D_PreConditions', `D_PostConditions', and `D_Invariants' version identifiers. D runtime changes: - Import druntime v2.099.1-beta.1. Phobos changes: - Import phobos v2.099.1-beta.1. - `Nullable' in `std.typecons' can now act as a range. - std.experimental.logger default level changed to `info' instead of `warning'. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 47871363d. * d-builtins.cc (d_init_versions): Add predefined version identifiers D_PreConditions, D_PostConditions, and D_Invariants. * d-codegen.cc (d_build_call): Update for new front-end interface. (build_frame_type): Generate reference field for NRVO variables with nested references. (build_closure): Generate assignment of return address to closure. * d-tree.h (DECL_INSTANTIATED): Use DECL_LANG_FLAG_2. (bind_expr): Remove. * decl.cc (DeclVisitor::visit (FuncDeclaration *)): Update for new front-end interface. (get_symbol_decl): Likewise. (get_decl_tree): Check DECL_LANG_FRAME_FIELD before DECL_LANG_NRVO. Dereference the field when both are set. * expr.cc (ExprVisitor::visit (DeleteExp *)): Update for new front-end interface. * modules.cc (get_internal_fn): Likewise. * toir.cc (IRVisitor::visit (ReturnStatement *)): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime c52e28b7. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_OPENBSD): Add core/sys/openbsd/pwd.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 99e9c1b77. * testsuite/libphobos.exceptions/message_with_null.d: New test. gcc/testsuite/ChangeLog: * gdc.dg/nrvo1.d: New test.
This commit is contained in:
parent
be07535d0f
commit
235d5a96cb
@ -484,6 +484,15 @@ d_init_versions (void)
|
||||
if (global.params.useAssert == CHECKENABLEon)
|
||||
VersionCondition::addPredefinedGlobalIdent ("assert");
|
||||
|
||||
if (global.params.useIn == CHECKENABLEon)
|
||||
VersionCondition::addPredefinedGlobalIdent("D_PreConditions");
|
||||
|
||||
if (global.params.useOut == CHECKENABLEon)
|
||||
VersionCondition::addPredefinedGlobalIdent("D_PostConditions");
|
||||
|
||||
if (global.params.useInvariants == CHECKENABLEon)
|
||||
VersionCondition::addPredefinedGlobalIdent("D_Invariants");
|
||||
|
||||
if (global.params.useArrayBounds == CHECKENABLEoff)
|
||||
VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks");
|
||||
|
||||
|
@ -2207,9 +2207,9 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
|
||||
build_address (targ));
|
||||
}
|
||||
|
||||
/* Type `noreturn` is a terminator, as no other arguments can possibly
|
||||
be evaluated after it. */
|
||||
if (TREE_TYPE (targ) == noreturn_type_node)
|
||||
/* Type `noreturn` is a terminator, as no other arguments can possibly
|
||||
be evaluated after it. */
|
||||
if (TREE_TYPE (targ) == noreturn_type_node)
|
||||
noreturn_call = true;
|
||||
|
||||
vec_safe_push (args, targ);
|
||||
@ -2690,9 +2690,15 @@ build_frame_type (tree ffi, FuncDeclaration *fd)
|
||||
DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (vsym);
|
||||
TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (vsym);
|
||||
|
||||
/* Can't do nrvo if the variable is put in a frame. */
|
||||
if (fd->nrvo_can && fd->nrvo_var == v)
|
||||
fd->nrvo_can = 0;
|
||||
if (DECL_LANG_NRVO (vsym))
|
||||
{
|
||||
/* Store the nrvo variable in the frame by reference. */
|
||||
TREE_TYPE (field) = build_reference_type (TREE_TYPE (field));
|
||||
|
||||
/* Can't do nrvo if the variable is put in a closure, since what the
|
||||
return slot points to may no longer exist. */
|
||||
gcc_assert (!FRAMEINFO_IS_CLOSURE (ffi));
|
||||
}
|
||||
|
||||
if (FRAMEINFO_IS_CLOSURE (ffi))
|
||||
{
|
||||
@ -2769,13 +2775,17 @@ build_closure (FuncDeclaration *fd)
|
||||
for (size_t i = 0; i < fd->closureVars.length; i++)
|
||||
{
|
||||
VarDeclaration *v = fd->closureVars[i];
|
||||
|
||||
if (!v->isParameter ())
|
||||
continue;
|
||||
|
||||
tree vsym = get_symbol_decl (v);
|
||||
|
||||
if (TREE_CODE (vsym) != PARM_DECL && !DECL_LANG_NRVO (vsym))
|
||||
continue;
|
||||
|
||||
tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym));
|
||||
|
||||
/* Variable is an alias for the NRVO slot, store the reference. */
|
||||
if (DECL_LANG_NRVO (vsym))
|
||||
vsym = build_address (DECL_LANG_NRVO (vsym));
|
||||
|
||||
tree expr = modify_expr (field, vsym);
|
||||
add_stmt (expr);
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ lang_tree_node
|
||||
|
||||
/* True if the decl comes from a template instance. */
|
||||
#define DECL_INSTANTIATED(NODE) \
|
||||
(DECL_LANG_FLAG_1 (VAR_OR_FUNCTION_DECL_CHECK (NODE)))
|
||||
(DECL_LANG_FLAG_2 (VAR_OR_FUNCTION_DECL_CHECK (NODE)))
|
||||
|
||||
enum d_tree_index
|
||||
{
|
||||
@ -580,7 +580,6 @@ extern tree build_bounds_index_condition (IndexExp *, tree, tree);
|
||||
extern tree build_bounds_slice_condition (SliceExp *, tree, tree, tree);
|
||||
extern bool array_bounds_check (void);
|
||||
extern bool checkaction_trap_p (void);
|
||||
extern tree bind_expr (tree, tree);
|
||||
extern TypeFunction *get_function_type (Type *);
|
||||
extern bool call_by_alias_p (FuncDeclaration *, FuncDeclaration *);
|
||||
extern tree d_build_call_expr (FuncDeclaration *, tree, Expressions *);
|
||||
|
@ -791,7 +791,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->semantic3Errors)
|
||||
if (d->hasSemantic3Errors ())
|
||||
return;
|
||||
|
||||
if (d->isNested ())
|
||||
@ -805,7 +805,7 @@ public:
|
||||
break;
|
||||
|
||||
/* Parent failed to compile, but errors were gagged. */
|
||||
if (fdp->semantic3Errors)
|
||||
if (fdp->hasSemantic3Errors ())
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -921,15 +921,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/* May change cfun->static_chain. */
|
||||
build_closure (d);
|
||||
|
||||
if (d->vresult)
|
||||
declare_local_var (d->vresult);
|
||||
|
||||
if (d->v_argptr)
|
||||
push_stmt_list ();
|
||||
|
||||
/* Named return value optimisation support for D.
|
||||
Implemented by overriding all the RETURN_EXPRs and replacing all
|
||||
occurrences of VAR with the RESULT_DECL for the function.
|
||||
@ -951,7 +942,7 @@ public:
|
||||
else
|
||||
d->shidden = resdecl;
|
||||
|
||||
if (d->nrvo_can && d->nrvo_var)
|
||||
if (d->isNRVO () && d->nrvo_var)
|
||||
{
|
||||
tree var = get_symbol_decl (d->nrvo_var);
|
||||
|
||||
@ -966,6 +957,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/* May change cfun->static_chain. */
|
||||
build_closure (d);
|
||||
|
||||
if (d->vresult)
|
||||
declare_local_var (d->vresult);
|
||||
|
||||
if (d->v_argptr)
|
||||
push_stmt_list ();
|
||||
|
||||
build_function_body (d);
|
||||
|
||||
/* Initialize the _argptr variable. */
|
||||
@ -1284,26 +1284,26 @@ get_symbol_decl (Declaration *decl)
|
||||
/* In [pragma/crtctor], Annotates a function so it is run after the C
|
||||
runtime library is initialized and before the D runtime library is
|
||||
initialized. */
|
||||
if (fd->isCrtCtorDtor == 1)
|
||||
if (fd->isCrtCtor ())
|
||||
{
|
||||
DECL_STATIC_CONSTRUCTOR (decl->csym) = 1;
|
||||
decl_init_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
|
||||
}
|
||||
else if (fd->isCrtCtorDtor == 2)
|
||||
else if (fd->isCrtDtor ())
|
||||
{
|
||||
DECL_STATIC_DESTRUCTOR (decl->csym) = 1;
|
||||
decl_fini_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function was declared `naked'. */
|
||||
if (fd->naked)
|
||||
if (fd->isNaked ())
|
||||
{
|
||||
insert_decl_attribute (decl->csym, "naked");
|
||||
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1;
|
||||
}
|
||||
|
||||
/* Mark compiler generated functions as artificial. */
|
||||
if (fd->generated)
|
||||
if (fd->isGenerated ())
|
||||
DECL_ARTIFICIAL (decl->csym) = 1;
|
||||
|
||||
/* Ensure and require contracts are lexically nested in the function they
|
||||
@ -1486,20 +1486,26 @@ get_decl_tree (Declaration *decl)
|
||||
if (vd == NULL || fd == NULL)
|
||||
return t;
|
||||
|
||||
/* Get the named return value. */
|
||||
if (DECL_LANG_NRVO (t))
|
||||
return DECL_LANG_NRVO (t);
|
||||
|
||||
/* Get the closure holding the var decl. */
|
||||
if (DECL_LANG_FRAME_FIELD (t))
|
||||
{
|
||||
FuncDeclaration *parent = vd->toParent2 ()->isFuncDeclaration ();
|
||||
tree frame_ref = get_framedecl (fd, parent);
|
||||
|
||||
return component_ref (build_deref (frame_ref),
|
||||
DECL_LANG_FRAME_FIELD (t));
|
||||
tree field = component_ref (build_deref (frame_ref),
|
||||
DECL_LANG_FRAME_FIELD (t));
|
||||
/* Frame field can also be a reference to the DECL_RESULT of a function.
|
||||
Dereference it to get the value. */
|
||||
if (DECL_LANG_NRVO (t))
|
||||
field = build_deref (field);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
/* Get the named return value. */
|
||||
if (DECL_LANG_NRVO (t))
|
||||
return DECL_LANG_NRVO (t);
|
||||
|
||||
/* Get the non-local `this' value by going through parent link
|
||||
of nested classes, this routine pretty much undoes what
|
||||
getRightThis in the frontend removes from codegen. */
|
||||
|
@ -1,4 +1,4 @@
|
||||
2503f17e5767bc4fcd0cf3889c90fa0415b0edaa
|
||||
47871363d804f54b29ccfd444b082c19716c2301
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
@ -1 +1 @@
|
||||
v2.099.0
|
||||
v2.099.1-beta.1
|
||||
|
@ -547,7 +547,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
|
||||
if (overflow) assert(0);
|
||||
|
||||
// Skip no-op for noreturn without custom aligment
|
||||
if (memsize != 0 || !alignment.isDefault())
|
||||
if (memalignsize != 0 || !alignment.isDefault())
|
||||
alignmember(alignment, memalignsize, &ofs);
|
||||
|
||||
uint memoffset = ofs;
|
||||
@ -570,7 +570,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
|
||||
* definitions exposed some issues in their TypeInfo generation in DMD.
|
||||
* Related PR: https://github.com/dlang/dmd/pull/13312
|
||||
*/
|
||||
if (semanticRun == PASS.init && !isInterfaceDeclaration())
|
||||
if (semanticRun == PASS.initial && !isInterfaceDeclaration())
|
||||
{
|
||||
auto stc = storage_class;
|
||||
if (_scope)
|
||||
@ -747,7 +747,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
|
||||
extern (C++) static int fp(Dsymbol s, void* ctxt)
|
||||
{
|
||||
auto f = s.isCtorDeclaration();
|
||||
if (f && f.semanticRun == PASS.init)
|
||||
if (f && f.semanticRun == PASS.initial)
|
||||
f.dsymbolSemantic(null);
|
||||
return 0;
|
||||
}
|
||||
|
@ -100,9 +100,9 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
|
||||
|
||||
if (tthis && ad.aliasthis.sym.needThis())
|
||||
{
|
||||
if (e.op == EXP.variable)
|
||||
if (auto ve = e.isVarExp())
|
||||
{
|
||||
if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
|
||||
if (auto fd = ve.var.isFuncDeclaration())
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=13009
|
||||
// Support better match for the overloaded alias this.
|
||||
|
@ -52,16 +52,16 @@ bool isArrayOpValid(Expression e)
|
||||
{
|
||||
if (isUnaArrayOp(e.op))
|
||||
{
|
||||
return isArrayOpValid((cast(UnaExp)e).e1);
|
||||
return isArrayOpValid(e.isUnaExp().e1);
|
||||
}
|
||||
if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == EXP.assign)
|
||||
{
|
||||
BinExp be = cast(BinExp)e;
|
||||
BinExp be = e.isBinExp();
|
||||
return isArrayOpValid(be.e1) && isArrayOpValid(be.e2);
|
||||
}
|
||||
if (e.op == EXP.construct)
|
||||
{
|
||||
BinExp be = cast(BinExp)e;
|
||||
BinExp be = e.isBinExp();
|
||||
return be.e1.op == EXP.slice && isArrayOpValid(be.e2);
|
||||
}
|
||||
// if (e.op == EXP.call)
|
||||
@ -76,7 +76,7 @@ bool isArrayOpValid(Expression e)
|
||||
bool isNonAssignmentArrayOp(Expression e)
|
||||
{
|
||||
if (e.op == EXP.slice)
|
||||
return isNonAssignmentArrayOp((cast(SliceExp)e).e1);
|
||||
return isNonAssignmentArrayOp(e.isSliceExp().e1);
|
||||
|
||||
Type tb = e.type.toBasetype();
|
||||
if (tb.ty == Tarray || tb.ty == Tsarray)
|
||||
@ -176,7 +176,7 @@ Expression arrayOp(BinAssignExp e, Scope* sc)
|
||||
return e.e1.modifiableLvalue(sc, e.e1);
|
||||
}
|
||||
|
||||
return arrayOp(cast(BinExp)e, sc);
|
||||
return arrayOp(e.isBinExp(), sc);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
|
@ -54,4 +54,3 @@ alias TemplateInstances = Array!(TemplateInstance);
|
||||
alias Ensures = Array!(Ensure);
|
||||
alias Designators = Array!(Designator);
|
||||
alias DesigInits = Array!(DesigInit);
|
||||
|
||||
|
@ -67,4 +67,3 @@ typedef Array<struct Ensure> Ensures;
|
||||
typedef Array<struct Designator> Designators;
|
||||
|
||||
typedef Array<struct DesigInit> DesigInits;
|
||||
|
||||
|
@ -99,9 +99,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
|
||||
result = BE.halt;
|
||||
return;
|
||||
}
|
||||
if (s.exp.op == EXP.assert_)
|
||||
if (AssertExp a = s.exp.isAssertExp())
|
||||
{
|
||||
AssertExp a = cast(AssertExp)s.exp;
|
||||
if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
|
||||
{
|
||||
result = BE.halt;
|
||||
@ -505,7 +504,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
|
||||
if (!(s.stc & STC.nothrow_))
|
||||
{
|
||||
if (mustNotThrow && !(s.stc & STC.nothrow_))
|
||||
s.deprecation("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
|
||||
s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
|
||||
else
|
||||
result |= BE.throw_;
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
|
||||
auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_);
|
||||
auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf);
|
||||
fop.storage_class |= STC.inference;
|
||||
fop.generated = true;
|
||||
fop.flags |= FUNCFLAG.generated;
|
||||
Expression e;
|
||||
if (stc & STC.disable)
|
||||
{
|
||||
@ -575,7 +575,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
|
||||
tf = tf.addSTC(STC.const_).toTypeFunction();
|
||||
Identifier id = Id.xopEquals;
|
||||
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
|
||||
fop.generated = true;
|
||||
fop.flags |= FUNCFLAG.generated;
|
||||
fop.parent = sd;
|
||||
Expression e1 = new IdentifierExp(loc, Id.This);
|
||||
Expression e2 = new IdentifierExp(loc, Id.p);
|
||||
@ -644,13 +644,13 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
|
||||
switch (e.op)
|
||||
{
|
||||
case EXP.overloadSet:
|
||||
s = (cast(OverExp)e).vars;
|
||||
s = e.isOverExp().vars;
|
||||
break;
|
||||
case EXP.scope_:
|
||||
s = (cast(ScopeExp)e).sds;
|
||||
s = e.isScopeExp().sds;
|
||||
break;
|
||||
case EXP.variable:
|
||||
s = (cast(VarExp)e).var;
|
||||
s = e.isVarExp().var;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -696,7 +696,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
|
||||
tf = tf.addSTC(STC.const_).toTypeFunction();
|
||||
Identifier id = Id.xopCmp;
|
||||
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
|
||||
fop.generated = true;
|
||||
fop.flags |= FUNCFLAG.generated;
|
||||
fop.parent = sd;
|
||||
Expression e1 = new IdentifierExp(loc, Id.This);
|
||||
Expression e2 = new IdentifierExp(loc, Id.p);
|
||||
@ -814,7 +814,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
|
||||
auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted);
|
||||
Identifier id = Id.xtoHash;
|
||||
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
|
||||
fop.generated = true;
|
||||
fop.flags |= FUNCFLAG.generated;
|
||||
|
||||
/* Do memberwise hashing.
|
||||
*
|
||||
@ -937,13 +937,13 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
|
||||
if (stc & STC.safe)
|
||||
stc = (stc & ~STC.safe) | STC.trusted;
|
||||
|
||||
ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
|
||||
SliceExp se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
|
||||
new IntegerExp(loc, n, Type.tsize_t));
|
||||
// Prevent redundant bounds check
|
||||
(cast(SliceExp)ex).upperIsInBounds = true;
|
||||
(cast(SliceExp)ex).lowerIsLessThanUpper = true;
|
||||
se.upperIsInBounds = true;
|
||||
se.lowerIsLessThanUpper = true;
|
||||
|
||||
ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), ex);
|
||||
ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
|
||||
}
|
||||
e = Expression.combine(ex, e); // combine in reverse order
|
||||
}
|
||||
@ -952,7 +952,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
|
||||
{
|
||||
//printf("Building __fieldDtor(), %s\n", e.toChars());
|
||||
auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__fieldDtor);
|
||||
dd.generated = true;
|
||||
dd.flags |= FUNCFLAG.generated;
|
||||
dd.storage_class |= STC.inference;
|
||||
dd.fbody = new ExpStatement(loc, e);
|
||||
ad.members.push(dd);
|
||||
@ -1008,7 +1008,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
|
||||
e = Expression.combine(e, ce);
|
||||
}
|
||||
auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor);
|
||||
dd.generated = true;
|
||||
dd.flags |= FUNCFLAG.generated;
|
||||
dd.storage_class |= STC.inference;
|
||||
dd.fbody = new ExpStatement(loc, e);
|
||||
ad.members.push(dd);
|
||||
@ -1079,7 +1079,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
|
||||
stmts.push(new ExpStatement(loc, call));
|
||||
stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
|
||||
func.fbody = new CompoundStatement(loc, stmts);
|
||||
func.generated = true;
|
||||
func.flags |= FUNCFLAG.generated;
|
||||
|
||||
auto sc2 = sc.push();
|
||||
sc2.stc &= ~STC.static_; // not a static destructor
|
||||
@ -1127,7 +1127,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
|
||||
auto call = new CallExp(dtor.loc, dtor, null);
|
||||
call.directcall = true; // non-virtual call Class.__dtor();
|
||||
func.fbody = new ExpStatement(dtor.loc, call);
|
||||
func.generated = true;
|
||||
func.flags |= FUNCFLAG.generated;
|
||||
func.storage_class |= STC.inference;
|
||||
|
||||
auto sc2 = sc.push();
|
||||
@ -1403,7 +1403,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
|
||||
//printf("Building __fieldPostBlit()\n");
|
||||
checkShared();
|
||||
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit);
|
||||
dd.generated = true;
|
||||
dd.flags |= FUNCFLAG.generated;
|
||||
dd.storage_class |= STC.inference | STC.scope_;
|
||||
dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls);
|
||||
sd.postblits.shift(dd);
|
||||
@ -1441,7 +1441,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
|
||||
|
||||
checkShared();
|
||||
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit);
|
||||
dd.generated = true;
|
||||
dd.flags |= FUNCFLAG.generated;
|
||||
dd.storage_class |= STC.inference;
|
||||
dd.fbody = new ExpStatement(loc, e);
|
||||
sd.members.push(dd);
|
||||
@ -1504,7 +1504,7 @@ private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const
|
||||
auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true);
|
||||
ccd.storage_class |= funcStc;
|
||||
ccd.storage_class |= STC.inference;
|
||||
ccd.generated = true;
|
||||
ccd.flags |= FUNCFLAG.generated;
|
||||
return ccd;
|
||||
}
|
||||
|
||||
@ -1691,5 +1691,3 @@ bool buildCopyCtor(StructDeclaration sd, Scope* sc)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -217,15 +217,13 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
}
|
||||
emplaceExp!(ComplexExp)(&ue, loc, v, type);
|
||||
}
|
||||
else if (e1.op == EXP.symbolOffset)
|
||||
else if (SymOffExp soe = e1.isSymOffExp())
|
||||
{
|
||||
SymOffExp soe = cast(SymOffExp)e1;
|
||||
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
|
||||
ue.exp().type = type;
|
||||
}
|
||||
else if (e2.op == EXP.symbolOffset)
|
||||
else if (SymOffExp soe = e2.isSymOffExp())
|
||||
{
|
||||
SymOffExp soe = cast(SymOffExp)e2;
|
||||
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
|
||||
ue.exp().type = type;
|
||||
}
|
||||
@ -320,9 +318,8 @@ UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
}
|
||||
emplaceExp!(ComplexExp)(&ue, loc, v, type);
|
||||
}
|
||||
else if (e1.op == EXP.symbolOffset)
|
||||
else if (SymOffExp soe = e1.isSymOffExp())
|
||||
{
|
||||
SymOffExp soe = cast(SymOffExp)e1;
|
||||
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
|
||||
ue.exp().type = type;
|
||||
}
|
||||
@ -731,14 +728,12 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
|
||||
{
|
||||
if (e2.op == EXP.null_)
|
||||
cmp = 1;
|
||||
else if (e2.op == EXP.string_)
|
||||
else if (StringExp es2 = e2.isStringExp())
|
||||
{
|
||||
StringExp es2 = cast(StringExp)e2;
|
||||
cmp = (0 == es2.len);
|
||||
}
|
||||
else if (e2.op == EXP.arrayLiteral)
|
||||
else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp())
|
||||
{
|
||||
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
|
||||
cmp = !es2.elements || (0 == es2.elements.dim);
|
||||
}
|
||||
else
|
||||
@ -749,14 +744,12 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
|
||||
}
|
||||
else if (e2.op == EXP.null_)
|
||||
{
|
||||
if (e1.op == EXP.string_)
|
||||
if (StringExp es1 = e1.isStringExp())
|
||||
{
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
cmp = (0 == es1.len);
|
||||
}
|
||||
else if (e1.op == EXP.arrayLiteral)
|
||||
else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp())
|
||||
{
|
||||
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
|
||||
cmp = !es1.elements || (0 == es1.elements.dim);
|
||||
}
|
||||
else
|
||||
@ -767,8 +760,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
|
||||
}
|
||||
else if (e1.op == EXP.string_ && e2.op == EXP.string_)
|
||||
{
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
StringExp es2 = cast(StringExp)e2;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
StringExp es2 = e2.isStringExp();
|
||||
if (es1.sz != es2.sz)
|
||||
{
|
||||
assert(global.errors);
|
||||
@ -784,8 +777,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
|
||||
}
|
||||
else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
|
||||
{
|
||||
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
|
||||
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
|
||||
ArrayLiteralExp es1 = e1.isArrayLiteralExp();
|
||||
ArrayLiteralExp es2 = e2.isArrayLiteralExp();
|
||||
if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
|
||||
cmp = 1; // both arrays are empty
|
||||
else if (!es1.elements || !es2.elements)
|
||||
@ -818,8 +811,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
|
||||
else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
|
||||
{
|
||||
Lsa:
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
ArrayLiteralExp es2 = e2.isArrayLiteralExp();
|
||||
size_t dim1 = es1.len;
|
||||
size_t dim2 = es2.elements ? es2.elements.dim : 0;
|
||||
if (dim1 != dim2)
|
||||
@ -844,8 +837,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
|
||||
}
|
||||
else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
|
||||
{
|
||||
StructLiteralExp es1 = cast(StructLiteralExp)e1;
|
||||
StructLiteralExp es2 = cast(StructLiteralExp)e2;
|
||||
StructLiteralExp es1 = e1.isStructLiteralExp();
|
||||
StructLiteralExp es2 = e2.isStructLiteralExp();
|
||||
if (es1.sd != es2.sd)
|
||||
cmp = 0;
|
||||
else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
|
||||
@ -935,8 +928,8 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
|
||||
}
|
||||
else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
|
||||
{
|
||||
SymOffExp es1 = cast(SymOffExp)e1;
|
||||
SymOffExp es2 = cast(SymOffExp)e2;
|
||||
SymOffExp es1 = e1.isSymOffExp();
|
||||
SymOffExp es2 = e2.isSymOffExp();
|
||||
cmp = (es1.var == es2.var && es1.offset == es2.offset);
|
||||
}
|
||||
else
|
||||
@ -976,8 +969,8 @@ UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
//printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
|
||||
if (e1.op == EXP.string_ && e2.op == EXP.string_)
|
||||
{
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
StringExp es2 = cast(StringExp)e2;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
StringExp es2 = e2.isStringExp();
|
||||
size_t sz = es1.sz;
|
||||
assert(sz == es2.sz);
|
||||
size_t len = es1.len;
|
||||
@ -1045,7 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
|
||||
}
|
||||
if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
|
||||
{
|
||||
Expression ex = (cast(VectorExp)e1).e1;
|
||||
Expression ex = e1.isVectorExp().e1;
|
||||
emplaceExp!(UnionExp)(&ue, ex);
|
||||
return ue;
|
||||
}
|
||||
@ -1201,20 +1194,17 @@ UnionExp ArrayLength(Type type, Expression e1)
|
||||
{
|
||||
UnionExp ue = void;
|
||||
Loc loc = e1.loc;
|
||||
if (e1.op == EXP.string_)
|
||||
if (StringExp es1 = e1.isStringExp())
|
||||
{
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
|
||||
}
|
||||
else if (e1.op == EXP.arrayLiteral)
|
||||
else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
|
||||
{
|
||||
ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
|
||||
size_t dim = ale.elements ? ale.elements.dim : 0;
|
||||
emplaceExp!(IntegerExp)(&ue, loc, dim, type);
|
||||
}
|
||||
else if (e1.op == EXP.assocArrayLiteral)
|
||||
else if (AssocArrayLiteralExp ale = e1.isAssocArrayLiteralExp)
|
||||
{
|
||||
AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
|
||||
size_t dim = ale.keys.dim;
|
||||
emplaceExp!(IntegerExp)(&ue, loc, dim, type);
|
||||
}
|
||||
@ -1238,7 +1228,7 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
|
||||
assert(e1.type);
|
||||
if (e1.op == EXP.string_ && e2.op == EXP.int64)
|
||||
{
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
uinteger_t i = e2.toInteger();
|
||||
if (i >= es1.len)
|
||||
{
|
||||
@ -1261,9 +1251,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
|
||||
e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
|
||||
emplaceExp!(ErrorExp)(&ue);
|
||||
}
|
||||
else if (e1.op == EXP.arrayLiteral)
|
||||
else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
|
||||
{
|
||||
ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
|
||||
auto e = ale[cast(size_t)i];
|
||||
e.type = type;
|
||||
e.loc = loc;
|
||||
@ -1278,9 +1267,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
|
||||
else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
|
||||
{
|
||||
uinteger_t i = e2.toInteger();
|
||||
if (e1.op == EXP.arrayLiteral)
|
||||
if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
|
||||
{
|
||||
ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
|
||||
if (i >= ale.elements.dim)
|
||||
{
|
||||
e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.dim);
|
||||
@ -1300,9 +1288,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
|
||||
else
|
||||
cantExp(ue);
|
||||
}
|
||||
else if (e1.op == EXP.assocArrayLiteral)
|
||||
else if (AssocArrayLiteralExp ae = e1.isAssocArrayLiteralExp())
|
||||
{
|
||||
AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
|
||||
/* Search the keys backwards, in case there are duplicate keys
|
||||
*/
|
||||
for (size_t i = ae.keys.dim; i;)
|
||||
@ -1350,7 +1337,7 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
|
||||
|
||||
if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
|
||||
{
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
const uinteger_t ilwr = lwr.toInteger();
|
||||
const uinteger_t iupr = upr.toInteger();
|
||||
if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
|
||||
@ -1363,14 +1350,14 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
|
||||
const data1 = es1.peekData();
|
||||
memcpy(s, data1.ptr + ilwr * sz, len * sz);
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
|
||||
StringExp es = cast(StringExp)ue.exp();
|
||||
StringExp es = ue.exp().isStringExp();
|
||||
es.committed = es1.committed;
|
||||
es.type = type;
|
||||
}
|
||||
}
|
||||
else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
|
||||
{
|
||||
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
|
||||
ArrayLiteralExp es1 = e1.isArrayLiteralExp();
|
||||
const uinteger_t ilwr = lwr.toInteger();
|
||||
const uinteger_t iupr = upr.toInteger();
|
||||
if (sliceBoundsCheck(0, es1.elements.dim, ilwr, iupr))
|
||||
@ -1491,15 +1478,15 @@ private Expressions* copyElements(Expression e1, Expression e2 = null)
|
||||
}
|
||||
}
|
||||
|
||||
if (e1.op == EXP.arrayLiteral)
|
||||
append(cast(ArrayLiteralExp)e1);
|
||||
if (auto ale = e1.isArrayLiteralExp())
|
||||
append(ale);
|
||||
else
|
||||
elems.push(e1);
|
||||
|
||||
if (e2)
|
||||
{
|
||||
if (e2.op == EXP.arrayLiteral)
|
||||
append(cast(ArrayLiteralExp)e2);
|
||||
if (auto ale = e2.isArrayLiteralExp())
|
||||
append(ale);
|
||||
else
|
||||
elems.push(e2);
|
||||
}
|
||||
@ -1544,7 +1531,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
else
|
||||
utf_encode(sz, s, cast(dchar)v);
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
|
||||
StringExp es = cast(StringExp)ue.exp();
|
||||
StringExp es = ue.exp().isStringExp();
|
||||
es.type = type;
|
||||
es.committed = 1;
|
||||
}
|
||||
@ -1589,8 +1576,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
else if (e1.op == EXP.string_ && e2.op == EXP.string_)
|
||||
{
|
||||
// Concatenate the strings
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
StringExp es2 = cast(StringExp)e2;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
StringExp es2 = e2.isStringExp();
|
||||
size_t len = es1.len + es2.len;
|
||||
ubyte sz = es1.sz;
|
||||
if (sz != es2.sz)
|
||||
@ -1609,7 +1596,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
memcpy(cast(char*)s, data1.ptr, es1.len * sz);
|
||||
memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
|
||||
StringExp es = cast(StringExp)ue.exp();
|
||||
StringExp es = ue.exp().isStringExp();
|
||||
es.committed = es1.committed | es2.committed;
|
||||
es.type = type;
|
||||
assert(ue.exp().type);
|
||||
@ -1618,8 +1605,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
|
||||
{
|
||||
// [chars] ~ string --> [chars]
|
||||
StringExp es = cast(StringExp)e2;
|
||||
ArrayLiteralExp ea = cast(ArrayLiteralExp)e1;
|
||||
StringExp es = e2.isStringExp();
|
||||
ArrayLiteralExp ea = e1.isArrayLiteralExp();
|
||||
size_t len = es.len + ea.elements.dim;
|
||||
auto elems = new Expressions(len);
|
||||
for (size_t i = 0; i < ea.elements.dim; ++i)
|
||||
@ -1627,7 +1614,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
(*elems)[i] = ea[i];
|
||||
}
|
||||
emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
|
||||
ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
|
||||
ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
|
||||
sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim);
|
||||
assert(ue.exp().type);
|
||||
return ue;
|
||||
@ -1635,8 +1622,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
|
||||
{
|
||||
// string ~ [chars] --> [chars]
|
||||
StringExp es = cast(StringExp)e1;
|
||||
ArrayLiteralExp ea = cast(ArrayLiteralExp)e2;
|
||||
StringExp es = e1.isStringExp();
|
||||
ArrayLiteralExp ea = e2.isArrayLiteralExp();
|
||||
size_t len = es.len + ea.elements.dim;
|
||||
auto elems = new Expressions(len);
|
||||
for (size_t i = 0; i < ea.elements.dim; ++i)
|
||||
@ -1644,7 +1631,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
(*elems)[es.len + i] = ea[i];
|
||||
}
|
||||
emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
|
||||
ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
|
||||
ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
|
||||
sliceAssignArrayLiteralFromString(dest, es, 0);
|
||||
assert(ue.exp().type);
|
||||
return ue;
|
||||
@ -1652,7 +1639,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
else if (e1.op == EXP.string_ && e2.op == EXP.int64)
|
||||
{
|
||||
// string ~ char --> string
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
StringExp es;
|
||||
const sz = es1.sz;
|
||||
dinteger_t v = e2.toInteger();
|
||||
@ -1668,7 +1655,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
else
|
||||
utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
|
||||
es = cast(StringExp)ue.exp();
|
||||
es = ue.exp().isStringExp();
|
||||
es.committed = es1.committed;
|
||||
es.type = type;
|
||||
assert(ue.exp().type);
|
||||
@ -1679,7 +1666,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
// [w|d]?char ~ string --> string
|
||||
// We assume that we only ever prepend one char of the same type
|
||||
// (wchar,dchar) as the string's characters.
|
||||
StringExp es2 = cast(StringExp)e2;
|
||||
StringExp es2 = e2.isStringExp();
|
||||
const len = 1 + es2.len;
|
||||
const sz = es2.sz;
|
||||
dinteger_t v = e1.toInteger();
|
||||
@ -1688,7 +1675,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
const data2 = es2.peekData();
|
||||
memcpy(cast(char*)s + sz, data2.ptr, data2.length);
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
|
||||
StringExp es = cast(StringExp)ue.exp();
|
||||
StringExp es = ue.exp().isStringExp();
|
||||
es.sz = sz;
|
||||
es.committed = es2.committed;
|
||||
es.type = type;
|
||||
@ -1796,7 +1783,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
}
|
||||
if (!e.type.equals(type))
|
||||
{
|
||||
StringExp se = cast(StringExp)e.copy();
|
||||
StringExp se = e.copy().isStringExp();
|
||||
e = se.castTo(null, type);
|
||||
emplaceExp!(UnionExp)(&ue, e);
|
||||
e = ue.exp();
|
||||
@ -1812,23 +1799,21 @@ UnionExp Ptr(Type type, Expression e1)
|
||||
{
|
||||
//printf("Ptr(e1 = %s)\n", e1.toChars());
|
||||
UnionExp ue = void;
|
||||
if (e1.op == EXP.add)
|
||||
if (AddExp ae = e1.isAddExp())
|
||||
{
|
||||
AddExp ae = cast(AddExp)e1;
|
||||
if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
|
||||
if (AddrExp ade = ae.e1.isAddrExp())
|
||||
{
|
||||
AddrExp ade = cast(AddrExp)ae.e1;
|
||||
if (ade.e1.op == EXP.structLiteral)
|
||||
{
|
||||
StructLiteralExp se = cast(StructLiteralExp)ade.e1;
|
||||
uint offset = cast(uint)ae.e2.toInteger();
|
||||
Expression e = se.getField(type, offset);
|
||||
if (e)
|
||||
if (ae.e2.op == EXP.int64)
|
||||
if (StructLiteralExp se = ade.e1.isStructLiteralExp())
|
||||
{
|
||||
emplaceExp!(UnionExp)(&ue, e);
|
||||
return ue;
|
||||
uint offset = cast(uint)ae.e2.toInteger();
|
||||
Expression e = se.getField(type, offset);
|
||||
if (e)
|
||||
{
|
||||
emplaceExp!(UnionExp)(&ue, e);
|
||||
return ue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cantExp(ue);
|
||||
|
@ -981,7 +981,12 @@ final class CParser(AST) : Parser!AST
|
||||
e = new AST.DotIdExp(loc, e, Id.__sizeof);
|
||||
break;
|
||||
}
|
||||
// must be an expression
|
||||
e = cparsePrimaryExp();
|
||||
e = new AST.DotIdExp(loc, e, Id.__sizeof);
|
||||
break;
|
||||
}
|
||||
|
||||
e = cparseUnaryExp();
|
||||
e = new AST.DotIdExp(loc, e, Id.__sizeof);
|
||||
break;
|
||||
@ -1016,10 +1021,16 @@ final class CParser(AST) : Parser!AST
|
||||
{
|
||||
if (token.value == TOK.leftParenthesis)
|
||||
{
|
||||
//printf("cparseCastExp()\n");
|
||||
auto tk = peek(&token);
|
||||
if (tk.value == TOK.identifier &&
|
||||
!isTypedef(tk.ident) &&
|
||||
peek(tk).value == TOK.rightParenthesis)
|
||||
bool iscast;
|
||||
bool isexp;
|
||||
if (tk.value == TOK.identifier)
|
||||
{
|
||||
iscast = isTypedef(tk.ident);
|
||||
isexp = !iscast;
|
||||
}
|
||||
if (isexp)
|
||||
{
|
||||
// ( identifier ) is an expression
|
||||
return cparseUnaryExp();
|
||||
@ -1045,9 +1056,18 @@ final class CParser(AST) : Parser!AST
|
||||
auto ce = new AST.CompoundLiteralExp(loc, t, ci);
|
||||
return cparsePostfixOperators(ce);
|
||||
}
|
||||
else if (t.isTypeIdentifier() &&
|
||||
token.value == TOK.leftParenthesis &&
|
||||
!isCastExpression(pt))
|
||||
|
||||
if (iscast)
|
||||
{
|
||||
// ( type-name ) cast-expression
|
||||
auto ce = cparseCastExp();
|
||||
return new AST.CastExp(loc, ce, t);
|
||||
}
|
||||
|
||||
if (t.isTypeIdentifier() &&
|
||||
isexp &&
|
||||
token.value == TOK.leftParenthesis &&
|
||||
!isCastExpression(pt))
|
||||
{
|
||||
/* (t)(...)... might be a cast expression or a function call,
|
||||
* with different grammars: a cast would be cparseCastExp(),
|
||||
@ -1061,12 +1081,10 @@ final class CParser(AST) : Parser!AST
|
||||
AST.Expression e = new AST.CallExp(loc, ie, cparseArguments());
|
||||
return cparsePostfixOperators(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ( type-name ) cast-expression
|
||||
auto ce = cparseCastExp();
|
||||
return new AST.CastExp(loc, ce, t);
|
||||
}
|
||||
|
||||
// ( type-name ) cast-expression
|
||||
auto ce = cparseCastExp();
|
||||
return new AST.CastExp(loc, ce, t);
|
||||
}
|
||||
}
|
||||
return cparseUnaryExp();
|
||||
@ -1764,8 +1782,6 @@ final class CParser(AST) : Parser!AST
|
||||
symbols.push(stag);
|
||||
if (tt.tok == TOK.enum_)
|
||||
{
|
||||
if (!stag.members)
|
||||
error(tt.loc, "`enum %s` has no members", stag.toChars());
|
||||
isalias = false;
|
||||
s = new AST.AliasDeclaration(token.loc, id, stag);
|
||||
}
|
||||
@ -2382,7 +2398,19 @@ final class CParser(AST) : Parser!AST
|
||||
const idx = previd.toString();
|
||||
if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore
|
||||
importBuiltins = true; // probably one of those compiler extensions
|
||||
t = new AST.TypeIdentifier(loc, previd);
|
||||
t = null;
|
||||
if (scw & SCW.xtypedef)
|
||||
{
|
||||
/* Punch through to what the typedef is, to support things like:
|
||||
* typedef T* T;
|
||||
*/
|
||||
auto pt = lookupTypedef(previd);
|
||||
if (pt && *pt) // if previd is a known typedef
|
||||
t = *pt;
|
||||
}
|
||||
|
||||
if (!t)
|
||||
t = new AST.TypeIdentifier(loc, previd);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4767,7 +4795,8 @@ final class CParser(AST) : Parser!AST
|
||||
scan(&n);
|
||||
if (n.value == TOK.identifier && n.ident == Id.pack)
|
||||
return pragmaPack(loc);
|
||||
skipToNextLine();
|
||||
if (n.value != TOK.endOfLine)
|
||||
skipToNextLine();
|
||||
}
|
||||
|
||||
/*********
|
||||
@ -4786,7 +4815,8 @@ final class CParser(AST) : Parser!AST
|
||||
if (n.value != TOK.leftParenthesis)
|
||||
{
|
||||
error(loc, "left parenthesis expected to follow `#pragma pack`");
|
||||
skipToNextLine();
|
||||
if (n.value != TOK.endOfLine)
|
||||
skipToNextLine();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4796,7 +4826,8 @@ final class CParser(AST) : Parser!AST
|
||||
{
|
||||
error(loc, "right parenthesis expected to close `#pragma pack(`");
|
||||
}
|
||||
skipToNextLine();
|
||||
if (n.value != TOK.endOfLine)
|
||||
skipToNextLine();
|
||||
}
|
||||
|
||||
void setPackAlign(ref const Token t)
|
||||
@ -4923,7 +4954,8 @@ final class CParser(AST) : Parser!AST
|
||||
}
|
||||
|
||||
error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
|
||||
skipToNextLine();
|
||||
if (n.value != TOK.endOfLine)
|
||||
skipToNextLine();
|
||||
}
|
||||
|
||||
//}
|
||||
|
@ -232,11 +232,11 @@ bool needToCopyLiteral(const Expression expr)
|
||||
switch (e.op)
|
||||
{
|
||||
case EXP.arrayLiteral:
|
||||
return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
|
||||
return e.isArrayLiteralExp().ownedByCtfe == OwnedBy.code;
|
||||
case EXP.assocArrayLiteral:
|
||||
return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
|
||||
return e.isAssocArrayLiteralExp().ownedByCtfe == OwnedBy.code;
|
||||
case EXP.structLiteral:
|
||||
return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code;
|
||||
return e.isStructLiteralExp().ownedByCtfe == OwnedBy.code;
|
||||
case EXP.string_:
|
||||
case EXP.this_:
|
||||
case EXP.variable:
|
||||
@ -247,14 +247,14 @@ bool needToCopyLiteral(const Expression expr)
|
||||
case EXP.dotVariable:
|
||||
case EXP.slice:
|
||||
case EXP.cast_:
|
||||
e = (cast(UnaExp)e).e1;
|
||||
e = e.isUnaExp().e1;
|
||||
continue;
|
||||
case EXP.concatenate:
|
||||
return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2);
|
||||
return needToCopyLiteral(e.isBinExp().e1) || needToCopyLiteral(e.isBinExp().e2);
|
||||
case EXP.concatenateAssign:
|
||||
case EXP.concatenateElemAssign:
|
||||
case EXP.concatenateDcharAssign:
|
||||
e = (cast(BinExp)e).e2;
|
||||
e = e.isBinExp().e2;
|
||||
continue;
|
||||
default:
|
||||
return false;
|
||||
@ -286,7 +286,7 @@ UnionExp copyLiteral(Expression e)
|
||||
const slice = se.peekData();
|
||||
memcpy(s, slice.ptr, slice.length);
|
||||
emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz);
|
||||
StringExp se2 = cast(StringExp)ue.exp();
|
||||
StringExp se2 = ue.exp().isStringExp();
|
||||
se2.committed = se.committed;
|
||||
se2.postfix = se.postfix;
|
||||
se2.type = se.type;
|
||||
@ -299,14 +299,14 @@ UnionExp copyLiteral(Expression e)
|
||||
|
||||
emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements);
|
||||
|
||||
ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp();
|
||||
ArrayLiteralExp r = ue.exp().isArrayLiteralExp();
|
||||
r.ownedByCtfe = OwnedBy.ctfe;
|
||||
return ue;
|
||||
}
|
||||
if (auto aae = e.isAssocArrayLiteralExp())
|
||||
{
|
||||
emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values));
|
||||
AssocArrayLiteralExp r = cast(AssocArrayLiteralExp)ue.exp();
|
||||
AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp();
|
||||
r.type = e.type;
|
||||
r.ownedByCtfe = OwnedBy.ctfe;
|
||||
return ue;
|
||||
@ -482,7 +482,7 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
|
||||
// just a ref to the keys and values.
|
||||
OwnedBy wasOwned = aae.ownedByCtfe;
|
||||
emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values);
|
||||
aae = cast(AssocArrayLiteralExp)ue.exp();
|
||||
aae = ue.exp().isAssocArrayLiteralExp();
|
||||
aae.ownedByCtfe = wasOwned;
|
||||
}
|
||||
else
|
||||
@ -526,7 +526,7 @@ Expression resolveSlice(Expression e, UnionExp* pue = null)
|
||||
* It's very wasteful to resolve the slice when we only
|
||||
* need the length.
|
||||
*/
|
||||
uinteger_t resolveArrayLength(const Expression e)
|
||||
uinteger_t resolveArrayLength(Expression e)
|
||||
{
|
||||
switch (e.op)
|
||||
{
|
||||
@ -538,7 +538,7 @@ uinteger_t resolveArrayLength(const Expression e)
|
||||
|
||||
case EXP.slice:
|
||||
{
|
||||
auto se = cast(SliceExp)e;
|
||||
auto se = e.isSliceExp();
|
||||
const ilo = se.lwr.toInteger();
|
||||
const iup = se.upr.toInteger();
|
||||
return iup - ilo;
|
||||
@ -720,16 +720,16 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
|
||||
*ofs = soe.offset;
|
||||
if (auto dve = e.isDotVarExp())
|
||||
{
|
||||
const ex = dve.e1;
|
||||
auto ex = dve.e1;
|
||||
const v = dve.var.isVarDeclaration();
|
||||
assert(v);
|
||||
StructLiteralExp se = (ex.op == EXP.classReference)
|
||||
? (cast(ClassReferenceExp)ex).value
|
||||
: cast(StructLiteralExp)ex;
|
||||
? ex.isClassReferenceExp().value
|
||||
: ex.isStructLiteralExp();
|
||||
|
||||
// We can't use getField, because it makes a copy
|
||||
const i = (ex.op == EXP.classReference)
|
||||
? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset)
|
||||
? ex.isClassReferenceExp().getFieldIndex(e.type, v.offset)
|
||||
: se.getFieldIndex(e.type, v.offset);
|
||||
e = (*se.elements)[i];
|
||||
}
|
||||
@ -777,11 +777,11 @@ bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
|
||||
}
|
||||
// Note that type painting can occur with VarExp, so we
|
||||
// must compare the variables being pointed to.
|
||||
if (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
|
||||
if (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
|
||||
if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && agg1.isSymOffExp().var == agg2.isSymOffExp().var)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -801,14 +801,14 @@ Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres
|
||||
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
|
||||
}
|
||||
else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
|
||||
(cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr)
|
||||
agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr)
|
||||
{
|
||||
Type pointee = (cast(TypePointer)agg1.type).next;
|
||||
const sz = pointee.size();
|
||||
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
|
||||
}
|
||||
else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
|
||||
(cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
|
||||
agg1.isSymOffExp().var == agg2.isSymOffExp().var)
|
||||
{
|
||||
emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type);
|
||||
}
|
||||
@ -832,12 +832,12 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
|
||||
return pue.exp();
|
||||
}
|
||||
if (eptr.op == EXP.address)
|
||||
eptr = (cast(AddrExp)eptr).e1;
|
||||
eptr = eptr.isAddrExp().e1;
|
||||
dinteger_t ofs1;
|
||||
Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
|
||||
if (agg1.op == EXP.symbolOffset)
|
||||
{
|
||||
if ((cast(SymOffExp)agg1).var.type.ty != Tsarray)
|
||||
if (agg1.isSymOffExp().var.type.ty != Tsarray)
|
||||
{
|
||||
error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
|
||||
goto Lcant;
|
||||
@ -856,7 +856,7 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
|
||||
if (agg1.op == EXP.symbolOffset)
|
||||
{
|
||||
indx = ofs1 / sz;
|
||||
len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger();
|
||||
len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -881,8 +881,8 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
|
||||
}
|
||||
if (agg1.op == EXP.symbolOffset)
|
||||
{
|
||||
emplaceExp!(SymOffExp)(pue, loc, (cast(SymOffExp)agg1).var, indx * sz);
|
||||
SymOffExp se = cast(SymOffExp)pue.exp();
|
||||
emplaceExp!(SymOffExp)(pue, loc, agg1.isSymOffExp().var, indx * sz);
|
||||
SymOffExp se = pue.exp().isSymOffExp();
|
||||
se.type = type;
|
||||
return pue.exp();
|
||||
}
|
||||
@ -1016,7 +1016,7 @@ Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to)
|
||||
bool isCtfeComparable(Expression e)
|
||||
{
|
||||
if (e.op == EXP.slice)
|
||||
e = (cast(SliceExp)e).e1;
|
||||
e = e.isSliceExp().e1;
|
||||
if (e.isConst() != 1)
|
||||
{
|
||||
if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference)
|
||||
@ -1191,7 +1191,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
if (e1.op == EXP.classReference || e2.op == EXP.classReference)
|
||||
{
|
||||
if (e1.op == EXP.classReference && e2.op == EXP.classReference &&
|
||||
(cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value)
|
||||
e1.isClassReferenceExp().value == e2.isClassReferenceExp().value)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -1199,8 +1199,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
{
|
||||
// printf("e1: %s\n", e1.toChars());
|
||||
// printf("e2: %s\n", e2.toChars());
|
||||
Type t1 = isType((cast(TypeidExp)e1).obj);
|
||||
Type t2 = isType((cast(TypeidExp)e2).obj);
|
||||
Type t1 = isType(e1.isTypeidExp().obj);
|
||||
Type t2 = isType(e2.isTypeidExp().obj);
|
||||
assert(t1);
|
||||
assert(t2);
|
||||
return t1 != t2;
|
||||
@ -1214,7 +1214,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
dinteger_t ofs1, ofs2;
|
||||
Expression agg1 = getAggregateFromPointer(e1, &ofs1);
|
||||
Expression agg2 = getAggregateFromPointer(e2, &ofs2);
|
||||
if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
|
||||
if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
|
||||
{
|
||||
if (ofs1 == ofs2)
|
||||
return 0;
|
||||
@ -1232,13 +1232,13 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
return 0;
|
||||
assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_);
|
||||
// Same .funcptr. Do they have the same .ptr?
|
||||
Expression ptr1 = (cast(DelegateExp)e1).e1;
|
||||
Expression ptr2 = (cast(DelegateExp)e2).e1;
|
||||
Expression ptr1 = e1.isDelegateExp().e1;
|
||||
Expression ptr2 = e2.isDelegateExp().e1;
|
||||
dinteger_t ofs1, ofs2;
|
||||
Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
|
||||
Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
|
||||
// If they are EXP.variable, it means they are FuncDeclarations
|
||||
if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
|
||||
if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -1291,8 +1291,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
}
|
||||
if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
|
||||
{
|
||||
StructLiteralExp es1 = cast(StructLiteralExp)e1;
|
||||
StructLiteralExp es2 = cast(StructLiteralExp)e2;
|
||||
StructLiteralExp es1 = e1.isStructLiteralExp();
|
||||
StructLiteralExp es2 = e2.isStructLiteralExp();
|
||||
// For structs, we only need to return 0 or 1 (< and > aren't legal).
|
||||
if (es1.sd != es2.sd)
|
||||
return 1;
|
||||
@ -1326,8 +1326,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
|
||||
}
|
||||
if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
|
||||
{
|
||||
AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1;
|
||||
AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2;
|
||||
AssocArrayLiteralExp es1 = e1.isAssocArrayLiteralExp();
|
||||
AssocArrayLiteralExp es2 = e2.isAssocArrayLiteralExp();
|
||||
size_t dim = es1.keys.dim;
|
||||
if (es2.keys.dim != dim)
|
||||
return 1;
|
||||
@ -1394,8 +1394,8 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
|
||||
}
|
||||
else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
|
||||
{
|
||||
SymOffExp es1 = cast(SymOffExp)e1;
|
||||
SymOffExp es2 = cast(SymOffExp)e2;
|
||||
SymOffExp es1 = e1.isSymOffExp();
|
||||
SymOffExp es2 = e2.isSymOffExp();
|
||||
cmp = (es1.var == es2.var && es1.offset == es2.offset);
|
||||
}
|
||||
else if (e1.type.isreal())
|
||||
@ -1443,8 +1443,8 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
|
||||
{
|
||||
// [chars] ~ string => string (only valid for CTFE)
|
||||
StringExp es1 = cast(StringExp)e2;
|
||||
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e1;
|
||||
StringExp es1 = e2.isStringExp();
|
||||
ArrayLiteralExp es2 = e1.isArrayLiteralExp();
|
||||
const len = es1.len + es2.elements.dim;
|
||||
const sz = es1.sz;
|
||||
void* s = mem.xmalloc((len + 1) * sz);
|
||||
@ -1464,7 +1464,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
// Add terminating 0
|
||||
memset(cast(char*)s + len * sz, 0, sz);
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
|
||||
StringExp es = cast(StringExp)ue.exp();
|
||||
StringExp es = ue.exp().isStringExp();
|
||||
es.committed = 0;
|
||||
es.type = type;
|
||||
return ue;
|
||||
@ -1473,8 +1473,8 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
{
|
||||
// string ~ [chars] => string (only valid for CTFE)
|
||||
// Concatenate the strings
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
|
||||
StringExp es1 = e1.isStringExp();
|
||||
ArrayLiteralExp es2 = e2.isArrayLiteralExp();
|
||||
const len = es1.len + es2.elements.dim;
|
||||
const sz = es1.sz;
|
||||
void* s = mem.xmalloc((len + 1) * sz);
|
||||
@ -1494,7 +1494,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
// Add terminating 0
|
||||
memset(cast(char*)s + len * sz, 0, sz);
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
|
||||
StringExp es = cast(StringExp)ue.exp();
|
||||
StringExp es = ue.exp().isStringExp();
|
||||
es.sz = sz;
|
||||
es.committed = 0; //es1.committed;
|
||||
es.type = type;
|
||||
@ -1503,10 +1503,10 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
|
||||
{
|
||||
// [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
|
||||
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
|
||||
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
|
||||
ArrayLiteralExp es1 = e1.isArrayLiteralExp();
|
||||
ArrayLiteralExp es2 = e2.isArrayLiteralExp();
|
||||
emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements));
|
||||
es1 = cast(ArrayLiteralExp)ue.exp();
|
||||
es1 = ue.exp().isArrayLiteralExp();
|
||||
es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements));
|
||||
return ue;
|
||||
}
|
||||
@ -1594,7 +1594,7 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres
|
||||
// Disallow reinterpreting class casts. Do this by ensuring that
|
||||
// the original class can implicitly convert to the target class.
|
||||
// Also do not check 'alias this' for explicit cast expressions.
|
||||
auto tclass = (cast(ClassReferenceExp)e).originalClass().type.isTypeClass();
|
||||
auto tclass = e.isClassReferenceExp().originalClass().type.isTypeClass();
|
||||
auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf())
|
||||
: tclass.implicitConvTo(to.mutableOf());
|
||||
if (match)
|
||||
@ -1665,9 +1665,9 @@ void assignInPlace(Expression dest, Expression src)
|
||||
if (dest.op == EXP.structLiteral)
|
||||
{
|
||||
assert(dest.op == src.op);
|
||||
oldelems = (cast(StructLiteralExp)dest).elements;
|
||||
newelems = (cast(StructLiteralExp)src).elements;
|
||||
auto sd = (cast(StructLiteralExp)dest).sd;
|
||||
oldelems = dest.isStructLiteralExp().elements;
|
||||
newelems = src.isStructLiteralExp().elements;
|
||||
auto sd = dest.isStructLiteralExp().sd;
|
||||
const nfields = sd.nonHiddenFields();
|
||||
const nvthis = sd.fields.dim - nfields;
|
||||
if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim)
|
||||
@ -1676,22 +1676,22 @@ void assignInPlace(Expression dest, Expression src)
|
||||
}
|
||||
else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral)
|
||||
{
|
||||
oldelems = (cast(ArrayLiteralExp)dest).elements;
|
||||
newelems = (cast(ArrayLiteralExp)src).elements;
|
||||
oldelems = dest.isArrayLiteralExp().elements;
|
||||
newelems = src.isArrayLiteralExp().elements;
|
||||
}
|
||||
else if (dest.op == EXP.string_ && src.op == EXP.string_)
|
||||
{
|
||||
sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0);
|
||||
sliceAssignStringFromString(dest.isStringExp(), src.isStringExp(), 0);
|
||||
return;
|
||||
}
|
||||
else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_)
|
||||
{
|
||||
sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0);
|
||||
sliceAssignArrayLiteralFromString(dest.isArrayLiteralExp(), src.isStringExp(), 0);
|
||||
return;
|
||||
}
|
||||
else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_)
|
||||
{
|
||||
sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0);
|
||||
sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@ -1761,13 +1761,13 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
|
||||
size_t indxlo = 0;
|
||||
if (oldval.op == EXP.slice)
|
||||
{
|
||||
indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger();
|
||||
oldval = (cast(SliceExp)oldval).e1;
|
||||
indxlo = cast(size_t)oldval.isSliceExp().lwr.toInteger();
|
||||
oldval = oldval.isSliceExp().e1;
|
||||
}
|
||||
size_t copylen = oldlen < newlen ? oldlen : newlen;
|
||||
if (oldval.op == EXP.string_)
|
||||
{
|
||||
StringExp oldse = cast(StringExp)oldval;
|
||||
StringExp oldse = oldval.isStringExp();
|
||||
void* s = mem.xcalloc(newlen + 1, oldse.sz);
|
||||
const data = oldse.peekData();
|
||||
memcpy(s, data.ptr, copylen * oldse.sz);
|
||||
@ -1790,7 +1790,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
|
||||
}
|
||||
}
|
||||
emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
|
||||
StringExp se = cast(StringExp)pue.exp();
|
||||
StringExp se = pue.exp().isStringExp();
|
||||
se.type = arrayType;
|
||||
se.sz = oldse.sz;
|
||||
se.committed = oldse.committed;
|
||||
@ -1801,7 +1801,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
|
||||
if (oldlen != 0)
|
||||
{
|
||||
assert(oldval.op == EXP.arrayLiteral);
|
||||
ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval;
|
||||
ArrayLiteralExp ae = oldval.isArrayLiteralExp();
|
||||
foreach (size_t i; 0 .. copylen)
|
||||
(*elements)[i] = (*ae.elements)[indxlo + i];
|
||||
}
|
||||
@ -1819,7 +1819,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
|
||||
(*elements)[i] = defaultElem;
|
||||
}
|
||||
emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements);
|
||||
ArrayLiteralExp aae = cast(ArrayLiteralExp)pue.exp();
|
||||
ArrayLiteralExp aae = pue.exp().isArrayLiteralExp();
|
||||
aae.ownedByCtfe = OwnedBy.ctfe;
|
||||
}
|
||||
return pue.exp();
|
||||
@ -1874,14 +1874,14 @@ bool isCtfeValueValid(Expression newval)
|
||||
{
|
||||
// &struct.func or &clasinst.func
|
||||
// &nestedfunc
|
||||
Expression ethis = (cast(DelegateExp)newval).e1;
|
||||
return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
|
||||
Expression ethis = newval.isDelegateExp().e1;
|
||||
return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && ethis.isVarExp().var == newval.isDelegateExp().func);
|
||||
}
|
||||
|
||||
case EXP.symbolOffset:
|
||||
{
|
||||
// function pointer, or pointer to static variable
|
||||
Declaration d = (cast(SymOffExp)newval).var;
|
||||
Declaration d = newval.isSymOffExp().var;
|
||||
return d.isFuncDeclaration() || d.isDataseg();
|
||||
}
|
||||
|
||||
@ -1894,7 +1894,7 @@ bool isCtfeValueValid(Expression newval)
|
||||
case EXP.address:
|
||||
{
|
||||
// e1 should be a CTFE reference
|
||||
Expression e1 = (cast(AddrExp)newval).e1;
|
||||
Expression e1 = newval.isAddrExp().e1;
|
||||
return tb.ty == Tpointer &&
|
||||
(
|
||||
(e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
|
||||
@ -1908,7 +1908,7 @@ bool isCtfeValueValid(Expression newval)
|
||||
case EXP.slice:
|
||||
{
|
||||
// e1 should be an array aggregate
|
||||
const SliceExp se = cast(SliceExp)newval;
|
||||
const SliceExp se = newval.isSliceExp();
|
||||
assert(se.lwr && se.lwr.op == EXP.int64);
|
||||
assert(se.upr && se.upr.op == EXP.int64);
|
||||
return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
|
||||
@ -1932,7 +1932,7 @@ bool isCtfeReferenceValid(Expression newval)
|
||||
|
||||
case EXP.variable:
|
||||
{
|
||||
const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration();
|
||||
const VarDeclaration v = newval.isVarExp().var.isVarDeclaration();
|
||||
assert(v);
|
||||
// Must not be a reference to a reference
|
||||
return true;
|
||||
@ -1940,13 +1940,13 @@ bool isCtfeReferenceValid(Expression newval)
|
||||
|
||||
case EXP.index:
|
||||
{
|
||||
const Expression eagg = (cast(IndexExp)newval).e1;
|
||||
const Expression eagg = newval.isIndexExp().e1;
|
||||
return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral;
|
||||
}
|
||||
|
||||
case EXP.dotVariable:
|
||||
{
|
||||
Expression eagg = (cast(DotVarExp)newval).e1;
|
||||
Expression eagg = newval.isDotVarExp().e1;
|
||||
return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg);
|
||||
}
|
||||
|
||||
@ -1968,19 +1968,19 @@ void showCtfeExpr(Expression e, int level = 0)
|
||||
ClassDeclaration cd = null;
|
||||
if (e.op == EXP.structLiteral)
|
||||
{
|
||||
elements = (cast(StructLiteralExp)e).elements;
|
||||
sd = (cast(StructLiteralExp)e).sd;
|
||||
elements = e.isStructLiteralExp().elements;
|
||||
sd = e.isStructLiteralExp().sd;
|
||||
printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
|
||||
}
|
||||
else if (e.op == EXP.classReference)
|
||||
{
|
||||
elements = (cast(ClassReferenceExp)e).value.elements;
|
||||
cd = (cast(ClassReferenceExp)e).originalClass();
|
||||
printf("CLASS type = %s %p:\n", e.type.toChars(), (cast(ClassReferenceExp)e).value);
|
||||
elements = e.isClassReferenceExp().value.elements;
|
||||
cd = e.isClassReferenceExp().originalClass();
|
||||
printf("CLASS type = %s %p:\n", e.type.toChars(), e.isClassReferenceExp().value);
|
||||
}
|
||||
else if (e.op == EXP.arrayLiteral)
|
||||
{
|
||||
elements = (cast(ArrayLiteralExp)e).elements;
|
||||
elements = e.isArrayLiteralExp().elements;
|
||||
printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
|
||||
}
|
||||
else if (e.op == EXP.assocArrayLiteral)
|
||||
@ -1994,19 +1994,19 @@ void showCtfeExpr(Expression e, int level = 0)
|
||||
else if (e.op == EXP.slice)
|
||||
{
|
||||
printf("SLICE %p: %s\n", e, e.toChars());
|
||||
showCtfeExpr((cast(SliceExp)e).e1, level + 1);
|
||||
showCtfeExpr(e.isSliceExp().e1, level + 1);
|
||||
}
|
||||
else if (e.op == EXP.variable)
|
||||
{
|
||||
printf("VAR %p %s\n", e, e.toChars());
|
||||
VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
|
||||
VarDeclaration v = e.isVarExp().var.isVarDeclaration();
|
||||
if (v && getValue(v))
|
||||
showCtfeExpr(getValue(v), level + 1);
|
||||
}
|
||||
else if (e.op == EXP.address)
|
||||
{
|
||||
// This is potentially recursive. We mustn't try to print the thing we're pointing to.
|
||||
printf("POINTER %p to %p: %s\n", e, (cast(AddrExp)e).e1, e.toChars());
|
||||
printf("POINTER %p to %p: %s\n", e, e.isAddrExp().e1, e.toChars());
|
||||
}
|
||||
else
|
||||
printf("VALUE %p: %s\n", e, e.toChars());
|
||||
@ -2086,7 +2086,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var)
|
||||
(*elements)[i] = elem;
|
||||
}
|
||||
emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements);
|
||||
ArrayLiteralExp ae = cast(ArrayLiteralExp)ue.exp();
|
||||
ArrayLiteralExp ae = ue.exp().isArrayLiteralExp();
|
||||
ae.ownedByCtfe = OwnedBy.ctfe;
|
||||
}
|
||||
else if (t.ty == Tstruct)
|
||||
@ -2098,7 +2098,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var)
|
||||
(*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy();
|
||||
}
|
||||
emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps);
|
||||
StructLiteralExp se = cast(StructLiteralExp)ue.exp();
|
||||
StructLiteralExp se = ue.exp().isStructLiteralExp();
|
||||
se.type = ts;
|
||||
se.ownedByCtfe = OwnedBy.ctfe;
|
||||
}
|
||||
|
@ -222,4 +222,3 @@ bool mergeFieldInit(ref CSX a, const CSX b) pure nothrow
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -3880,4 +3880,3 @@ IntRange getIntRange(Expression e)
|
||||
case EXP.negate : return visitNeg(e.isNegExp());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ extern (C++) abstract class Declaration : Dsymbol
|
||||
* postblit. Print the first field that has
|
||||
* a disabled postblit.
|
||||
*/
|
||||
if (postblit.generated)
|
||||
if (postblit.isGenerated())
|
||||
{
|
||||
auto sd = p.isStructDeclaration();
|
||||
assert(sd);
|
||||
@ -334,7 +334,7 @@ extern (C++) abstract class Declaration : Dsymbol
|
||||
|
||||
if (auto ctor = isCtorDeclaration())
|
||||
{
|
||||
if (ctor.isCpCtor && ctor.generated)
|
||||
if (ctor.isCpCtor && ctor.isGenerated())
|
||||
{
|
||||
.error(loc, "Generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars());
|
||||
return true;
|
||||
@ -1060,24 +1060,51 @@ extern (C++) class VarDeclaration : Declaration
|
||||
enum AdrOnStackNone = ~0u;
|
||||
uint ctfeAdrOnStack;
|
||||
|
||||
bool isargptr; // if parameter that _argptr points to
|
||||
bool ctorinit; // it has been initialized in a ctor
|
||||
bool iscatchvar; // this is the exception object variable in catch() clause
|
||||
bool isowner; // this is an Owner, despite it being `scope`
|
||||
bool setInCtorOnly; // field can only be set in a constructor, as it is const or immutable
|
||||
// `bool` fields that are compacted into bit fields in a string mixin
|
||||
private extern (D) static struct BitFields
|
||||
{
|
||||
bool isargptr; /// if parameter that _argptr points to
|
||||
bool ctorinit; /// it has been initialized in a ctor
|
||||
bool iscatchvar; /// this is the exception object variable in catch() clause
|
||||
bool isowner; /// this is an Owner, despite it being `scope`
|
||||
bool setInCtorOnly; /// field can only be set in a constructor, as it is const or immutable
|
||||
|
||||
// Both these mean the var is not rebindable once assigned,
|
||||
// and the destructor gets run when it goes out of scope
|
||||
bool onstack; // it is a class that was allocated on the stack
|
||||
/// It is a class that was allocated on the stack
|
||||
///
|
||||
/// This means the var is not rebindable once assigned,
|
||||
/// and the destructor gets run when it goes out of scope
|
||||
bool onstack;
|
||||
|
||||
bool overlapped; /// if it is a field and has overlapping
|
||||
bool overlapUnsafe; /// if it is an overlapping field and the overlaps are unsafe
|
||||
bool doNotInferScope; /// do not infer 'scope' for this variable
|
||||
bool doNotInferReturn; /// do not infer 'return' for this variable
|
||||
|
||||
bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument
|
||||
}
|
||||
|
||||
private ushort bitFields; // stores multiple booleans for BitFields
|
||||
byte canassign; // it can be assigned to
|
||||
bool overlapped; // if it is a field and has overlapping
|
||||
bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
|
||||
bool doNotInferScope; // do not infer 'scope' for this variable
|
||||
bool doNotInferReturn; // do not infer 'return' for this variable
|
||||
ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false
|
||||
|
||||
bool isArgDtorVar; // temporary created to handle scope destruction of a function argument
|
||||
// Generate getter and setter functions for `bitFields`
|
||||
extern (D) mixin(() {
|
||||
string result = "extern (C++) pure nothrow @nogc @safe final {";
|
||||
foreach (size_t i, mem; __traits(allMembers, BitFields))
|
||||
{
|
||||
result ~= "
|
||||
/// set or get the corresponding BitFields member
|
||||
bool "~mem~"() const { return !!(bitFields & (1 << "~i.stringof~")); }
|
||||
/// ditto
|
||||
bool "~mem~"(bool v)
|
||||
{
|
||||
v ? (bitFields |= (1 << "~i.stringof~")) : (bitFields &= ~(1 << "~i.stringof~"));
|
||||
return v;
|
||||
}";
|
||||
}
|
||||
return result ~ "}";
|
||||
}());
|
||||
|
||||
|
||||
final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
|
||||
in
|
||||
@ -1642,64 +1669,6 @@ extern (C++) class VarDeclaration : Declaration
|
||||
{
|
||||
v.visit(this);
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Determine if `this` has a lifetime that lasts past
|
||||
* the destruction of `v`
|
||||
* Params:
|
||||
* v = variable to test against
|
||||
* Returns:
|
||||
* true if it does
|
||||
*/
|
||||
final bool enclosesLifetimeOf(VarDeclaration v) const pure
|
||||
{
|
||||
// VarDeclaration's with these STC's need special treatment
|
||||
enum special = STC.temp | STC.foreach_;
|
||||
|
||||
// Sequence numbers work when there are no special VarDeclaration's involved
|
||||
if (!((this.storage_class | v.storage_class) & special))
|
||||
{
|
||||
assert(this.sequenceNumber != this.sequenceNumber.init);
|
||||
assert(v.sequenceNumber != v.sequenceNumber.init);
|
||||
|
||||
return (this.sequenceNumber < v.sequenceNumber);
|
||||
}
|
||||
|
||||
// Assume that semantic produces temporaries according to their lifetime
|
||||
// (It won't create a temporary before the actual content)
|
||||
if ((this.storage_class & special) && (v.storage_class & special))
|
||||
return this.sequenceNumber < v.sequenceNumber;
|
||||
|
||||
// Fall back to lexical order
|
||||
assert(this.loc != Loc.initial);
|
||||
assert(v.loc != Loc.initial);
|
||||
|
||||
if (this.loc.linnum != v.loc.linnum)
|
||||
return this.loc.linnum < v.loc.linnum;
|
||||
|
||||
if (this.loc.charnum != v.loc.charnum)
|
||||
return this.loc.charnum < v.loc.charnum;
|
||||
|
||||
// Default fallback
|
||||
return this.sequenceNumber < v.sequenceNumber;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Add variable to maybes[].
|
||||
* When a maybescope variable `v` is assigned to a maybescope variable `this`,
|
||||
* we cannot determine if `this` is actually scope until the semantic
|
||||
* analysis for the function is completed. Thus, we save the data
|
||||
* until then.
|
||||
* Params:
|
||||
* v = an STC.maybescope variable that was assigned to `this`
|
||||
*/
|
||||
final void addMaybe(VarDeclaration v)
|
||||
{
|
||||
//printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
|
||||
if (!maybes)
|
||||
maybes = new VarDeclarations();
|
||||
maybes.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************
|
||||
|
@ -241,22 +241,33 @@ public:
|
||||
// When interpreting, these point to the value (NULL if value not determinable)
|
||||
// The index of this variable on the CTFE stack, ~0u if not allocated
|
||||
unsigned ctfeAdrOnStack;
|
||||
|
||||
bool isargptr; // if parameter that _argptr points to
|
||||
bool ctorinit; // it has been initialized in a ctor
|
||||
bool iscatchvar; // this is the exception object variable in catch() clause
|
||||
bool isowner; // this is an Owner, despite it being `scope`
|
||||
bool setInCtorOnly; // field can only be set in a constructor, as it is const or immutable
|
||||
bool onstack; // it is a class that was allocated on the stack
|
||||
char canassign; // it can be assigned to
|
||||
bool overlapped; // if it is a field and has overlapping
|
||||
bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
|
||||
bool doNotInferScope; // do not infer 'scope' for this variable
|
||||
bool doNotInferReturn; // do not infer 'return' for this variable
|
||||
unsigned char isdataseg; // private data for isDataseg
|
||||
bool isArgDtorVar; // temporary created to handle scope destruction of a function argument
|
||||
|
||||
private:
|
||||
uint16_t bitFields;
|
||||
public:
|
||||
int8_t canassign; // // it can be assigned to
|
||||
uint8_t isdataseg; // private data for isDataseg
|
||||
bool isargptr() const; // if parameter that _argptr points to
|
||||
bool isargptr(bool v);
|
||||
bool ctorinit() const; // it has been initialized in a ctor
|
||||
bool ctorinit(bool v);
|
||||
bool iscatchvar() const; // this is the exception object variable in catch() clause
|
||||
bool iscatchvar(bool v);
|
||||
bool isowner() const; // this is an Owner, despite it being `scope`
|
||||
bool isowner(bool v);
|
||||
bool setInCtorOnly() const; // field can only be set in a constructor, as it is const or immutable
|
||||
bool setInCtorOnly(bool v);
|
||||
bool onstack() const; // it is a class that was allocated on the stack
|
||||
bool onstack(bool v);
|
||||
bool overlapped() const; // if it is a field and has overlapping
|
||||
bool overlapped(bool v);
|
||||
bool overlapUnsafe() const; // if it is an overlapping field and the overlaps are unsafe
|
||||
bool overlapUnsafe(bool v);
|
||||
bool doNotInferScope() const; // do not infer 'scope' for this variable
|
||||
bool doNotInferScope(bool v);
|
||||
bool doNotInferReturn() const; // do not infer 'return' for this variable
|
||||
bool doNotInferReturn(bool v);
|
||||
bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument
|
||||
bool isArgDtorVar(bool v);
|
||||
static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
|
||||
VarDeclaration *syntaxCopy(Dsymbol *);
|
||||
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
|
||||
@ -273,7 +284,6 @@ public:
|
||||
bool hasPointers();
|
||||
bool canTakeAddressOf();
|
||||
bool needsScopeDtor();
|
||||
bool enclosesLifetimeOf(VarDeclaration *v) const;
|
||||
void checkCtorConstInit();
|
||||
Dsymbol *toAlias();
|
||||
// Eliminate need for dynamic_cast
|
||||
@ -541,7 +551,6 @@ public:
|
||||
// scopes from having the same name
|
||||
DsymbolTable *localsymtab;
|
||||
VarDeclaration *vthis; // 'this' parameter (member and nested)
|
||||
bool isThis2; // has a dual-context 'this' parameter
|
||||
VarDeclaration *v_arguments; // '_arguments' parameter
|
||||
|
||||
VarDeclaration *v_argptr; // '_argptr' variable
|
||||
@ -551,29 +560,20 @@ public:
|
||||
FuncDeclaration *overnext0; // next in overload list (only used during IFTI)
|
||||
Loc endloc; // location of closing curly bracket
|
||||
int vtblIndex; // for member functions, index into vtbl[]
|
||||
bool naked; // true if naked
|
||||
bool generated; // true if function was generated by the compiler rather than
|
||||
// supplied by the user
|
||||
bool hasAlwaysInlines; // contains references to functions that must be inlined
|
||||
unsigned char isCrtCtorDtor; // has attribute pragma(crt_constructor(1)/crt_destructor(2))
|
||||
// not set before the glue layer
|
||||
|
||||
ILS inlineStatusStmt;
|
||||
ILS inlineStatusExp;
|
||||
PINLINE inlining;
|
||||
|
||||
int inlineNest; // !=0 if nested inline
|
||||
bool eh_none; /// true if no exception unwinding is needed
|
||||
|
||||
// true if errors in semantic3 this function's frame ptr
|
||||
bool semantic3Errors;
|
||||
ForeachStatement *fes; // if foreach body, this is the foreach
|
||||
BaseClass* interfaceVirtual; // if virtual, but only appears in interface vtbl[]
|
||||
bool introducing; // true if 'introducing' function
|
||||
// if !=NULL, then this is the type
|
||||
// of the 'introducing' function
|
||||
// this one is overriding
|
||||
Type *tintro;
|
||||
bool inferRetType; // true if return type is to be inferred
|
||||
StorageClass storage_class2; // storage class for template onemember's
|
||||
|
||||
// Things that should really go into Scope
|
||||
@ -585,8 +585,6 @@ public:
|
||||
// 16 if there are multiple return statements
|
||||
int hasReturnExp;
|
||||
|
||||
// Support for NRVO (named return value optimization)
|
||||
bool nrvo_can; // true means we can do it
|
||||
VarDeclaration *nrvo_var; // variable to replace with shidden
|
||||
Symbol *shidden; // hidden pointer passed to function
|
||||
|
||||
@ -654,6 +652,19 @@ public:
|
||||
|
||||
bool isNogc();
|
||||
bool isNogcBypassingInference();
|
||||
bool isNRVO() const;
|
||||
void isNRVO(bool v);
|
||||
bool isNaked() const;
|
||||
bool isGenerated() const;
|
||||
void isGenerated(bool v);
|
||||
bool isIntroducing() const;
|
||||
bool hasSemantic3Errors() const;
|
||||
bool hasNoEH() const;
|
||||
bool inferRetType() const;
|
||||
bool hasDualContext() const;
|
||||
bool hasAlwaysInlines() const;
|
||||
bool isCrtCtor() const;
|
||||
bool isCrtDtor() const;
|
||||
|
||||
virtual bool isNested() const;
|
||||
AggregateDeclaration *isThis();
|
||||
|
@ -96,7 +96,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
|
||||
|
||||
override void setScope(Scope* sc)
|
||||
{
|
||||
if (semanticRun > PASS.init)
|
||||
if (semanticRun > PASS.initial)
|
||||
return;
|
||||
ScopeDsymbol.setScope(sc);
|
||||
}
|
||||
@ -163,6 +163,9 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
|
||||
if (defaultval)
|
||||
return defaultval;
|
||||
|
||||
if (isCsymbol())
|
||||
return memtype.defaultInit(loc, true);
|
||||
|
||||
if (_scope)
|
||||
dsymbolSemantic(this, _scope);
|
||||
if (errors)
|
||||
|
@ -535,7 +535,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
|
||||
istatex.caller = istate;
|
||||
istatex.fd = fd;
|
||||
|
||||
if (fd.isThis2)
|
||||
if (fd.hasDualContext())
|
||||
{
|
||||
Expression arg0 = thisarg;
|
||||
if (arg0 && arg0.type.ty == Tstruct)
|
||||
@ -678,7 +678,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
|
||||
e = CTFEExp.voidexp;
|
||||
if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
|
||||
e = thisarg;
|
||||
if (tf.isref && fd.isThis2 && e.op == EXP.index)
|
||||
if (tf.isref && fd.hasDualContext() && e.op == EXP.index)
|
||||
{
|
||||
auto ie = e.isIndexExp();
|
||||
auto pe = ie.e1.isPtrExp();
|
||||
@ -944,7 +944,7 @@ public:
|
||||
if (auto eaddr = e.isAddrExp())
|
||||
x = eaddr.e1;
|
||||
VarDeclaration v;
|
||||
while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
|
||||
while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
|
||||
{
|
||||
if (v.storage_class & STC.ref_)
|
||||
{
|
||||
@ -1526,7 +1526,7 @@ public:
|
||||
}
|
||||
while ((*boss.value.elements)[next].op == EXP.classReference)
|
||||
{
|
||||
boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
|
||||
boss = (*boss.value.elements)[next].isClassReferenceExp();
|
||||
}
|
||||
(*boss.value.elements)[next] = collateral;
|
||||
return oldest;
|
||||
@ -1752,7 +1752,7 @@ public:
|
||||
if (istate && istate.fd.vthis)
|
||||
{
|
||||
result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
|
||||
if (istate.fd.isThis2)
|
||||
if (istate.fd.hasDualContext())
|
||||
{
|
||||
result = ctfeEmplaceExp!PtrExp(e.loc, result);
|
||||
result.type = Type.tvoidptr.sarrayOf(2);
|
||||
@ -1768,15 +1768,15 @@ public:
|
||||
result = ctfeGlobals.stack.getThis();
|
||||
if (result)
|
||||
{
|
||||
if (istate && istate.fd.isThis2)
|
||||
if (istate && istate.fd.hasDualContext())
|
||||
{
|
||||
assert(result.op == EXP.address);
|
||||
result = (cast(AddrExp)result).e1;
|
||||
result = result.isAddrExp().e1;
|
||||
assert(result.op == EXP.arrayLiteral);
|
||||
result = (*(cast(ArrayLiteralExp)result).elements)[0];
|
||||
result = (*result.isArrayLiteralExp().elements)[0];
|
||||
if (e.type.ty == Tstruct)
|
||||
{
|
||||
result = (cast(AddrExp)result).e1;
|
||||
result = result.isAddrExp().e1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1873,7 +1873,9 @@ public:
|
||||
{
|
||||
fromType = (cast(TypeArray)e.var.type).next;
|
||||
}
|
||||
if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee))))
|
||||
if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) ||
|
||||
(fromType && isSafePointerCast(fromType, pointee)) ||
|
||||
(e.var.isCsymbol() && e.offset + pointee.size() <= e.var.type.size())))
|
||||
{
|
||||
result = e;
|
||||
return;
|
||||
@ -1980,7 +1982,7 @@ public:
|
||||
if (decl.isDataseg()) {
|
||||
// Normally this is already done by optimize()
|
||||
// Do it here in case optimize(WANTvalue) wasn't run before CTFE
|
||||
emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0);
|
||||
emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0);
|
||||
result = pue.exp();
|
||||
result.type = e.type;
|
||||
return;
|
||||
@ -2399,7 +2401,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass();
|
||||
ClassDeclaration cd = result.isClassReferenceExp().originalClass();
|
||||
assert(cd);
|
||||
|
||||
emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
|
||||
@ -2487,7 +2489,7 @@ public:
|
||||
else
|
||||
{
|
||||
// segfault bug 6250
|
||||
assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e);
|
||||
assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
|
||||
|
||||
ex = interpretRegion(exp, istate);
|
||||
if (exceptionOrCant(ex))
|
||||
@ -2521,7 +2523,7 @@ public:
|
||||
return;
|
||||
}
|
||||
emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
|
||||
auto ale = cast(ArrayLiteralExp)pue.exp();
|
||||
auto ale = pue.exp().isArrayLiteralExp();
|
||||
ale.ownedByCtfe = OwnedBy.ctfe;
|
||||
result = ale;
|
||||
}
|
||||
@ -2705,7 +2707,7 @@ public:
|
||||
return;
|
||||
}
|
||||
emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
|
||||
auto sle = cast(StructLiteralExp)pue.exp();
|
||||
auto sle = pue.exp().isStructLiteralExp();
|
||||
sle.type = e.type;
|
||||
sle.ownedByCtfe = OwnedBy.ctfe;
|
||||
sle.origin = e.origin;
|
||||
@ -2737,7 +2739,7 @@ public:
|
||||
foreach (ref element; *elements)
|
||||
element = copyLiteral(elem).copy();
|
||||
emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
|
||||
auto ae = cast(ArrayLiteralExp)pue.exp();
|
||||
auto ae = pue.exp().isArrayLiteralExp();
|
||||
ae.ownedByCtfe = OwnedBy.ctfe;
|
||||
return ae;
|
||||
}
|
||||
@ -2959,7 +2961,7 @@ public:
|
||||
result = e; // optimize: reuse this CTFE reference
|
||||
else
|
||||
{
|
||||
auto edt = cast(DotTypeExp)e.copy();
|
||||
auto edt = e.copy().isDotTypeExp();
|
||||
edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
|
||||
result = edt;
|
||||
}
|
||||
@ -3335,7 +3337,7 @@ public:
|
||||
if (exceptionOrCant(newval))
|
||||
return;
|
||||
|
||||
VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration();
|
||||
VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
|
||||
setValue(v, newval);
|
||||
|
||||
// Get the value to return. Note that 'newval' is an Lvalue,
|
||||
@ -3351,7 +3353,7 @@ public:
|
||||
{
|
||||
while (e1.op == EXP.cast_)
|
||||
{
|
||||
CastExp ce = cast(CastExp)e1;
|
||||
CastExp ce = e1.isCastExp();
|
||||
e1 = ce.e1;
|
||||
}
|
||||
}
|
||||
@ -3362,7 +3364,7 @@ public:
|
||||
AssocArrayLiteralExp existingAA = null;
|
||||
Expression lastIndex = null;
|
||||
Expression oldval = null;
|
||||
if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
|
||||
if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
|
||||
{
|
||||
// ---------------------------------------
|
||||
// Deal with AA index assignment
|
||||
@ -3374,12 +3376,12 @@ public:
|
||||
* (2) If the ultimate AA is null, no insertion happens at all. Instead,
|
||||
* we create nested AA literals, and change it into a assignment.
|
||||
*/
|
||||
IndexExp ie = cast(IndexExp)e1;
|
||||
IndexExp ie = e1.isIndexExp();
|
||||
int depth = 0; // how many nested AA indices are there?
|
||||
while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
|
||||
while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
|
||||
{
|
||||
assert(ie.modifiable);
|
||||
ie = cast(IndexExp)ie.e1;
|
||||
ie = ie.e1.isIndexExp();
|
||||
++depth;
|
||||
}
|
||||
|
||||
@ -3392,7 +3394,7 @@ public:
|
||||
// Normal case, ultimate parent AA already exists
|
||||
// We need to walk from the deepest index up, checking that an AA literal
|
||||
// already exists on each level.
|
||||
lastIndex = interpretRegion((cast(IndexExp)e1).e2, istate);
|
||||
lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
|
||||
lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
|
||||
if (exceptionOrCant(lastIndex))
|
||||
return;
|
||||
@ -3400,9 +3402,9 @@ public:
|
||||
while (depth > 0)
|
||||
{
|
||||
// Walk the syntax tree to find the indexExp at this depth
|
||||
IndexExp xe = cast(IndexExp)e1;
|
||||
IndexExp xe = e1.isIndexExp();
|
||||
foreach (d; 0 .. depth)
|
||||
xe = cast(IndexExp)xe.e1;
|
||||
xe = xe.e1.isIndexExp();
|
||||
|
||||
Expression ekey = interpretRegion(xe.e2, istate);
|
||||
if (exceptionOrCant(ekey))
|
||||
@ -3450,9 +3452,9 @@ public:
|
||||
oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
|
||||
|
||||
Expression newaae = oldval;
|
||||
while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
|
||||
while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
|
||||
{
|
||||
Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
|
||||
Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
|
||||
if (exceptionOrCant(ekey))
|
||||
return;
|
||||
ekey = resolveSlice(ekey); // only happens with AA assignment
|
||||
@ -3463,7 +3465,7 @@ public:
|
||||
valuesx.push(newaae);
|
||||
|
||||
auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
|
||||
aae.type = (cast(IndexExp)e1).e1.type;
|
||||
aae.type = e1.isIndexExp().e1.type;
|
||||
aae.ownedByCtfe = OwnedBy.ctfe;
|
||||
if (!existingAA)
|
||||
{
|
||||
@ -3471,7 +3473,7 @@ public:
|
||||
lastIndex = ekey;
|
||||
}
|
||||
newaae = aae;
|
||||
e1 = (cast(IndexExp)e1).e1;
|
||||
e1 = e1.isIndexExp().e1;
|
||||
}
|
||||
|
||||
// We must set to aggregate with newaae
|
||||
@ -3521,11 +3523,11 @@ public:
|
||||
if (exceptionOrCant(e1))
|
||||
return;
|
||||
|
||||
if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
|
||||
if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
|
||||
{
|
||||
IndexExp ie = cast(IndexExp)e1;
|
||||
IndexExp ie = e1.isIndexExp();
|
||||
assert(ie.e1.op == EXP.assocArrayLiteral);
|
||||
existingAA = cast(AssocArrayLiteralExp)ie.e1;
|
||||
existingAA = ie.e1.isAssocArrayLiteralExp();
|
||||
lastIndex = ie.e2;
|
||||
}
|
||||
}
|
||||
@ -3657,7 +3659,7 @@ public:
|
||||
|
||||
// We have changed it into a reference assignment
|
||||
// Note that returnValue is still the new length.
|
||||
e1 = (cast(ArrayLengthExp)e1).e1;
|
||||
e1 = e1.isArrayLengthExp().e1;
|
||||
Type t = e1.type.toBasetype();
|
||||
if (t.ty != Tarray)
|
||||
{
|
||||
@ -3733,8 +3735,8 @@ public:
|
||||
if (auto dve = e1x.isDotVarExp())
|
||||
{
|
||||
auto ex = dve.e1;
|
||||
auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
|
||||
: ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
|
||||
auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
|
||||
: ex.op == EXP.classReference ? ex.isClassReferenceExp().value
|
||||
: null;
|
||||
auto v = dve.var.isVarDeclaration();
|
||||
if (!sle || !v)
|
||||
@ -3792,10 +3794,10 @@ public:
|
||||
* e.v = newval
|
||||
*/
|
||||
auto ex = dve.e1;
|
||||
auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
|
||||
: ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
|
||||
auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
|
||||
: ex.op == EXP.classReference ? ex.isClassReferenceExp().value
|
||||
: null;
|
||||
auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
|
||||
auto v = e1.isDotVarExp().var.isVarDeclaration();
|
||||
if (!sle || !v)
|
||||
{
|
||||
e.error("CTFE internal error: dotvar assignment");
|
||||
@ -3808,7 +3810,7 @@ public:
|
||||
}
|
||||
|
||||
int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
|
||||
: (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
|
||||
: ex.isClassReferenceExp().findFieldIndexByName(v);
|
||||
if (fieldi == -1)
|
||||
{
|
||||
e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
|
||||
@ -3865,7 +3867,7 @@ public:
|
||||
return CTFEExp.cantexp;
|
||||
}
|
||||
|
||||
ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate;
|
||||
ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
|
||||
if (existingAE.ownedByCtfe != OwnedBy.ctfe)
|
||||
{
|
||||
e.error("cannot modify read-only constant `%s`", existingAE.toChars());
|
||||
@ -3920,8 +3922,8 @@ public:
|
||||
assert(oldval.op == EXP.arrayLiteral);
|
||||
assert(newval.op == EXP.arrayLiteral);
|
||||
|
||||
Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
|
||||
Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
|
||||
Expressions* oldelems = oldval.isArrayLiteralExp().elements;
|
||||
Expressions* newelems = newval.isArrayLiteralExp().elements;
|
||||
assert(oldelems.dim == newelems.dim);
|
||||
|
||||
Type elemtype = oldval.type.nextOf();
|
||||
@ -4124,7 +4126,7 @@ public:
|
||||
|
||||
if (newval.op == EXP.slice && !isBlockAssignment)
|
||||
{
|
||||
auto se = cast(SliceExp)newval;
|
||||
auto se = newval.isSliceExp();
|
||||
auto aggr2 = se.e1;
|
||||
const srclower = se.lwr.toInteger();
|
||||
const srcupper = se.upr.toInteger();
|
||||
@ -4140,7 +4142,7 @@ public:
|
||||
// https://issues.dlang.org/show_bug.cgi?id=14024
|
||||
assert(aggr2.op == EXP.arrayLiteral);
|
||||
Expressions* oldelems = existingAE.elements;
|
||||
Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
|
||||
Expressions* newelems = aggr2.isArrayLiteralExp().elements;
|
||||
|
||||
Type elemtype = aggregate.type.nextOf();
|
||||
bool needsPostblit = e.e2.isLvalue();
|
||||
@ -4213,13 +4215,13 @@ public:
|
||||
/* Mixed slice: it was initialized as an array literal of chars/integers.
|
||||
* Now a slice of it is being set with a string.
|
||||
*/
|
||||
sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex);
|
||||
sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
|
||||
return newval;
|
||||
}
|
||||
if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
|
||||
{
|
||||
Expressions* oldelems = existingAE.elements;
|
||||
Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
|
||||
Expressions* newelems = newval.isArrayLiteralExp().elements;
|
||||
Type elemtype = existingAE.type.nextOf();
|
||||
bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
|
||||
foreach (j, newelem; *newelems)
|
||||
@ -4264,7 +4266,7 @@ public:
|
||||
if (!directblk && (*w)[k].op == EXP.arrayLiteral)
|
||||
{
|
||||
// Multidimensional array block assign
|
||||
if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
|
||||
if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
|
||||
return ex;
|
||||
}
|
||||
else if (refCopy)
|
||||
@ -4420,7 +4422,7 @@ public:
|
||||
while (e.op == EXP.not)
|
||||
{
|
||||
ret *= -1;
|
||||
e = (cast(NotExp)e).e1;
|
||||
e = e.isNotExp().e1;
|
||||
}
|
||||
switch (e.op)
|
||||
{
|
||||
@ -4430,8 +4432,8 @@ public:
|
||||
goto case; /+ fall through +/
|
||||
case EXP.greaterThan:
|
||||
case EXP.greaterOrEqual:
|
||||
*p1 = (cast(BinExp)e).e1;
|
||||
*p2 = (cast(BinExp)e).e2;
|
||||
*p1 = e.isBinExp().e1;
|
||||
*p2 = e.isBinExp().e2;
|
||||
if (!(isPointer((*p1).type) && isPointer((*p2).type)))
|
||||
ret = 0;
|
||||
break;
|
||||
@ -4898,7 +4900,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors)
|
||||
if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
|
||||
{
|
||||
e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
|
||||
result = CTFEExp.cantexp;
|
||||
@ -5201,7 +5203,7 @@ public:
|
||||
// Pointer to a non-array variable
|
||||
if (agg.op == EXP.symbolOffset)
|
||||
{
|
||||
e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), (cast(SymOffExp)agg).var.toChars());
|
||||
e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5285,7 +5287,7 @@ public:
|
||||
e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
|
||||
return false;
|
||||
}
|
||||
*pagg = (cast(SliceExp)e1).e1;
|
||||
*pagg = e1.isSliceExp().e1;
|
||||
*pidx = index + ilwr;
|
||||
}
|
||||
else
|
||||
@ -5377,7 +5379,7 @@ public:
|
||||
assert(e1.op == EXP.assocArrayLiteral);
|
||||
UnionExp e2tmp = void;
|
||||
e2 = resolveSlice(e2, &e2tmp);
|
||||
result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2);
|
||||
result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
|
||||
if (!result)
|
||||
{
|
||||
e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
|
||||
@ -5637,7 +5639,7 @@ public:
|
||||
}
|
||||
|
||||
e1 = resolveSlice(e1);
|
||||
result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e2, e1);
|
||||
result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
|
||||
if (exceptionOrCant(result))
|
||||
return;
|
||||
if (!result)
|
||||
@ -5742,7 +5744,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto cre = cast(ClassReferenceExp)result;
|
||||
auto cre = result.isClassReferenceExp();
|
||||
auto cd = cre.originalClass();
|
||||
|
||||
// Find dtor(s) in inheritance chain
|
||||
@ -5859,10 +5861,10 @@ public:
|
||||
result = pue.exp();
|
||||
return;
|
||||
}
|
||||
if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
|
||||
if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
|
||||
{
|
||||
// type painting operation
|
||||
IndexExp ie = cast(IndexExp)e1;
|
||||
IndexExp ie = e1.isIndexExp();
|
||||
if (castBackFromVoid)
|
||||
{
|
||||
// get the original type. For strings, it's just the type...
|
||||
@ -5870,7 +5872,7 @@ public:
|
||||
// ..but for arrays of type void*, it's the type of the element
|
||||
if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
|
||||
{
|
||||
ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
|
||||
ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
|
||||
const indx = cast(size_t)ie.e2.toInteger();
|
||||
if (indx < ale.elements.dim)
|
||||
{
|
||||
@ -5912,7 +5914,7 @@ public:
|
||||
{
|
||||
// &val[idx]
|
||||
dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
|
||||
IndexExp ie = cast(IndexExp)ae.e1;
|
||||
IndexExp ie = ae.e1.isIndexExp();
|
||||
Expression lwr = ie.e2;
|
||||
Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
|
||||
|
||||
@ -5938,7 +5940,7 @@ public:
|
||||
if (auto ve = e1.isVarExp())
|
||||
emplaceExp!(VarExp)(pue, e.loc, ve.var);
|
||||
else
|
||||
emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset);
|
||||
emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
|
||||
result = pue.exp();
|
||||
result.type = e.to;
|
||||
return;
|
||||
@ -5966,7 +5968,7 @@ public:
|
||||
{
|
||||
// Note that the slice may be void[], so when checking for dangerous
|
||||
// casts, we need to use the original type, which is se.e1.
|
||||
SliceExp se = cast(SliceExp)e1;
|
||||
SliceExp se = e1.isSliceExp();
|
||||
if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
|
||||
{
|
||||
e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
|
||||
@ -6086,7 +6088,7 @@ public:
|
||||
{
|
||||
if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
|
||||
{
|
||||
AddrExp ade = cast(AddrExp)ae.e1;
|
||||
AddrExp ade = ae.e1.isAddrExp();
|
||||
Expression ex = interpretRegion(ade.e1, istate);
|
||||
if (exceptionOrCant(ex))
|
||||
return;
|
||||
@ -6131,7 +6133,7 @@ public:
|
||||
}
|
||||
|
||||
// *(&x) ==> x
|
||||
result = (cast(AddrExp)result).e1;
|
||||
result = result.isAddrExp().e1;
|
||||
|
||||
if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
|
||||
{
|
||||
@ -6211,8 +6213,8 @@ public:
|
||||
// We can't use getField, because it makes a copy
|
||||
if (ex.op == EXP.classReference)
|
||||
{
|
||||
se = (cast(ClassReferenceExp)ex).value;
|
||||
i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
|
||||
se = ex.isClassReferenceExp().value;
|
||||
i = ex.isClassReferenceExp().findFieldIndexByName(v);
|
||||
}
|
||||
else if (ex.op == EXP.typeid_)
|
||||
{
|
||||
@ -6233,7 +6235,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
se = cast(StructLiteralExp)ex;
|
||||
se = ex.isStructLiteralExp();
|
||||
i = findFieldIndexByName(se.sd, v);
|
||||
}
|
||||
if (i == -1)
|
||||
@ -6540,7 +6542,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e)
|
||||
|
||||
if (e.op == EXP.classReference)
|
||||
{
|
||||
StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
|
||||
StructLiteralExp sle = e.isClassReferenceExp().value;
|
||||
if (auto ex = scrubSE(sle))
|
||||
return ex;
|
||||
}
|
||||
@ -6620,7 +6622,7 @@ private Expression scrubCacheValue(Expression e)
|
||||
|
||||
if (e.op == EXP.classReference)
|
||||
{
|
||||
if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
|
||||
if (auto ex = scrubSE(e.isClassReferenceExp().value))
|
||||
return ex;
|
||||
}
|
||||
else if (auto sle = e.isStructLiteralExp())
|
||||
@ -6767,14 +6769,14 @@ private Expression copyRegionExp(Expression e)
|
||||
case EXP.vector:
|
||||
case EXP.dotVariable:
|
||||
{
|
||||
UnaExp ue = cast(UnaExp)e;
|
||||
UnaExp ue = e.isUnaExp();
|
||||
ue.e1 = copyRegionExp(ue.e1);
|
||||
break;
|
||||
}
|
||||
|
||||
case EXP.index:
|
||||
{
|
||||
BinExp be = cast(BinExp)e;
|
||||
BinExp be = e.isBinExp();
|
||||
be.e1 = copyRegionExp(be.e1);
|
||||
be.e2 = copyRegionExp(be.e2);
|
||||
break;
|
||||
@ -6939,7 +6941,7 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi
|
||||
|
||||
Expressions args = Expressions(numParams);
|
||||
|
||||
AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa;
|
||||
AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
|
||||
if (!ae.keys || ae.keys.dim == 0)
|
||||
return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
|
||||
Expression eresult;
|
||||
@ -7298,7 +7300,7 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const re
|
||||
{
|
||||
// At present, the constructors just copy their arguments into the struct.
|
||||
// But we might need some magic if stack tracing gets added to druntime.
|
||||
StructLiteralExp se = (cast(ClassReferenceExp)pthis).value;
|
||||
StructLiteralExp se = pthis.isClassReferenceExp().value;
|
||||
assert(arguments.dim <= se.elements.dim);
|
||||
foreach (i, arg; *arguments)
|
||||
{
|
||||
|
@ -991,10 +991,6 @@ public:
|
||||
if (stc & STC.returninferred)
|
||||
stc &= ~(STC.return_ | STC.returninferred);
|
||||
|
||||
// 'return inout ref' is the same as 'inout ref'
|
||||
if ((stc & (STC.return_ | STC.wild)) == (STC.return_ | STC.wild))
|
||||
stc &= ~STC.return_;
|
||||
|
||||
// much like hdrgen.stcToBuffer()
|
||||
string rrs;
|
||||
const isout = (stc & STC.out_) != 0;
|
||||
@ -1365,5 +1361,3 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -662,7 +662,7 @@ extern (C++) final class Module : Package
|
||||
return true; // already read
|
||||
|
||||
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
|
||||
if (auto result = FileManager.fileManager.lookup(srcfile))
|
||||
if (auto result = global.fileManager.lookup(srcfile))
|
||||
{
|
||||
this.src = result.data;
|
||||
if (global.params.emitMakeDeps)
|
||||
|
@ -708,6 +708,31 @@ struct Scope
|
||||
return null;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Find the lexically enclosing function (if any).
|
||||
*
|
||||
* This function skips through generated FuncDeclarations,
|
||||
* e.g. rewritten foreach bodies.
|
||||
*
|
||||
* Returns: the function or null
|
||||
*/
|
||||
inout(FuncDeclaration) getEnclosingFunction() inout
|
||||
{
|
||||
if (!this.func)
|
||||
return null;
|
||||
|
||||
auto fd = cast(FuncDeclaration) this.func;
|
||||
|
||||
// Look through foreach bodies rewritten as delegates
|
||||
while (fd.fes)
|
||||
{
|
||||
assert(fd.fes.func);
|
||||
fd = fd.fes.func;
|
||||
}
|
||||
|
||||
return cast(inout(FuncDeclaration)) fd;
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* For TemplateDeclarations, we need to remember the Scope
|
||||
* where it was declared. So mark the Scope as not
|
||||
|
@ -190,7 +190,7 @@ struct Visibility
|
||||
|
||||
enum PASS : ubyte
|
||||
{
|
||||
init, // initial state
|
||||
initial, // initial state
|
||||
semantic, // semantic() started
|
||||
semanticdone, // semantic() done
|
||||
semantic2, // semantic2() started
|
||||
@ -249,7 +249,7 @@ extern (C++) class Dsymbol : ASTNode
|
||||
Scope* _scope; // !=null means context to use for semantic()
|
||||
const(char)* prettystring; // cached value of toPrettyChars()
|
||||
bool errors; // this symbol failed to pass semantic()
|
||||
PASS semanticRun = PASS.init;
|
||||
PASS semanticRun = PASS.initial;
|
||||
ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
|
||||
|
||||
DeprecatedDeclaration depdecl; // customized deprecation message
|
||||
@ -621,7 +621,7 @@ extern (C++) class Dsymbol : ASTNode
|
||||
static bool has2This(Dsymbol s)
|
||||
{
|
||||
if (auto f = s.isFuncDeclaration())
|
||||
return f.isThis2;
|
||||
return f.hasDualContext();
|
||||
if (auto ad = s.isAggregateDeclaration())
|
||||
return ad.vthis2 !is null;
|
||||
return false;
|
||||
@ -2399,6 +2399,7 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
|
||||
{
|
||||
enum log = false;
|
||||
if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
|
||||
if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
|
||||
auto sd = s.isScopeDsymbol(); // new declaration
|
||||
auto sd2 = s2.isScopeDsymbol(); // existing declaration
|
||||
|
||||
@ -2457,6 +2458,7 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
|
||||
sc._module.tagSymTab[cast(void*)s] = s2;
|
||||
return s;
|
||||
}
|
||||
// neither s2 nor s is a tag
|
||||
if (log) printf(" collision\n");
|
||||
return null;
|
||||
}
|
||||
@ -2483,6 +2485,7 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
|
||||
{
|
||||
enum log = false;
|
||||
if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
|
||||
if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
|
||||
|
||||
static Dsymbol collision()
|
||||
{
|
||||
@ -2552,8 +2555,16 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
|
||||
|
||||
if (fd.fbody) // fd is the definition
|
||||
{
|
||||
if (log) printf(" replace existing with new\n");
|
||||
sds.symtab.update(fd); // replace fd2 in symbol table with fd
|
||||
fd.overnext = fd2;
|
||||
|
||||
/* If fd2 is covering a tag symbol, then fd has to cover the same one
|
||||
*/
|
||||
auto ps = cast(void*)fd2 in sc._module.tagSymTab;
|
||||
if (ps)
|
||||
sc._module.tagSymTab[cast(void*)fd] = *ps;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ struct Visibility
|
||||
*/
|
||||
enum class PASS : uint8_t
|
||||
{
|
||||
init, // initial state
|
||||
initial, // initial state
|
||||
semantic, // semantic() started
|
||||
semanticdone, // semantic() done
|
||||
semantic2, // semantic2() started
|
||||
|
@ -231,7 +231,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
override void visit(AliasThis dsym)
|
||||
{
|
||||
if (dsym.semanticRun != PASS.init)
|
||||
if (dsym.semanticRun != PASS.initial)
|
||||
return;
|
||||
|
||||
if (dsym._scope)
|
||||
@ -346,7 +346,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
printf("linkage = %d\n", dsym.linkage);
|
||||
//if (strcmp(toChars(), "mul") == 0) assert(0);
|
||||
}
|
||||
//if (semanticRun > PASS.init)
|
||||
//if (semanticRun > PASS.initial)
|
||||
// return;
|
||||
//semanticRun = PSSsemantic;
|
||||
|
||||
@ -417,7 +417,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
}
|
||||
//printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars());
|
||||
dsym._init = dsym._init.inferType(sc);
|
||||
dsym.type = dsym._init.initializerToExpression().type;
|
||||
dsym.type = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0).type;
|
||||
if (needctfe)
|
||||
sc = sc.endCTFE();
|
||||
|
||||
@ -527,7 +527,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
* and add those.
|
||||
*/
|
||||
size_t nelems = Parameter.dim(tt.arguments);
|
||||
Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression() : null;
|
||||
Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0) : null;
|
||||
if (ie)
|
||||
ie = ie.expressionSemantic(sc);
|
||||
if (nelems > 0 && ie)
|
||||
@ -987,12 +987,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
if (ai && tb.ty == Taarray)
|
||||
e = ai.toAssocArrayLiteral();
|
||||
else
|
||||
e = dsym._init.initializerToExpression();
|
||||
e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
|
||||
if (!e)
|
||||
{
|
||||
// Run semantic, but don't need to interpret
|
||||
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret);
|
||||
e = dsym._init.initializerToExpression();
|
||||
e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
|
||||
if (!e)
|
||||
{
|
||||
dsym.error("is not a static and cannot have static initializer");
|
||||
@ -1162,23 +1162,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
dsym.edtor = dsym.callScopeDtor(sc);
|
||||
if (dsym.edtor)
|
||||
{
|
||||
/* If dsym is a local variable, who's type is a struct with a scope destructor,
|
||||
* then make dsym scope, too.
|
||||
*/
|
||||
if (global.params.useDIP1000 == FeatureState.enabled &&
|
||||
!(dsym.storage_class & (STC.parameter | STC.temp | STC.field | STC.in_ | STC.foreach_ | STC.result | STC.manifest)) &&
|
||||
!dsym.isDataseg() &&
|
||||
!dsym.doNotInferScope &&
|
||||
dsym.type.hasPointers())
|
||||
{
|
||||
auto tv = dsym.type.baseElemOf();
|
||||
if (tv.ty == Tstruct &&
|
||||
tv.isTypeStruct().sym.dtor.storage_class & STC.scope_)
|
||||
{
|
||||
dsym.storage_class |= STC.scope_;
|
||||
}
|
||||
}
|
||||
|
||||
if (sc.func && dsym.storage_class & (STC.static_ | STC.gshared))
|
||||
dsym.edtor = dsym.edtor.expressionSemantic(sc._module._scope);
|
||||
else
|
||||
@ -1256,7 +1239,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
override void visit(Import imp)
|
||||
{
|
||||
//printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars());
|
||||
if (imp.semanticRun > PASS.init)
|
||||
if (imp.semanticRun > PASS.initial)
|
||||
return;
|
||||
|
||||
if (imp._scope)
|
||||
@ -1433,7 +1416,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
void attribSemantic(AttribDeclaration ad)
|
||||
{
|
||||
if (ad.semanticRun != PASS.init)
|
||||
if (ad.semanticRun != PASS.initial)
|
||||
return;
|
||||
ad.semanticRun = PASS.semantic;
|
||||
Dsymbols* d = ad.include(sc);
|
||||
@ -1776,7 +1759,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
}
|
||||
else if (auto f = s.isFuncDeclaration())
|
||||
{
|
||||
f.isCrtCtorDtor |= isCtor ? 1 : 2;
|
||||
f.flags |= isCtor ? FUNCFLAG.CRTCtor : FUNCFLAG.CRTDtor;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
@ -1990,7 +1973,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
override void visit(Module m)
|
||||
{
|
||||
if (m.semanticRun != PASS.init)
|
||||
if (m.semanticRun != PASS.initial)
|
||||
return;
|
||||
//printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
|
||||
m.semanticRun = PASS.semantic;
|
||||
@ -2099,7 +2082,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
deferDsymbolSemantic(ed, scx);
|
||||
Module.dprogress = dprogress_save;
|
||||
//printf("\tdeferring %s\n", toChars());
|
||||
ed.semanticRun = PASS.init;
|
||||
ed.semanticRun = PASS.initial;
|
||||
return;
|
||||
}
|
||||
else
|
||||
@ -2503,7 +2486,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
printf("sc.stc = %llx\n", sc.stc);
|
||||
printf("sc.module = %s\n", sc._module.toChars());
|
||||
}
|
||||
if (tempdecl.semanticRun != PASS.init)
|
||||
if (tempdecl.semanticRun != PASS.initial)
|
||||
return; // semantic() already run
|
||||
|
||||
if (tempdecl._scope)
|
||||
@ -2648,11 +2631,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
printf("+TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm);
|
||||
fflush(stdout);
|
||||
}
|
||||
if (tm.semanticRun != PASS.init)
|
||||
if (tm.semanticRun != PASS.initial)
|
||||
{
|
||||
// When a class/struct contains mixin members, and is done over
|
||||
// because of forward references, never reach here so semanticRun
|
||||
// has been reset to PASS.init.
|
||||
// has been reset to PASS.initial.
|
||||
static if (LOG)
|
||||
{
|
||||
printf("\tsemantic done\n");
|
||||
@ -2678,7 +2661,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
*/
|
||||
if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null))
|
||||
{
|
||||
if (tm.semanticRun == PASS.init) // forward reference had occurred
|
||||
if (tm.semanticRun == PASS.initial) // forward reference had occurred
|
||||
{
|
||||
//printf("forward reference - deferring\n");
|
||||
return deferDsymbolSemantic(tm, scx);
|
||||
@ -2865,7 +2848,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
override void visit(Nspace ns)
|
||||
{
|
||||
if (ns.semanticRun != PASS.init)
|
||||
if (ns.semanticRun != PASS.initial)
|
||||
return;
|
||||
static if (LOG)
|
||||
{
|
||||
@ -2989,7 +2972,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars());
|
||||
}
|
||||
|
||||
if (funcdecl.semanticRun != PASS.init && funcdecl.isFuncLiteralDeclaration())
|
||||
if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration())
|
||||
{
|
||||
/* Member functions that have return types that are
|
||||
* forward references can have semantic() run more than
|
||||
@ -3023,7 +3006,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
AggregateDeclaration ad = funcdecl.isThis();
|
||||
// Don't nest structs b/c of generated methods which should not access the outer scopes.
|
||||
// https://issues.dlang.org/show_bug.cgi?id=16627
|
||||
if (ad && !funcdecl.generated)
|
||||
if (ad && !funcdecl.isGenerated())
|
||||
{
|
||||
funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_);
|
||||
ad.makeNested();
|
||||
@ -3061,12 +3044,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
funcdecl.inlining = pragmadecl.evalPragmaInline(sc);
|
||||
|
||||
// check pragma(crt_constructor)
|
||||
if (funcdecl.isCrtCtorDtor)
|
||||
if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor))
|
||||
{
|
||||
if (funcdecl.linkage != LINK.c)
|
||||
{
|
||||
funcdecl.error("must be `extern(C)` for `pragma(%s)`",
|
||||
funcdecl.isCrtCtorDtor == 1 ? "crt_constructor".ptr : "crt_destructor".ptr);
|
||||
(funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor".ptr : "crt_destructor".ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3293,7 +3276,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
if (sc.scopesym && sc.scopesym.isAggregateDeclaration())
|
||||
funcdecl.error("`static` member has no `this` to which `return` can apply");
|
||||
else
|
||||
error(funcdecl.loc, "Top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars());
|
||||
error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars());
|
||||
}
|
||||
|
||||
if (funcdecl.isAbstract() && !funcdecl.isVirtual())
|
||||
@ -3524,7 +3507,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
else
|
||||
{
|
||||
//printf("\tintroducing function %s\n", funcdecl.toChars());
|
||||
funcdecl.introducing = 1;
|
||||
funcdecl.flags |= FUNCFLAG.introducing;
|
||||
if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads)
|
||||
{
|
||||
/* Overloaded functions with same name are grouped and in reverse order.
|
||||
@ -3916,8 +3899,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
}
|
||||
}
|
||||
|
||||
if (funcdecl.isMain())
|
||||
funcdecl.checkDmain(); // Check main() parameters and return type
|
||||
funcdecl.checkMain(); // Check main() parameters and return type
|
||||
|
||||
/* Purity and safety can be inferred for some functions by examining
|
||||
* the function body.
|
||||
@ -4525,7 +4507,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
if (sd.errors)
|
||||
sd.type = Type.terror;
|
||||
if (sd.semanticRun == PASS.init)
|
||||
if (sd.semanticRun == PASS.initial)
|
||||
sd.type = sd.type.addSTC(sc.stc | sd.storage_class);
|
||||
sd.type = sd.type.typeSemantic(sd.loc, sc);
|
||||
if (auto ts = sd.type.isTypeStruct())
|
||||
@ -4539,7 +4521,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// Ungag errors when not speculative
|
||||
Ungag ungag = sd.ungagSpeculative();
|
||||
|
||||
if (sd.semanticRun == PASS.init)
|
||||
if (sd.semanticRun == PASS.initial)
|
||||
{
|
||||
sd.visibility = sc.visibility;
|
||||
|
||||
@ -4747,7 +4729,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
if (cldec.errors)
|
||||
cldec.type = Type.terror;
|
||||
if (cldec.semanticRun == PASS.init)
|
||||
if (cldec.semanticRun == PASS.initial)
|
||||
cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class);
|
||||
cldec.type = cldec.type.typeSemantic(cldec.loc, sc);
|
||||
if (auto tc = cldec.type.isTypeClass())
|
||||
@ -4761,7 +4743,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// Ungag errors when not speculative
|
||||
Ungag ungag = cldec.ungagSpeculative();
|
||||
|
||||
if (cldec.semanticRun == PASS.init)
|
||||
if (cldec.semanticRun == PASS.initial)
|
||||
{
|
||||
cldec.visibility = sc.visibility;
|
||||
|
||||
@ -5259,7 +5241,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
|
||||
auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
|
||||
ctor.storage_class |= STC.inference;
|
||||
ctor.generated = true;
|
||||
ctor.flags |= FUNCFLAG.generated;
|
||||
ctor.fbody = new CompoundStatement(Loc.initial, new Statements());
|
||||
|
||||
cldec.members.push(ctor);
|
||||
@ -5416,7 +5398,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||
// Ungag errors when not speculative
|
||||
Ungag ungag = idec.ungagSpeculative();
|
||||
|
||||
if (idec.semanticRun == PASS.init)
|
||||
if (idec.semanticRun == PASS.initial)
|
||||
{
|
||||
idec.visibility = sc.visibility;
|
||||
|
||||
@ -5750,7 +5732,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (tempinst.semanticRun != PASS.init)
|
||||
if (tempinst.semanticRun != PASS.initial)
|
||||
{
|
||||
static if (LOG)
|
||||
{
|
||||
@ -5761,7 +5743,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
global.gag = 0;
|
||||
tempinst.error(tempinst.loc, "recursive template expansion");
|
||||
if (tempinst.gagged)
|
||||
tempinst.semanticRun = PASS.init;
|
||||
tempinst.semanticRun = PASS.initial;
|
||||
else
|
||||
tempinst.inst = tempinst;
|
||||
tempinst.errors = true;
|
||||
@ -5800,7 +5782,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=13220
|
||||
// Roll back status for later semantic re-running
|
||||
tempinst.semanticRun = PASS.init;
|
||||
tempinst.semanticRun = PASS.initial;
|
||||
}
|
||||
else
|
||||
tempinst.inst = tempinst;
|
||||
@ -6034,7 +6016,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
|
||||
|
||||
// Create our own scope for the template parameters
|
||||
Scope* _scope = tempdecl._scope;
|
||||
if (tempdecl.semanticRun == PASS.init)
|
||||
if (tempdecl.semanticRun == PASS.initial)
|
||||
{
|
||||
tempinst.error("template instantiation `%s` forward references template declaration `%s`", tempinst.toChars(), tempdecl.toChars());
|
||||
return;
|
||||
@ -6332,7 +6314,7 @@ Laftersemantic:
|
||||
target_symbol_list.remove(target_symbol_list_idx);
|
||||
tempinst.memberOf = null; // no longer a member
|
||||
}
|
||||
tempinst.semanticRun = PASS.init;
|
||||
tempinst.semanticRun = PASS.initial;
|
||||
tempinst.inst = null;
|
||||
tempinst.symtab = null;
|
||||
}
|
||||
@ -6495,10 +6477,10 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
|
||||
|
||||
// Ungag errors when not instantiated DeclDefs scope alias
|
||||
auto ungag = Ungag(global.gag);
|
||||
//printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated());
|
||||
if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration())
|
||||
//printf("%s parent = %s, gag = %d, instantiated = %d\n", ds.toChars(), ds.parent.toChars(), global.gag, ds.isInstantiated() !is null);
|
||||
if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration() && (sc.minst || sc.tinst))
|
||||
{
|
||||
//printf("%s type = %s\n", toPrettyChars(), type.toChars());
|
||||
//printf("%s type = %s\n", ds.toPrettyChars(), ds.type.toChars());
|
||||
global.gag = 0;
|
||||
}
|
||||
|
||||
@ -6572,13 +6554,13 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
|
||||
}
|
||||
if (s) // it's a symbolic alias
|
||||
{
|
||||
//printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars());
|
||||
//printf("alias %s resolved to %s %s\n", ds.toChars(), s.kind(), s.toChars());
|
||||
ds.type = null;
|
||||
ds.aliassym = s;
|
||||
}
|
||||
else // it's a type alias
|
||||
{
|
||||
//printf("alias %s resolved to type %s\n", toChars(), type.toChars());
|
||||
//printf("alias %s resolved to type %s\n", ds.toChars(), ds.type.toChars());
|
||||
ds.type = ds.type.typeSemantic(ds.loc, sc);
|
||||
ds.aliassym = null;
|
||||
}
|
||||
|
@ -1173,7 +1173,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
||||
|
||||
fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
|
||||
fd.parent = ti;
|
||||
fd.inferRetType = true;
|
||||
fd.flags |= FUNCFLAG.inferRetType;
|
||||
|
||||
// Shouldn't run semantic on default arguments and return type.
|
||||
foreach (ref param; *tf.parameterList.parameters)
|
||||
@ -2827,13 +2827,13 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
if (!sc)
|
||||
sc = td._scope; // workaround for Type.aliasthisOf
|
||||
|
||||
if (td.semanticRun == PASS.init && td._scope)
|
||||
if (td.semanticRun == PASS.initial && td._scope)
|
||||
{
|
||||
// Try to fix forward reference. Ungag errors while doing so.
|
||||
Ungag ungag = td.ungagSpeculative();
|
||||
td.dsymbolSemantic(td._scope);
|
||||
}
|
||||
if (td.semanticRun == PASS.init)
|
||||
if (td.semanticRun == PASS.initial)
|
||||
{
|
||||
.error(loc, "forward reference to template `%s`", td.toChars());
|
||||
Lerror:
|
||||
@ -2851,7 +2851,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
|
||||
tiargs = new Objects();
|
||||
auto ti = new TemplateInstance(loc, td, tiargs);
|
||||
Objects dedtypes = Objects(td.parameters.dim);
|
||||
assert(td.semanticRun != PASS.init);
|
||||
assert(td.semanticRun != PASS.initial);
|
||||
MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0);
|
||||
//printf("matchWithInstance = %d\n", mta);
|
||||
if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
|
||||
@ -6425,7 +6425,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
if (!td)
|
||||
return 0;
|
||||
|
||||
if (td.semanticRun == PASS.init)
|
||||
if (td.semanticRun == PASS.initial)
|
||||
{
|
||||
if (td._scope)
|
||||
{
|
||||
@ -6433,7 +6433,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
Ungag ungag = td.ungagSpeculative();
|
||||
td.dsymbolSemantic(td._scope);
|
||||
}
|
||||
if (td.semanticRun == PASS.init)
|
||||
if (td.semanticRun == PASS.initial)
|
||||
{
|
||||
error("`%s` forward references template declaration `%s`",
|
||||
toChars(), td.toChars());
|
||||
@ -6786,7 +6786,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
(*tiargs)[j] = sa;
|
||||
|
||||
TemplateDeclaration td = sa.isTemplateDeclaration();
|
||||
if (td && td.semanticRun == PASS.init && td.literal)
|
||||
if (td && td.semanticRun == PASS.initial && td.literal)
|
||||
{
|
||||
td.dsymbolSemantic(sc);
|
||||
}
|
||||
@ -6915,7 +6915,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
|
||||
dedtypes.setDim(td.parameters.dim);
|
||||
dedtypes.zero();
|
||||
assert(td.semanticRun != PASS.init);
|
||||
assert(td.semanticRun != PASS.initial);
|
||||
|
||||
MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0);
|
||||
//printf("matchWithInstance = %d\n", m);
|
||||
@ -7093,7 +7093,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
|
||||
{
|
||||
//printf("TemplateInstance.needsTypeInference() %s\n", toChars());
|
||||
if (semanticRun != PASS.init)
|
||||
if (semanticRun != PASS.initial)
|
||||
return false;
|
||||
|
||||
uint olderrs = global.errors;
|
||||
@ -7174,7 +7174,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
*/
|
||||
dedtypes.setDim(td.parameters.dim);
|
||||
dedtypes.zero();
|
||||
if (td.semanticRun == PASS.init)
|
||||
if (td.semanticRun == PASS.initial)
|
||||
{
|
||||
if (td._scope)
|
||||
{
|
||||
@ -7182,7 +7182,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
|
||||
Ungag ungag = td.ungagSpeculative();
|
||||
td.dsymbolSemantic(td._scope);
|
||||
}
|
||||
if (td.semanticRun == PASS.init)
|
||||
if (td.semanticRun == PASS.initial)
|
||||
{
|
||||
error("`%s` forward references template declaration `%s`", toChars(), td.toChars());
|
||||
return 1;
|
||||
@ -7740,13 +7740,13 @@ extern (C++) final class TemplateMixin : TemplateInstance
|
||||
if (!td)
|
||||
return 0;
|
||||
|
||||
if (td.semanticRun == PASS.init)
|
||||
if (td.semanticRun == PASS.initial)
|
||||
{
|
||||
if (td._scope)
|
||||
td.dsymbolSemantic(td._scope);
|
||||
else
|
||||
{
|
||||
semanticRun = PASS.init;
|
||||
semanticRun = PASS.initial;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -445,6 +445,9 @@ public:
|
||||
*/
|
||||
private void writeIdentifier(const AST.Dsymbol s, const bool canFix = false)
|
||||
{
|
||||
if (const mn = getMangleOverride(s))
|
||||
return buf.writestring(mn);
|
||||
|
||||
writeIdentifier(s.ident, s.loc, s.kind(), canFix);
|
||||
}
|
||||
|
||||
@ -719,15 +722,20 @@ public:
|
||||
visited[cast(void*)fd] = true;
|
||||
|
||||
// silently ignore non-user-defined destructors
|
||||
if (fd.generated && fd.isDtorDeclaration())
|
||||
if (fd.isGenerated && fd.isDtorDeclaration())
|
||||
return;
|
||||
|
||||
// Note that tf might be null for templated (member) functions
|
||||
auto tf = cast(AST.TypeFunction)fd.type;
|
||||
if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
|
||||
if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
|
||||
{
|
||||
ignored("function %s because of linkage", fd.toPrettyChars());
|
||||
return checkVirtualFunction(fd);
|
||||
return checkFunctionNeedsPlaceholder(fd);
|
||||
}
|
||||
if (fd.mangleOverride && tf && tf.linkage != LINK.c)
|
||||
{
|
||||
ignored("function %s because C++ doesn't support explicit mangling", fd.toPrettyChars());
|
||||
return checkFunctionNeedsPlaceholder(fd);
|
||||
}
|
||||
if (!adparent && !fd.fbody)
|
||||
{
|
||||
@ -742,7 +750,7 @@ public:
|
||||
if (tf && !isSupportedType(tf.next))
|
||||
{
|
||||
ignored("function %s because its return type cannot be mapped to C++", fd.toPrettyChars());
|
||||
return checkVirtualFunction(fd);
|
||||
return checkFunctionNeedsPlaceholder(fd);
|
||||
}
|
||||
if (tf) foreach (i, fparam; tf.parameterList)
|
||||
{
|
||||
@ -750,7 +758,7 @@ public:
|
||||
{
|
||||
ignored("function %s because one of its parameters has type `%s` which cannot be mapped to C++",
|
||||
fd.toPrettyChars(), fparam.type.toChars());
|
||||
return checkVirtualFunction(fd);
|
||||
return checkFunctionNeedsPlaceholder(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -822,13 +830,19 @@ public:
|
||||
|
||||
}
|
||||
|
||||
/// Checks whether `fd` is a virtual function and emits a dummy declaration
|
||||
/// if required to ensure proper vtable layout
|
||||
private void checkVirtualFunction(AST.FuncDeclaration fd)
|
||||
/++
|
||||
+ Checks whether `fd` is a function that requires a dummy declaration
|
||||
+ instead of simply emitting the declaration (because it would cause
|
||||
+ ABI / behaviour issues). This includes:
|
||||
+
|
||||
+ - virtual functions to ensure proper vtable layout
|
||||
+ - destructors that would break RAII
|
||||
+/
|
||||
private void checkFunctionNeedsPlaceholder(AST.FuncDeclaration fd)
|
||||
{
|
||||
// Omit redundant declarations - the slot was already
|
||||
// reserved in the base class
|
||||
if (fd.isVirtual() && fd.introducing)
|
||||
if (fd.isVirtual() && fd.isIntroducing())
|
||||
{
|
||||
// Hide placeholders because they are not ABI compatible
|
||||
writeProtection(AST.Visibility.Kind.private_);
|
||||
@ -837,6 +851,15 @@ public:
|
||||
buf.printf("virtual void __vtable_slot_%u();", counter++);
|
||||
buf.writenl();
|
||||
}
|
||||
else if (fd.isDtorDeclaration())
|
||||
{
|
||||
// Create inaccessible dtor to prevent code from keeping instances that
|
||||
// need to be destroyed on the C++ side (but cannot call the dtor)
|
||||
writeProtection(AST.Visibility.Kind.private_);
|
||||
buf.writeByte('~');
|
||||
buf.writestring(adparent.ident.toString());
|
||||
buf.writestringln("();");
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(AST.UnitTestDeclaration utd)
|
||||
@ -948,6 +971,11 @@ public:
|
||||
ignored("variable %s because of linkage", vd.toPrettyChars());
|
||||
return;
|
||||
}
|
||||
if (vd.mangleOverride && vd.linkage != LINK.c)
|
||||
{
|
||||
ignored("variable %s because C++ doesn't support explicit mangling", vd.toPrettyChars());
|
||||
return;
|
||||
}
|
||||
if (!isSupportedType(type))
|
||||
{
|
||||
ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
|
||||
@ -1073,7 +1101,7 @@ public:
|
||||
|
||||
auto fd = ad.aliassym.isFuncDeclaration();
|
||||
|
||||
if (fd && (fd.generated || fd.isDtorDeclaration()))
|
||||
if (fd && (fd.isGenerated() || fd.isDtorDeclaration()))
|
||||
{
|
||||
// Ignore. It's taken care of while visiting FuncDeclaration
|
||||
return;
|
||||
@ -1106,7 +1134,7 @@ public:
|
||||
// Print prefix of the base class if this function originates from a superclass
|
||||
// because alias might be resolved through multiple classes, e.g.
|
||||
// e.g. for alias visit = typeof(super).visit in the visitors
|
||||
if (!fd.introducing)
|
||||
if (!fd.isIntroducing())
|
||||
printPrefix(ad.toParent().isClassDeclaration().baseClass);
|
||||
else
|
||||
printPrefix(pd);
|
||||
@ -1655,7 +1683,16 @@ public:
|
||||
scope(exit) printf("[typeToBuffer(AST.Type, AST.Dsymbol) exit] %s sym %s\n", t.toChars(), s.toChars());
|
||||
}
|
||||
|
||||
this.ident = s.ident;
|
||||
// The context pointer (represented as `ThisDeclaration`) is named
|
||||
// `this` but accessible via `outer`
|
||||
if (auto td = s.isThisDeclaration())
|
||||
{
|
||||
import dmd.id;
|
||||
this.ident = Id.outer;
|
||||
}
|
||||
else
|
||||
this.ident = s.ident;
|
||||
|
||||
auto type = origType !is null ? origType : t;
|
||||
AST.Dsymbol customLength;
|
||||
|
||||
@ -1702,7 +1739,12 @@ public:
|
||||
if (this.ident)
|
||||
{
|
||||
buf.writeByte(' ');
|
||||
writeIdentifier(s, canFixup);
|
||||
// Custom identifier doesn't need further checks
|
||||
if (this.ident !is s.ident)
|
||||
buf.writestring(this.ident.toString());
|
||||
else
|
||||
writeIdentifier(s, canFixup);
|
||||
|
||||
}
|
||||
this.ident = null;
|
||||
|
||||
@ -2922,6 +2964,10 @@ public:
|
||||
scope(exit) printf("[writeFullName exit] %s\n", sym.toPrettyChars());
|
||||
}
|
||||
|
||||
// Explicit `pragma(mangle, "<some string>` overrides the declared name
|
||||
if (auto mn = getMangleOverride(sym))
|
||||
return buf.writestring(mn);
|
||||
|
||||
/// Checks whether `sym` is nested in `par` and hence doesn't need the FQN
|
||||
static bool isNestedIn(AST.Dsymbol sym, AST.Dsymbol par)
|
||||
{
|
||||
@ -2970,6 +3016,15 @@ public:
|
||||
else
|
||||
buf.writestring(sym.ident.toString());
|
||||
}
|
||||
|
||||
/// Returns: Explicit mangling for `sym` if present
|
||||
extern(D) static const(char)[] getMangleOverride(const AST.Dsymbol sym)
|
||||
{
|
||||
if (auto decl = sym.isDeclaration())
|
||||
return decl.mangleOverride;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Namespace for identifiers used to represent special enums in C++
|
||||
@ -3037,7 +3092,7 @@ void hashEndIf(ref OutBuffer buf)
|
||||
/// Writes `#define <content>` into the supplied buffer
|
||||
void hashDefine(ref OutBuffer buf, string content)
|
||||
{
|
||||
buf.writestring("# define ");
|
||||
buf.writestring("#define ");
|
||||
buf.writestringln(content);
|
||||
}
|
||||
|
||||
|
@ -692,9 +692,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
|
||||
|
||||
// If va's lifetime encloses v's, then error
|
||||
if (va && !va.isDataseg() &&
|
||||
(va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp) ||
|
||||
vaIsRef ||
|
||||
va.isReference() && !(v.storage_class & (STC.parameter | STC.temp))) &&
|
||||
((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef) &&
|
||||
fd.setUnsafe())
|
||||
{
|
||||
if (!gag)
|
||||
@ -793,7 +791,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
|
||||
|
||||
// If va's lifetime encloses v's, then error
|
||||
if (va &&
|
||||
(va.enclosesLifetimeOf(v) || (va.isRef() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
|
||||
(va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
|
||||
fd.setUnsafe())
|
||||
{
|
||||
if (!gag)
|
||||
@ -1284,27 +1282,24 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
|
||||
{
|
||||
if (!gag)
|
||||
{
|
||||
const(char)* msg, supplemental;
|
||||
if (v.storage_class & STC.parameter &&
|
||||
(v.type.hasPointers() || v.storage_class & STC.ref_))
|
||||
{
|
||||
msg = "returning `%s` escapes a reference to parameter `%s`";
|
||||
supplemental = vsr == ScopeRef.Ref_ReturnScope
|
||||
? "perhaps remove `scope` parameter annotation so `return` applies to `ref`"
|
||||
: v.ident is Id.This
|
||||
? "perhaps annotate the function with `return`"
|
||||
: "perhaps annotate the parameter with `return`";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "returning `%s` escapes a reference to local variable `%s`";
|
||||
if (v.ident is Id.This)
|
||||
supplemental = "perhaps annotate the function with `return`";
|
||||
}
|
||||
const(char)* varKind = v.isParameter() ? "parameter" : "local variable";
|
||||
previewErrorFunc(sc.isDeprecated(), featureState)(e.loc,
|
||||
"returning `%s` escapes a reference to %s `%s`", e.toChars(), varKind, v.toChars());
|
||||
|
||||
previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
|
||||
if (supplemental)
|
||||
previewSupplementalFunc(sc.isDeprecated(), featureState)(e.loc, supplemental);
|
||||
if (v.isParameter() && v.isReference())
|
||||
{
|
||||
if (v.storage_class & STC.returnScope)
|
||||
{
|
||||
previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc,
|
||||
"perhaps change the `return scope` into `scope return`");
|
||||
}
|
||||
else
|
||||
{
|
||||
const(char)* annotateKind = (v.ident is Id.This) ? "function" : "parameter";
|
||||
previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc,
|
||||
"perhaps annotate the %s with `return`", annotateKind);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
@ -1897,7 +1892,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
|
||||
|
||||
override void visit(ThisExp e)
|
||||
{
|
||||
if (e.var && e.var.toParent2().isFuncDeclaration().isThis2)
|
||||
if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
|
||||
escapeByValue(e, er, live);
|
||||
else if (e.var)
|
||||
er.byref.push(e.var);
|
||||
@ -2297,3 +2292,37 @@ bool isReferenceToMutable(Parameter p, Type t)
|
||||
}
|
||||
return isReferenceToMutable(p.type);
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Determine if `va` has a lifetime that lasts past
|
||||
* the destruction of `v`
|
||||
* Params:
|
||||
* va = variable assigned to
|
||||
* v = variable being assigned
|
||||
* Returns:
|
||||
* true if it does
|
||||
*/
|
||||
private bool enclosesLifetimeOf(const VarDeclaration va, const VarDeclaration v) pure
|
||||
{
|
||||
assert(va.sequenceNumber != va.sequenceNumber.init);
|
||||
assert(v.sequenceNumber != v.sequenceNumber.init);
|
||||
return va.sequenceNumber < v.sequenceNumber;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Add variable `v` to maybes[]
|
||||
*
|
||||
* When a maybescope variable `v` is assigned to a maybescope variable `va`,
|
||||
* we cannot determine if `this` is actually scope until the semantic
|
||||
* analysis for the function is completed. Thus, we save the data
|
||||
* until then.
|
||||
* Params:
|
||||
* v = an `STC.maybescope` variable that was assigned to `this`
|
||||
*/
|
||||
private void addMaybe(VarDeclaration va, VarDeclaration v)
|
||||
{
|
||||
//printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
|
||||
if (!va.maybes)
|
||||
va.maybes = new VarDeclarations();
|
||||
va.maybes.push(v);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ FuncDeclaration hasThis(Scope* sc)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!fd.isNested() || fd.isThis() || (fd.isThis2 && fd.isMember2()))
|
||||
if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
|
||||
break;
|
||||
|
||||
Dsymbol parent = fd.parent;
|
||||
@ -187,7 +187,7 @@ FuncDeclaration hasThis(Scope* sc)
|
||||
fd = parent.isFuncDeclaration();
|
||||
}
|
||||
|
||||
if (!fd.isThis() && !(fd.isThis2 && fd.isMember2()))
|
||||
if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@ -1210,7 +1210,7 @@ extern (C++) abstract class Expression : ASTNode
|
||||
scope bool function(DtorDeclaration) check, const string checkName
|
||||
) {
|
||||
auto dd = f.isDtorDeclaration();
|
||||
if (!dd || !dd.generated)
|
||||
if (!dd || !dd.isGenerated())
|
||||
return;
|
||||
|
||||
// DtorDeclaration without parents should fail at an earlier stage
|
||||
@ -1227,7 +1227,7 @@ extern (C++) abstract class Expression : ASTNode
|
||||
}
|
||||
|
||||
dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
|
||||
dd.generated ? "generated " : "".ptr,
|
||||
dd.isGenerated() ? "generated " : "".ptr,
|
||||
ad.toChars,
|
||||
cast(int) checkName.length, checkName.ptr);
|
||||
|
||||
@ -1258,7 +1258,7 @@ extern (C++) abstract class Expression : ASTNode
|
||||
{
|
||||
field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
|
||||
|
||||
if (fieldSd.dtor.generated)
|
||||
if (fieldSd.dtor.isGenerated())
|
||||
checkOverridenDtor(sc, fieldSd.dtor, check, checkName);
|
||||
else
|
||||
fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
|
||||
@ -1288,7 +1288,7 @@ extern (C++) abstract class Expression : ASTNode
|
||||
return false; // magic variable never violates pure and safe
|
||||
if (v.isImmutable())
|
||||
return false; // always safe and pure to access immutables...
|
||||
if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
|
||||
if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
|
||||
return false; // or const global/parameter values which have no mutable indirections
|
||||
if (v.storage_class & STC.manifest)
|
||||
return false; // ...or manifest constants
|
||||
@ -3461,7 +3461,7 @@ extern (C++) final class ScopeExp : Expression
|
||||
//assert(ti.needsTypeInference(sc));
|
||||
if (ti.tempdecl &&
|
||||
ti.semantictiargsdone &&
|
||||
ti.semanticRun == PASS.init)
|
||||
ti.semanticRun == PASS.initial)
|
||||
{
|
||||
error("partial %s `%s` has no type", sds.kind(), toChars());
|
||||
return true;
|
||||
@ -3859,7 +3859,7 @@ extern (C++) final class FuncExp : Expression
|
||||
{
|
||||
if (td)
|
||||
return new FuncExp(loc, td.syntaxCopy(null));
|
||||
else if (fd.semanticRun == PASS.init)
|
||||
else if (fd.semanticRun == PASS.initial)
|
||||
return new FuncExp(loc, fd.syntaxCopy(null));
|
||||
else // https://issues.dlang.org/show_bug.cgi?id=13481
|
||||
// Prevent multiple semantic analysis of lambda body.
|
||||
@ -4950,7 +4950,7 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
|
||||
// Same logic as ScopeExp.checkType()
|
||||
if (ti.tempdecl &&
|
||||
ti.semantictiargsdone &&
|
||||
ti.semanticRun == PASS.init)
|
||||
ti.semanticRun == PASS.initial)
|
||||
{
|
||||
error("partial %s `%s` has no type", ti.kind(), toChars());
|
||||
return true;
|
||||
@ -4962,7 +4962,7 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
|
||||
{
|
||||
if (ti.tempdecl &&
|
||||
ti.semantictiargsdone &&
|
||||
ti.semanticRun == PASS.init)
|
||||
ti.semanticRun == PASS.initial)
|
||||
|
||||
error("partial %s `%s` has no value", ti.kind(), toChars());
|
||||
else
|
||||
|
@ -1046,7 +1046,7 @@ L1:
|
||||
if (e1.op == EXP.this_)
|
||||
{
|
||||
FuncDeclaration f = hasThis(sc);
|
||||
if (f && f.isThis2)
|
||||
if (f && f.hasDualContext())
|
||||
{
|
||||
if (f.followInstantiationContext(ad))
|
||||
{
|
||||
@ -1444,13 +1444,6 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
|
||||
Expression ex = condexp.expressionSemantic(sc);
|
||||
if (ex.op == EXP.error)
|
||||
e = ex;
|
||||
else if (e.op == EXP.function_ || e.op == EXP.delegate_)
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21285
|
||||
// Functions and delegates don't convert correctly with castTo below
|
||||
exps[i] = condexp.e1;
|
||||
e = condexp.e2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert to common type
|
||||
@ -1723,7 +1716,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
||||
if (sc._module)
|
||||
sc._module.hasAlwaysInlines = true;
|
||||
if (sc.func)
|
||||
sc.func.hasAlwaysInlines = true;
|
||||
sc.func.flags |= FUNCFLAG.hasAlwaysInline;
|
||||
}
|
||||
|
||||
const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
|
||||
@ -3743,7 +3736,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
return setError();
|
||||
}
|
||||
|
||||
if (sd.hasRegularCtor() && nargs)
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22639
|
||||
// If the new expression has arguments, we either should call a
|
||||
// regular constructor of a copy constructor if the first argument
|
||||
// is the same type as the struct
|
||||
if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
|
||||
{
|
||||
FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
|
||||
if (!f || f.errors)
|
||||
@ -4201,30 +4198,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
Type tthis = null;
|
||||
Expression e1org = exp.e1;
|
||||
|
||||
if (exp.e1.op == EXP.comma)
|
||||
if (auto ce = exp.e1.isCommaExp())
|
||||
{
|
||||
/* Rewrite (a,b)(args) as (a,(b(args)))
|
||||
*/
|
||||
auto ce = cast(CommaExp)exp.e1;
|
||||
exp.e1 = ce.e2;
|
||||
ce.e2 = exp;
|
||||
result = ce.expressionSemantic(sc);
|
||||
return;
|
||||
}
|
||||
if (exp.e1.op == EXP.delegate_)
|
||||
if (DelegateExp de = exp.e1.isDelegateExp())
|
||||
{
|
||||
DelegateExp de = cast(DelegateExp)exp.e1;
|
||||
exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
|
||||
visit(exp);
|
||||
return;
|
||||
}
|
||||
if (exp.e1.op == EXP.function_)
|
||||
if (FuncExp fe = exp.e1.isFuncExp())
|
||||
{
|
||||
if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments))
|
||||
return setError();
|
||||
|
||||
// Run e1 semantic even if arguments have any errors
|
||||
FuncExp fe = cast(FuncExp)exp.e1;
|
||||
exp.e1 = callExpSemantic(fe, sc, exp.arguments);
|
||||
if (exp.e1.op == EXP.error)
|
||||
{
|
||||
@ -4252,9 +4246,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
/* This recognizes:
|
||||
* foo!(tiargs)(funcargs)
|
||||
*/
|
||||
if (exp.e1.op == EXP.scope_)
|
||||
if (ScopeExp se = exp.e1.isScopeExp())
|
||||
{
|
||||
ScopeExp se = cast(ScopeExp)exp.e1;
|
||||
TemplateInstance ti = se.sds.isTemplateInstance();
|
||||
if (ti)
|
||||
{
|
||||
@ -4300,9 +4293,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
* expr.foo!(tiargs)(funcargs)
|
||||
*/
|
||||
Ldotti:
|
||||
if (exp.e1.op == EXP.dotTemplateInstance)
|
||||
if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
|
||||
{
|
||||
DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
|
||||
TemplateInstance ti = se.ti;
|
||||
{
|
||||
/* Attempt to instantiate ti. If that works, go with it.
|
||||
@ -4347,9 +4339,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exp.e1.op == EXP.dotIdentifier)
|
||||
if (DotIdExp die = exp.e1.isDotIdExp())
|
||||
{
|
||||
DotIdExp die = cast(DotIdExp)exp.e1;
|
||||
exp.e1 = die.expressionSemantic(sc);
|
||||
/* Look for e1 having been rewritten to expr.opDispatch!(string)
|
||||
* We handle such earlier, so go back.
|
||||
@ -4380,9 +4371,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
|
||||
/* Look for e1 being a lazy parameter
|
||||
*/
|
||||
if (exp.e1.op == EXP.variable)
|
||||
if (VarExp ve = exp.e1.isVarExp())
|
||||
{
|
||||
VarExp ve = cast(VarExp)exp.e1;
|
||||
if (ve.var.storage_class & STC.lazy_)
|
||||
{
|
||||
// lazy parameters can be called without violating purity and safety
|
||||
@ -4404,10 +4394,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
exp.e1 = new VarExp(se.loc, se.var, true);
|
||||
exp.e1 = exp.e1.expressionSemantic(sc);
|
||||
}
|
||||
else if (exp.e1.op == EXP.dot)
|
||||
else if (DotExp de = exp.e1.isDotExp())
|
||||
{
|
||||
DotExp de = cast(DotExp)exp.e1;
|
||||
|
||||
if (de.e2.op == EXP.overloadSet)
|
||||
{
|
||||
ethis = de.e1;
|
||||
@ -4490,7 +4478,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
if (sd.ctor)
|
||||
{
|
||||
auto ctor = sd.ctor.isCtorDeclaration();
|
||||
if (ctor && ctor.isCpCtor && ctor.generated)
|
||||
if (ctor && ctor.isCpCtor && ctor.isGenerated())
|
||||
sd.ctor = null;
|
||||
}
|
||||
|
||||
@ -4504,7 +4492,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
If all constructors are copy constructors, then
|
||||
try default construction.
|
||||
*/
|
||||
if (!sd.hasRegularCtor)
|
||||
if (!sd.hasRegularCtor &&
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22639
|
||||
// we might still have a copy constructor that could be called
|
||||
(*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
|
||||
goto Lx;
|
||||
|
||||
auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
|
||||
@ -4850,10 +4841,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
return setError();
|
||||
}
|
||||
}
|
||||
else if (exp.e1.op == EXP.overloadSet)
|
||||
else if (auto oe = exp.e1.isOverExp())
|
||||
{
|
||||
auto os = (cast(OverExp)exp.e1).vars;
|
||||
exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments);
|
||||
exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments);
|
||||
if (!exp.f)
|
||||
return setError();
|
||||
if (ethis)
|
||||
@ -4877,11 +4867,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
const(char)* p;
|
||||
Dsymbol s;
|
||||
exp.f = null;
|
||||
if (exp.e1.op == EXP.function_)
|
||||
if (auto fe = exp.e1.isFuncExp())
|
||||
{
|
||||
// function literal that direct called is always inferred.
|
||||
assert((cast(FuncExp)exp.e1).fd);
|
||||
exp.f = (cast(FuncExp)exp.e1).fd;
|
||||
assert(fe.fd);
|
||||
exp.f = fe.fd;
|
||||
tf = cast(TypeFunction)exp.f.type;
|
||||
p = "function literal";
|
||||
}
|
||||
@ -5011,11 +5001,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
t1 = tf;
|
||||
}
|
||||
else if (exp.e1.op == EXP.variable)
|
||||
else if (VarExp ve = exp.e1.isVarExp())
|
||||
{
|
||||
// Do overload resolution
|
||||
VarExp ve = cast(VarExp)exp.e1;
|
||||
|
||||
exp.f = ve.var.isFuncDeclaration();
|
||||
assert(exp.f);
|
||||
tiargs = null;
|
||||
@ -5162,7 +5150,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
// declare dual-context container
|
||||
if (exp.f && exp.f.isThis2 && !sc.intypeof && sc.func)
|
||||
if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
|
||||
{
|
||||
// check access to second `this`
|
||||
if (AggregateDeclaration ad2 = exp.f.isMember2())
|
||||
@ -6042,13 +6030,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
|
||||
{
|
||||
auto fileName = FileName(name.toDString);
|
||||
if (auto fmResult = FileManager.fileManager.lookup(fileName))
|
||||
if (auto fmResult = global.fileManager.lookup(fileName))
|
||||
{
|
||||
se = new StringExp(e.loc, fmResult.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto readResult = File.read(name);
|
||||
auto readResult = File.read(name.toDString);
|
||||
if (!readResult.success)
|
||||
{
|
||||
e.error("cannot read file `%s`", name);
|
||||
@ -6060,9 +6048,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
auto data = readResult.extractSlice();
|
||||
se = new StringExp(e.loc, data);
|
||||
|
||||
FileBuffer* fileBuffer = FileBuffer.create();
|
||||
fileBuffer.data = data;
|
||||
FileManager.fileManager.add(fileName, fileBuffer);
|
||||
FileBuffer* fileBuffer = new FileBuffer(data);
|
||||
global.fileManager.add(fileName, fileBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6200,10 +6187,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
|
||||
const op = exp.e1.op;
|
||||
bool isEqualsCallExpression;
|
||||
if (op == EXP.call)
|
||||
if (const callExp = exp.e1.isCallExp())
|
||||
{
|
||||
const callExp = cast(CallExp) exp.e1;
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20331
|
||||
// callExp.f may be null if the assert contains a call to
|
||||
// a function pointer or literal
|
||||
@ -6436,7 +6421,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
else if (t)
|
||||
{
|
||||
result = new IntegerExp(exp.loc, t.alignsize, Type.tsize_t);
|
||||
// Note similarity to getProperty() implementation of __xalignof
|
||||
const explicitAlignment = t.alignment();
|
||||
const naturalAlignment = t.alignsize();
|
||||
const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
|
||||
result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
|
||||
}
|
||||
else if (s)
|
||||
{
|
||||
@ -6643,7 +6632,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
|
||||
(!v.needThis() && v.semanticRun > PASS.init))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
|
||||
(!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
|
||||
{
|
||||
// (e1, v)
|
||||
checkAccess(exp.loc, sc, exp.e1, v);
|
||||
@ -6736,7 +6725,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
}
|
||||
result = e;
|
||||
// declare dual-context container
|
||||
if (f.isThis2 && !sc.intypeof && sc.func)
|
||||
if (f.hasDualContext() && !sc.intypeof && sc.func)
|
||||
{
|
||||
// check access to second `this`
|
||||
if (AggregateDeclaration ad2 = f.isMember2())
|
||||
@ -7311,7 +7300,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
if (checkNonAssignmentArrayOp(e.e1))
|
||||
return setError();
|
||||
|
||||
e.type = Type.tbool;
|
||||
e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
|
||||
result = e;
|
||||
}
|
||||
|
||||
@ -7323,7 +7312,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
// 3. Removal of keyword, "delete" can be used for other identities
|
||||
if (!exp.isRAII)
|
||||
{
|
||||
error(exp.loc, "The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
|
||||
error(exp.loc, "the `delete` keyword is obsolete");
|
||||
errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
|
||||
return setError();
|
||||
}
|
||||
|
||||
@ -7847,9 +7837,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
*/
|
||||
if (VarDeclaration v = expToVariable(exp.e1))
|
||||
{
|
||||
if (exp.e1.op == EXP.dotVariable)
|
||||
if (DotVarExp dve = exp.e1.isDotVarExp())
|
||||
{
|
||||
DotVarExp dve = cast(DotVarExp)exp.e1;
|
||||
|
||||
if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) &&
|
||||
!(v.storage_class & STC.ref_))
|
||||
{
|
||||
@ -8140,10 +8130,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
result = exp.e2;
|
||||
return;
|
||||
}
|
||||
if (exp.e2.op == EXP.template_)
|
||||
if (auto te = exp.e2.isTemplateExp())
|
||||
{
|
||||
auto td = (cast(TemplateExp)exp.e2).td;
|
||||
Expression e = new DotTemplateExp(exp.loc, exp.e1, td);
|
||||
Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
|
||||
result = e.expressionSemantic(sc);
|
||||
return;
|
||||
}
|
||||
@ -8182,11 +8171,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
e.e2 = e.e2.arrayFuncConv(sc);
|
||||
|
||||
e.type = e.e2.type;
|
||||
result = e;
|
||||
|
||||
if (sc.flags & SCOPE.Cfile)
|
||||
return;
|
||||
|
||||
if (e.type is Type.tvoid)
|
||||
discardValue(e.e1);
|
||||
else if (!e.allowCommaExp && !e.isGenerated && !(sc.flags & SCOPE.Cfile))
|
||||
else if (!e.allowCommaExp && !e.isGenerated)
|
||||
e.error("Using the result of a comma expression is not allowed");
|
||||
result = e;
|
||||
}
|
||||
|
||||
override void visit(IntervalExp e)
|
||||
@ -8472,6 +8465,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
// OR it in, because it might already be set for C array indexing
|
||||
exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
|
||||
}
|
||||
else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
|
||||
{
|
||||
if (auto ve = exp.e1.isVarExp())
|
||||
{
|
||||
/* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
|
||||
*/
|
||||
auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
|
||||
auto e = new AddExp(exp.loc, vp, exp.e2);
|
||||
auto pe = new PtrExp(exp.loc, e);
|
||||
result = pe.expressionSemantic(sc).optimize(WANTvalue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10024,9 +10030,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
return;
|
||||
}
|
||||
|
||||
if (exp.e1.op == EXP.slice)
|
||||
if (SliceExp se = exp.e1.isSliceExp())
|
||||
{
|
||||
SliceExp se = cast(SliceExp)exp.e1;
|
||||
if (se.e1.type.toBasetype().ty == Tsarray)
|
||||
{
|
||||
exp.error("cannot append to static array `%s`", se.e1.type.toChars());
|
||||
@ -11270,7 +11275,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
e1x = e1x.optimize(WANTvalue);
|
||||
if (e1x.toBool().hasValue(exp.op == EXP.orOr))
|
||||
{
|
||||
result = IntegerExp.createBool(exp.op == EXP.orOr);
|
||||
if (sc.flags & SCOPE.Cfile)
|
||||
result = new IntegerExp(exp.op == EXP.orOr);
|
||||
else
|
||||
result = IntegerExp.createBool(exp.op == EXP.orOr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -11315,7 +11323,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
if (e2x.type.ty == Tvoid)
|
||||
exp.type = Type.tvoid;
|
||||
else
|
||||
exp.type = Type.tbool;
|
||||
exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
|
||||
|
||||
exp.e1 = e1x;
|
||||
exp.e2 = e2x;
|
||||
@ -11412,7 +11420,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
if (f1 || f2)
|
||||
return setError();
|
||||
|
||||
exp.type = Type.tbool;
|
||||
exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
|
||||
|
||||
// Special handling for array comparisons
|
||||
Expression arrayLowering = null;
|
||||
@ -11690,7 +11698,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
if (f1 || f2)
|
||||
return setError();
|
||||
|
||||
exp.type = Type.tbool;
|
||||
exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
|
||||
|
||||
if (!isArrayComparison)
|
||||
{
|
||||
@ -11825,8 +11833,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
return;
|
||||
}
|
||||
|
||||
if (exp.econd.op == EXP.dotIdentifier)
|
||||
(cast(DotIdExp)exp.econd).noderef = true;
|
||||
if (auto die = exp.econd.isDotIdExp())
|
||||
die.noderef = true;
|
||||
|
||||
Expression ec = exp.econd.expressionSemantic(sc);
|
||||
ec = resolveProperties(sc, ec);
|
||||
@ -12654,9 +12662,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
|
||||
|
||||
if (e.op == EXP.error)
|
||||
return e;
|
||||
if (e.op == EXP.dotVariable)
|
||||
if (DotVarExp dve = e.isDotVarExp())
|
||||
{
|
||||
DotVarExp dve = cast(DotVarExp)e;
|
||||
if (FuncDeclaration fd = dve.var.isFuncDeclaration())
|
||||
{
|
||||
if (TemplateDeclaration td = fd.findTemplateDeclRoot())
|
||||
@ -12707,9 +12714,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
|
||||
}
|
||||
}
|
||||
|
||||
if (e.op == EXP.dotTemplateDeclaration)
|
||||
if (DotTemplateExp dte = e.isDotTemplateExp())
|
||||
{
|
||||
DotTemplateExp dte = cast(DotTemplateExp)e;
|
||||
exp.e1 = dte.e1; // pull semantic() result
|
||||
|
||||
exp.ti.tempdecl = dte.td;
|
||||
@ -12738,10 +12744,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
|
||||
return new ScopeExp(exp.loc, exp.ti)
|
||||
.expressionSemantic(sc);
|
||||
}
|
||||
else if (e.op == EXP.dot)
|
||||
else if (DotExp de = e.isDotExp())
|
||||
{
|
||||
DotExp de = cast(DotExp)e;
|
||||
|
||||
if (de.e2.op == EXP.overloadSet)
|
||||
{
|
||||
if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
|
||||
@ -12765,9 +12769,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
|
||||
.expressionSemantic(sc);
|
||||
}
|
||||
}
|
||||
else if (e.op == EXP.overloadSet)
|
||||
else if (OverExp oe = e.isOverExp())
|
||||
{
|
||||
OverExp oe = cast(OverExp)e;
|
||||
exp.ti.tempdecl = oe.vars;
|
||||
return new ScopeExp(exp.loc, exp.ti)
|
||||
.expressionSemantic(sc);
|
||||
@ -13055,7 +13058,7 @@ Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, Aggre
|
||||
{
|
||||
n++;
|
||||
e1 = new VarExp(loc, f.vthis);
|
||||
if (f.isThis2)
|
||||
if (f.hasDualContext())
|
||||
{
|
||||
// (*__this)[i]
|
||||
if (n > 1)
|
||||
@ -13355,8 +13358,8 @@ Expression toBoolean(Expression exp, Scope* sc)
|
||||
|
||||
default:
|
||||
// Default is 'yes' - do nothing
|
||||
Expression e = exp;
|
||||
Type t = exp.type;
|
||||
Expression e = arrayFuncConv(exp, sc);
|
||||
Type t = e.type;
|
||||
Type tb = t.toBasetype();
|
||||
Type att = null;
|
||||
|
||||
|
@ -20,10 +20,15 @@ import dmd.identifier;
|
||||
enum package_d = "package." ~ mars_ext;
|
||||
enum package_di = "package." ~ hdr_ext;
|
||||
|
||||
struct FileManager
|
||||
final class FileManager
|
||||
{
|
||||
private StringTable!(FileBuffer*) files;
|
||||
private __gshared bool initialized = false;
|
||||
|
||||
///
|
||||
public this () nothrow
|
||||
{
|
||||
this.files._init();
|
||||
}
|
||||
|
||||
nothrow:
|
||||
/********************************************
|
||||
@ -143,9 +148,6 @@ nothrow:
|
||||
*/
|
||||
const(FileBuffer)* lookup(FileName filename)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
const name = filename.toString;
|
||||
if (auto val = files.lookup(name))
|
||||
return val.value;
|
||||
@ -182,9 +184,6 @@ nothrow:
|
||||
*/
|
||||
const(char)[][] getLines(FileName file)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
const(char)[][] lines;
|
||||
if (const buffer = lookup(file))
|
||||
{
|
||||
@ -241,29 +240,9 @@ nothrow:
|
||||
*/
|
||||
FileBuffer* add(FileName filename, FileBuffer* filebuffer)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
auto val = files.insert(filename.toString, filebuffer);
|
||||
return val == null ? null : val.value;
|
||||
}
|
||||
|
||||
__gshared fileManager = FileManager();
|
||||
|
||||
// Initialize the global FileManager singleton
|
||||
private void _init()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
fileManager.initialize();
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
files._init();
|
||||
}
|
||||
}
|
||||
|
||||
private FileBuffer readFromStdin() nothrow
|
||||
|
@ -320,4 +320,3 @@ void foreachExpAndVar(Statement s,
|
||||
|
||||
visit(s);
|
||||
}
|
||||
|
||||
|
298
gcc/d/dmd/func.d
298
gcc/d/dmd/func.d
@ -140,7 +140,7 @@ public:
|
||||
override void visit(TryFinallyStatement s)
|
||||
{
|
||||
DtorExpStatement des;
|
||||
if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
|
||||
if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
|
||||
fd.nrvo_var == des.var)
|
||||
{
|
||||
if (!(global.params.useExceptions && ClassDeclaration.throwable))
|
||||
@ -182,7 +182,7 @@ public:
|
||||
catches.push(ctch);
|
||||
|
||||
Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
|
||||
fd.eh_none = false;
|
||||
fd.flags &= ~FUNCFLAG.noEH;
|
||||
replaceCurrent(s2);
|
||||
s2.accept(this);
|
||||
}
|
||||
@ -205,6 +205,17 @@ enum FUNCFLAG : uint
|
||||
printf = 0x200, /// is a printf-like function
|
||||
scanf = 0x400, /// is a scanf-like function
|
||||
noreturn = 0x800, /// the function does not return
|
||||
NRVO = 0x1000, /// Support for named return value optimization
|
||||
naked = 0x2000, /// The function is 'naked' (see inline ASM)
|
||||
generated = 0x4000, /// The function is compiler generated (e.g. `opCmp`)
|
||||
introducing = 0x8000, /// If this function introduces the overload set
|
||||
semantic3Errors = 0x10000, /// If errors in semantic3 this function's frame ptr
|
||||
noEH = 0x20000, /// No exception unwinding is needed
|
||||
inferRetType = 0x40000, /// Return type is to be inferred
|
||||
dualContext = 0x80000, /// has a dual-context 'this' parameter
|
||||
hasAlwaysInline = 0x100000, /// Contains references to functions that must be inlined
|
||||
CRTCtor = 0x200000, /// Has attribute pragma(crt_constructor)
|
||||
CRTDtor = 0x400000, /// Has attribute pragma(crt_destructor)
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
@ -268,7 +279,6 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
// scopes from having the same name
|
||||
DsymbolTable localsymtab;
|
||||
VarDeclaration vthis; /// 'this' parameter (member and nested)
|
||||
bool isThis2; /// has a dual-context 'this' parameter
|
||||
VarDeclaration v_arguments; /// '_arguments' parameter
|
||||
|
||||
VarDeclaration v_argptr; /// '_argptr' variable
|
||||
@ -278,31 +288,21 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
|
||||
Loc endloc; /// location of closing curly bracket
|
||||
int vtblIndex = -1; /// for member functions, index into vtbl[]
|
||||
bool naked; /// true if naked
|
||||
bool generated; /// true if function was generated by the compiler rather than
|
||||
/// supplied by the user
|
||||
bool hasAlwaysInlines; /// contains references to functions that must be inlined
|
||||
ubyte isCrtCtorDtor; /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
|
||||
/// not set before the glue layer
|
||||
|
||||
ILS inlineStatusStmt = ILS.uninitialized;
|
||||
ILS inlineStatusExp = ILS.uninitialized;
|
||||
PINLINE inlining = PINLINE.default_;
|
||||
|
||||
int inlineNest; /// !=0 if nested inline
|
||||
bool eh_none; /// true if no exception unwinding is needed
|
||||
|
||||
bool semantic3Errors; /// true if errors in semantic3 this function's frame ptr
|
||||
ForeachStatement fes; /// if foreach body, this is the foreach
|
||||
BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
|
||||
bool introducing; /// true if 'introducing' function
|
||||
/** if !=NULL, then this is the type
|
||||
of the 'introducing' function
|
||||
this one is overriding
|
||||
*/
|
||||
Type tintro;
|
||||
|
||||
bool inferRetType; /// true if return type is to be inferred
|
||||
StorageClass storage_class2; /// storage class for template onemember's
|
||||
|
||||
// Things that should really go into Scope
|
||||
@ -314,8 +314,6 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
/// 16 if there are multiple return statements
|
||||
int hasReturnExp;
|
||||
|
||||
// Support for NRVO (named return value optimization)
|
||||
bool nrvo_can = true; /// true means we can do NRVO
|
||||
VarDeclaration nrvo_var; /// variable to replace with shidden
|
||||
Symbol* shidden; /// hidden pointer passed to function
|
||||
|
||||
@ -346,7 +344,9 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
|
||||
FuncDeclarations *inlinedNestedCallees;
|
||||
|
||||
uint flags; /// FUNCFLAG.xxxxx
|
||||
/// Function flags: A collection of boolean packed for memory efficiency
|
||||
/// See the `FUNCFLAG` enum
|
||||
uint flags = FUNCFLAG.NRVO;
|
||||
|
||||
/**
|
||||
* Data for a function declaration that is needed for the Objective-C
|
||||
@ -374,7 +374,8 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
/* The type given for "infer the return type" is a TypeFunction with
|
||||
* NULL for the return type.
|
||||
*/
|
||||
inferRetType = (type && type.nextOf() is null);
|
||||
if (type && type.nextOf() is null)
|
||||
this.flags |= FUNCFLAG.inferRetType;
|
||||
}
|
||||
|
||||
static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
|
||||
@ -480,7 +481,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
return false;
|
||||
}
|
||||
|
||||
return !errors && !semantic3Errors;
|
||||
return !errors && !this.hasSemantic3Errors();
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
@ -515,9 +516,11 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
*/
|
||||
extern (D) final void declareThis(Scope* sc)
|
||||
{
|
||||
isThis2 = toParent2() != toParentLocal();
|
||||
const bool dualCtx = (toParent2() != toParentLocal());
|
||||
if (dualCtx)
|
||||
this.flags |= FUNCFLAG.dualContext;
|
||||
auto ad = isThis();
|
||||
if (!isThis2 && !ad && !isNested())
|
||||
if (!dualCtx && !ad && !isNested())
|
||||
{
|
||||
vthis = null;
|
||||
objc.selectorParameter = null;
|
||||
@ -529,16 +532,16 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
return t.addMod(type.mod).addStorageClass(storage_class);
|
||||
}
|
||||
|
||||
if (isThis2 || isNested())
|
||||
if (dualCtx || isNested())
|
||||
{
|
||||
/* The 'this' for a nested function is the link to the
|
||||
* enclosing function's stack frame.
|
||||
* Note that nested functions and member functions are disjoint.
|
||||
*/
|
||||
Type tthis = addModStc(isThis2 ?
|
||||
Type tthis = addModStc(dualCtx ?
|
||||
Type.tvoidptr.sarrayOf(2).pointerTo() :
|
||||
Type.tvoid.pointerTo());
|
||||
vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null);
|
||||
vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
|
||||
vthis.storage_class |= STC.parameter | STC.nodtor;
|
||||
}
|
||||
else if (ad)
|
||||
@ -549,22 +552,6 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
if (thandle.ty == Tstruct)
|
||||
{
|
||||
vthis.storage_class |= STC.ref_;
|
||||
|
||||
/* if member function is marked 'inout', then 'this' is 'return ref'
|
||||
* The same thing is done for `ref inout` parameters in TypeFunction's semantic routine.
|
||||
*/
|
||||
if (auto tf = type.isTypeFunction())
|
||||
{
|
||||
/* This feature was a mistake, but existing code relies on it.
|
||||
* So only disable it in @safe code and DIP1000 code
|
||||
*/
|
||||
if (!(global.params.useDIP1000 == FeatureState.enabled &&
|
||||
tf.trust == TRUST.safe))
|
||||
{
|
||||
if (tf.isInOutQual())
|
||||
vthis.storage_class |= STC.return_;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -574,19 +561,8 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
vthis.storage_class |= STC.return_;
|
||||
if (tf.isScopeQual)
|
||||
vthis.storage_class |= STC.scope_;
|
||||
|
||||
/* Add STC.returnScope like typesem.d does for TypeFunction parameters,
|
||||
* at least it should be the same. At the moment, we'll just
|
||||
* do existing practice. But we should examine how TypeFunction does
|
||||
* it, for consistency.
|
||||
*/
|
||||
if (global.params.useDIP1000 != FeatureState.enabled &&
|
||||
!tf.isref && isRefReturnScope(vthis.storage_class))
|
||||
{
|
||||
/* if `ref return scope`, evaluate to `ref` `return scope`
|
||||
*/
|
||||
if (tf.isreturnscope)
|
||||
vthis.storage_class |= STC.returnScope;
|
||||
}
|
||||
}
|
||||
if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_))
|
||||
vthis.storage_class |= STC.maybescope;
|
||||
@ -1369,7 +1345,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
if (!tf.isnogc)
|
||||
flags |= FUNCFLAG.nogcInprocess;
|
||||
|
||||
if (!isVirtual() || introducing)
|
||||
if (!isVirtual() || this.isIntroducing())
|
||||
flags |= FUNCFLAG.returnInprocess;
|
||||
|
||||
// Initialize for inferring STC.scope_
|
||||
@ -1482,6 +1458,73 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
|
||||
}
|
||||
|
||||
final bool isNRVO() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.NRVO);
|
||||
}
|
||||
|
||||
final void isNRVO(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) this.flags |= FUNCFLAG.NRVO;
|
||||
else this.flags &= ~FUNCFLAG.NRVO;
|
||||
}
|
||||
|
||||
final bool isNaked() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.naked);
|
||||
}
|
||||
|
||||
final bool isGenerated() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.generated);
|
||||
}
|
||||
|
||||
final void isGenerated(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) this.flags |= FUNCFLAG.generated;
|
||||
else this.flags &= ~FUNCFLAG.generated;
|
||||
}
|
||||
|
||||
final bool isIntroducing() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.introducing);
|
||||
}
|
||||
|
||||
final bool hasSemantic3Errors() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.semantic3Errors);
|
||||
}
|
||||
|
||||
final bool hasNoEH() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.noEH);
|
||||
}
|
||||
|
||||
final bool inferRetType() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.inferRetType);
|
||||
}
|
||||
|
||||
final bool hasDualContext() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.dualContext);
|
||||
}
|
||||
|
||||
final bool hasAlwaysInlines() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.hasAlwaysInline);
|
||||
}
|
||||
|
||||
final bool isCrtCtor() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.CRTCtor);
|
||||
}
|
||||
|
||||
final bool isCrtDtor() const scope @safe pure nothrow @nogc
|
||||
{
|
||||
return !!(this.flags & FUNCFLAG.CRTDtor);
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* The function is doing something that may allocate with the GC,
|
||||
* so mark it as not nogc (not no-how).
|
||||
@ -1809,19 +1852,19 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
{
|
||||
auto ad = isThis();
|
||||
ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
|
||||
return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
|
||||
return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
|
||||
}
|
||||
|
||||
bool addPostInvariant()
|
||||
{
|
||||
auto ad = isThis();
|
||||
ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
|
||||
return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
|
||||
return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
{
|
||||
return generated ? "generated function" : "function";
|
||||
return this.isGenerated() ? "generated function" : "function";
|
||||
}
|
||||
|
||||
/********************************************
|
||||
@ -2163,7 +2206,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
vresult.parent = this;
|
||||
}
|
||||
|
||||
if (sc && vresult.semanticRun == PASS.init)
|
||||
if (sc && vresult.semanticRun == PASS.initial)
|
||||
{
|
||||
TypeFunction tf = type.toTypeFunction();
|
||||
if (tf.isref)
|
||||
@ -2609,35 +2652,124 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
return fd;
|
||||
}
|
||||
|
||||
/******************
|
||||
* Check parameters and return type of D main() function.
|
||||
* Issue error messages.
|
||||
*/
|
||||
extern (D) final void checkDmain()
|
||||
/+
|
||||
+ Checks the parameter and return types iff this is a `main` function.
|
||||
+
|
||||
+ The following signatures are allowed for a `D main`:
|
||||
+ - Either no or a single parameter of type `string[]`
|
||||
+ - Return type is either `void`, `int` or `noreturn`
|
||||
+
|
||||
+ The following signatures are standard C:
|
||||
+ - `int main()`
|
||||
+ - `int main(int, char**)`
|
||||
+
|
||||
+ This function accepts the following non-standard extensions:
|
||||
+ - `char** envp` as a third parameter
|
||||
+ - `void` / `noreturn` as return type
|
||||
+
|
||||
+ This function will issue errors for unexpected arguments / return types.
|
||||
+/
|
||||
extern (D) final void checkMain()
|
||||
{
|
||||
TypeFunction tf = type.toTypeFunction();
|
||||
const nparams = tf.parameterList.length;
|
||||
bool argerr;
|
||||
if (nparams == 1)
|
||||
{
|
||||
auto fparam0 = tf.parameterList[0];
|
||||
auto t = fparam0.type.toBasetype();
|
||||
if (t.ty != Tarray ||
|
||||
t.nextOf().ty != Tarray ||
|
||||
t.nextOf().nextOf().ty != Tchar ||
|
||||
fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
|
||||
{
|
||||
argerr = true;
|
||||
}
|
||||
}
|
||||
if (ident != Id.main || isMember() || isNested())
|
||||
return; // Not a main function
|
||||
|
||||
if (!tf.nextOf())
|
||||
TypeFunction tf = type.toTypeFunction();
|
||||
|
||||
Type retType = tf.nextOf();
|
||||
if (!retType)
|
||||
{
|
||||
// auto main(), check after semantic
|
||||
assert(this.inferRetType);
|
||||
else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid && tf.nextOf().ty != Tnoreturn)
|
||||
return;
|
||||
}
|
||||
|
||||
/// Checks whether `t` is equivalent to `char**`
|
||||
/// Ignores qualifiers and treats enums according to their base type
|
||||
static bool isCharPtrPtr(Type t)
|
||||
{
|
||||
auto tp = t.toBasetype().isTypePointer();
|
||||
if (!tp)
|
||||
return false;
|
||||
|
||||
tp = tp.next.toBasetype().isTypePointer();
|
||||
if (!tp)
|
||||
return false;
|
||||
|
||||
return tp.next.toBasetype().ty == Tchar;
|
||||
}
|
||||
|
||||
// Neither of these qualifiers is allowed because they affect the ABI
|
||||
enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
|
||||
|
||||
const nparams = tf.parameterList.length;
|
||||
bool argerr;
|
||||
|
||||
if (linkage == LINK.d)
|
||||
{
|
||||
if (nparams == 1)
|
||||
{
|
||||
auto fparam0 = tf.parameterList[0];
|
||||
auto t = fparam0.type.toBasetype();
|
||||
if (t.ty != Tarray ||
|
||||
t.nextOf().ty != Tarray ||
|
||||
t.nextOf().nextOf().ty != Tchar ||
|
||||
fparam0.storageClass & invalidSTC)
|
||||
{
|
||||
argerr = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (tf.parameterList.varargs || nparams >= 2 || argerr)
|
||||
error("parameter list must be empty or accept one parameter of type `string[]`");
|
||||
}
|
||||
|
||||
else if (linkage == LINK.c)
|
||||
{
|
||||
if (nparams == 2 || nparams == 3)
|
||||
{
|
||||
// Argument count must be int
|
||||
auto argCount = tf.parameterList[0];
|
||||
argerr |= !!(argCount.storageClass & invalidSTC);
|
||||
argerr |= argCount.type.toBasetype().ty != Tint32;
|
||||
|
||||
// Argument pointer must be char**
|
||||
auto argPtr = tf.parameterList[1];
|
||||
argerr |= !!(argPtr.storageClass & invalidSTC);
|
||||
argerr |= !isCharPtrPtr(argPtr.type);
|
||||
|
||||
// `char** environ` is a common extension, see J.5.1 of the C standard
|
||||
if (nparams == 3)
|
||||
{
|
||||
auto envPtr = tf.parameterList[2];
|
||||
argerr |= !!(envPtr.storageClass & invalidSTC);
|
||||
argerr |= !isCharPtrPtr(envPtr.type);
|
||||
}
|
||||
}
|
||||
else
|
||||
argerr = nparams != 0;
|
||||
|
||||
// Disallow variadic main() - except for K&R declarations in C files.
|
||||
// E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
|
||||
if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
|
||||
argerr |= true;
|
||||
|
||||
if (argerr)
|
||||
{
|
||||
error("parameters must match one of the following signatures");
|
||||
loc.errorSupplemental("`main()`");
|
||||
loc.errorSupplemental("`main(int argc, char** argv)`");
|
||||
loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
|
||||
}
|
||||
}
|
||||
else
|
||||
return; // Neither C nor D main, ignore (should probably be an error)
|
||||
|
||||
// Allow enums with appropriate base types (same ABI)
|
||||
retType = retType.toBasetype();
|
||||
|
||||
if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
|
||||
error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
|
||||
else if (tf.parameterList.varargs || nparams >= 2 || argerr)
|
||||
error("parameters must be `main()` or `main(string[] args)`");
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
@ -2649,7 +2781,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
*/
|
||||
final bool checkNRVO()
|
||||
{
|
||||
if (!nrvo_can || returns is null)
|
||||
if (!isNRVO() || returns is null)
|
||||
return false;
|
||||
|
||||
auto tf = type.toTypeFunction();
|
||||
@ -2661,7 +2793,7 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
if (auto ve = rs.exp.isVarExp())
|
||||
{
|
||||
auto v = ve.var.isVarDeclaration();
|
||||
if (!v || v.isOut() || v.isRef())
|
||||
if (!v || v.isReference())
|
||||
return false;
|
||||
else if (nrvo_var is null)
|
||||
{
|
||||
@ -2669,6 +2801,8 @@ extern (C++) class FuncDeclaration : Declaration
|
||||
// parameters and closure variables cannot be NRVOed.
|
||||
if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
|
||||
return false;
|
||||
if (v.nestedrefs.length && needsClosure())
|
||||
return false;
|
||||
// The variable type needs to be equivalent to the return type.
|
||||
if (!v.type.equivalent(tf.next))
|
||||
return false;
|
||||
|
@ -15,6 +15,7 @@ import core.stdc.stdint;
|
||||
import dmd.root.array;
|
||||
import dmd.root.filename;
|
||||
import dmd.common.outbuffer;
|
||||
import dmd.file_manager;
|
||||
import dmd.identifier;
|
||||
|
||||
/// Defines a setting for how compiler warnings and deprecations are handled
|
||||
@ -329,6 +330,9 @@ extern (C++) struct Global
|
||||
bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
|
||||
uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks
|
||||
|
||||
/// Cache files read from disk
|
||||
FileManager fileManager;
|
||||
|
||||
enum recursionLimit = 500; /// number of recursive template expansions before abort
|
||||
|
||||
nothrow:
|
||||
@ -383,6 +387,7 @@ extern (C++) struct Global
|
||||
|
||||
extern (C++) void _init()
|
||||
{
|
||||
this.fileManager = new FileManager();
|
||||
version (MARS)
|
||||
{
|
||||
vendor = "Digital Mars D";
|
||||
|
@ -19,6 +19,8 @@
|
||||
// Can't include arraytypes.h here, need to declare these directly.
|
||||
template <typename TYPE> struct Array;
|
||||
|
||||
class FileManager;
|
||||
|
||||
typedef unsigned char Diagnostic;
|
||||
enum
|
||||
{
|
||||
@ -292,6 +294,8 @@ struct Global
|
||||
bool hasMainFunction;
|
||||
unsigned varSequenceNumber;
|
||||
|
||||
FileManager* fileManager;
|
||||
|
||||
/* Start gagging. Return the current number of gagged errors
|
||||
*/
|
||||
unsigned startGagging();
|
||||
|
@ -1836,25 +1836,12 @@ public:
|
||||
t = te.sym.memtype;
|
||||
goto L1;
|
||||
}
|
||||
case Twchar:
|
||||
// BUG: need to cast(wchar)
|
||||
case Tdchar:
|
||||
// BUG: need to cast(dchar)
|
||||
if (cast(uinteger_t)v > 0xFF)
|
||||
{
|
||||
buf.printf("'\\U%08llx'", cast(long)v);
|
||||
break;
|
||||
}
|
||||
goto case;
|
||||
case Tchar:
|
||||
case Twchar:
|
||||
case Tdchar:
|
||||
{
|
||||
size_t o = buf.length;
|
||||
if (v == '\'')
|
||||
buf.writestring("'\\''");
|
||||
else if (isprint(cast(int)v) && v != '\\')
|
||||
buf.printf("'%c'", cast(int)v);
|
||||
else
|
||||
buf.printf("'\\x%02x'", cast(int)v);
|
||||
const o = buf.length;
|
||||
writeSingleCharLiteral(*buf, cast(dchar) v);
|
||||
if (hgs.ddoc)
|
||||
escapeDdocString(buf, o);
|
||||
break;
|
||||
@ -2761,9 +2748,15 @@ bool stcToBuffer(OutBuffer* buf, StorageClass stc)
|
||||
bool result = false;
|
||||
|
||||
if (stc & STC.scopeinferred)
|
||||
{
|
||||
//buf.writestring("scope-inferred ");
|
||||
stc &= ~(STC.scope_ | STC.scopeinferred);
|
||||
}
|
||||
if (stc & STC.returninferred)
|
||||
{
|
||||
//buf.writestring("return-inferred ");
|
||||
stc &= ~(STC.return_ | STC.returninferred);
|
||||
}
|
||||
|
||||
/* Put scope ref return into a standard order
|
||||
*/
|
||||
|
@ -285,7 +285,7 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
|
||||
if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0)
|
||||
return true;
|
||||
|
||||
if (!tf1.nextOf().equals(tf2.nextOf()))
|
||||
if (!cTypeEquivalence(tf1.next, tf2.next))
|
||||
return false; // function return types don't match
|
||||
|
||||
if (tf1.parameterList.length != tf2.parameterList.length)
|
||||
@ -318,3 +318,40 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
|
||||
//printf("t2: %s\n", tf2.toChars());
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Types haven't been merged yet, because we haven't done
|
||||
* semantic() yet.
|
||||
* But we still need to see if t1 and t2 are the same type.
|
||||
* Params:
|
||||
* t1 = first type
|
||||
* t2 = second type
|
||||
* Returns:
|
||||
* true if they are equivalent types
|
||||
*/
|
||||
bool cTypeEquivalence(Type t1, Type t2)
|
||||
{
|
||||
if (t1.equals(t2))
|
||||
return true; // that was easy
|
||||
|
||||
if (t1.ty != t2.ty || t1.mod != t2.mod)
|
||||
return false;
|
||||
|
||||
if (auto tp = t1.isTypePointer())
|
||||
return cTypeEquivalence(tp.next, t2.nextOf());
|
||||
|
||||
if (auto ta = t1.isTypeSArray())
|
||||
// Bug: should check array dimension
|
||||
return cTypeEquivalence(ta.next, t2.nextOf());
|
||||
|
||||
if (auto ts = t1.isTypeStruct())
|
||||
return ts.sym is t2.isTypeStruct().sym;
|
||||
|
||||
if (auto te = t1.isTypeEnum())
|
||||
return te.sym is t2.isTypeEnum().sym;
|
||||
|
||||
if (auto tf = t1.isTypeFunction())
|
||||
return cFuncEquivalence(tf, tf.isTypeFunction());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -114,4 +114,4 @@ public:
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
Expression *initializerToExpression(Initializer *init, Type *t = NULL);
|
||||
Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
|
||||
|
@ -1080,10 +1080,11 @@ Initializer inferType(Initializer init, Scope* sc)
|
||||
* Params:
|
||||
* init = `Initializer` AST node
|
||||
* itype = if not `null`, type to coerce expression to
|
||||
* isCfile = default initializers are different with C
|
||||
* Returns:
|
||||
* `Expression` created, `null` if cannot, `ErrorExp` for other errors
|
||||
*/
|
||||
extern (C++) Expression initializerToExpression(Initializer init, Type itype = null)
|
||||
extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
|
||||
{
|
||||
Expression visitVoid(VoidInitializer)
|
||||
{
|
||||
@ -1204,7 +1205,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
|
||||
if (!init.type) // don't know what type to use
|
||||
return null;
|
||||
if (!defaultInit)
|
||||
defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial);
|
||||
defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial, isCfile);
|
||||
element = defaultInit;
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ class Lexer
|
||||
bool doDocComment; // collect doc comment information
|
||||
bool anyToken; // seen at least one token
|
||||
bool commentToken; // comments are TOK.comment's
|
||||
bool tokenizeNewlines; // newlines are turned into TOK.endOfLine's
|
||||
|
||||
version (DMDLIB)
|
||||
{
|
||||
@ -116,6 +117,7 @@ class Lexer
|
||||
line = p;
|
||||
this.doDocComment = doDocComment;
|
||||
this.commentToken = commentToken;
|
||||
this.tokenizeNewlines = false;
|
||||
this.inTokenStringConstant = 0;
|
||||
this.lastDocLine = 0;
|
||||
//initKeywords();
|
||||
@ -227,6 +229,8 @@ class Lexer
|
||||
|
||||
/****************************
|
||||
* Turn next token in buffer into a token.
|
||||
* Params:
|
||||
* t = the token to set the resulting Token to
|
||||
*/
|
||||
final void scan(Token* t)
|
||||
{
|
||||
@ -286,7 +290,15 @@ class Lexer
|
||||
case '\r':
|
||||
p++;
|
||||
if (*p != '\n') // if CR stands by itself
|
||||
{
|
||||
endOfLine();
|
||||
if (tokenizeNewlines)
|
||||
{
|
||||
t.value = TOK.endOfLine;
|
||||
tokenizeNewlines = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
version (DMDLIB)
|
||||
{
|
||||
if (whitespaceToken)
|
||||
@ -299,6 +311,12 @@ class Lexer
|
||||
case '\n':
|
||||
p++;
|
||||
endOfLine();
|
||||
if (tokenizeNewlines)
|
||||
{
|
||||
t.value = TOK.endOfLine;
|
||||
tokenizeNewlines = false;
|
||||
return;
|
||||
}
|
||||
version (DMDLIB)
|
||||
{
|
||||
if (whitespaceToken)
|
||||
@ -1045,6 +1063,10 @@ class Lexer
|
||||
return;
|
||||
case '#':
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22825
|
||||
// Special token sequences are terminated by newlines,
|
||||
// and should not be skipped over.
|
||||
this.tokenizeNewlines = true;
|
||||
p++;
|
||||
if (parseSpecialTokenSequence())
|
||||
continue;
|
||||
@ -1064,6 +1086,12 @@ class Lexer
|
||||
{
|
||||
endOfLine();
|
||||
p++;
|
||||
if (tokenizeNewlines)
|
||||
{
|
||||
t.value = TOK.endOfLine;
|
||||
tokenizeNewlines = false;
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -2607,16 +2635,19 @@ class Lexer
|
||||
{
|
||||
auto linnum = this.scanloc.linnum;
|
||||
const(char)* filespec = null;
|
||||
const loc = this.loc();
|
||||
bool flags;
|
||||
|
||||
if (!linemarker)
|
||||
scan(&tok);
|
||||
if (tok.value == TOK.int32Literal || tok.value == TOK.int64Literal)
|
||||
{
|
||||
const lin = cast(int)(tok.unsvalue - 1);
|
||||
if (lin != tok.unsvalue - 1)
|
||||
error("line number `%lld` out of range", cast(ulong)tok.unsvalue);
|
||||
const lin = cast(int)(tok.unsvalue);
|
||||
if (lin != tok.unsvalue)
|
||||
{
|
||||
error(tok.loc, "line number `%lld` out of range", cast(ulong)tok.unsvalue);
|
||||
skipToNextLine();
|
||||
return;
|
||||
}
|
||||
else
|
||||
linnum = lin;
|
||||
}
|
||||
@ -2624,15 +2655,19 @@ class Lexer
|
||||
{
|
||||
}
|
||||
else
|
||||
goto Lerr;
|
||||
{
|
||||
error(tok.loc, "positive integer argument expected following `#line`");
|
||||
if (tok.value != TOK.endOfLine)
|
||||
skipToNextLine();
|
||||
return;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
switch (*p)
|
||||
scan(&tok);
|
||||
switch (tok.value)
|
||||
{
|
||||
case 0:
|
||||
case 0x1A:
|
||||
case '\n':
|
||||
Lnewline:
|
||||
case TOK.endOfFile:
|
||||
case TOK.endOfLine:
|
||||
if (!inTokenStringConstant)
|
||||
{
|
||||
this.scanloc.linnum = linnum;
|
||||
@ -2640,93 +2675,40 @@ class Lexer
|
||||
this.scanloc.filename = filespec;
|
||||
}
|
||||
return;
|
||||
case '\r':
|
||||
p++;
|
||||
if (*p != '\n')
|
||||
{
|
||||
p--;
|
||||
goto Lnewline;
|
||||
}
|
||||
continue;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\f':
|
||||
p++;
|
||||
continue; // skip white space
|
||||
case '_':
|
||||
case TOK.file:
|
||||
if (filespec || flags)
|
||||
goto Lerr;
|
||||
if (memcmp(p, "__FILE__".ptr, 8) == 0)
|
||||
filespec = mem.xstrdup(scanloc.filename);
|
||||
continue;
|
||||
case TOK.string_:
|
||||
if (filespec || flags)
|
||||
goto Lerr;
|
||||
if (tok.ptr[0] != '"' || tok.postfix != 0)
|
||||
goto Lerr;
|
||||
filespec = tok.ustring;
|
||||
continue;
|
||||
case TOK.int32Literal:
|
||||
if (!filespec)
|
||||
goto Lerr;
|
||||
if (linemarker && tok.unsvalue >= 1 && tok.unsvalue <= 4)
|
||||
{
|
||||
p += 8;
|
||||
filespec = mem.xstrdup(scanloc.filename);
|
||||
flags = true; // linemarker flags seen
|
||||
continue;
|
||||
}
|
||||
goto Lerr;
|
||||
case '"':
|
||||
if (filespec || flags)
|
||||
goto Lerr;
|
||||
stringbuffer.setsize(0);
|
||||
p++;
|
||||
while (1)
|
||||
{
|
||||
uint c;
|
||||
c = *p;
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
case '\r':
|
||||
case 0:
|
||||
case 0x1A:
|
||||
goto Lerr;
|
||||
case '"':
|
||||
stringbuffer.writeByte(0);
|
||||
filespec = mem.xstrdup(cast(const(char)*)stringbuffer[].ptr);
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
if (c & 0x80)
|
||||
{
|
||||
uint u = decodeUTF();
|
||||
if (u == PS || u == LS)
|
||||
goto Lerr;
|
||||
}
|
||||
stringbuffer.writeByte(c);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
if (!linemarker)
|
||||
goto Lerr;
|
||||
flags = true; // linemarker flags seen
|
||||
++p;
|
||||
if ('0' <= *p && *p <= '9')
|
||||
goto Lerr; // only one digit allowed
|
||||
continue;
|
||||
|
||||
default:
|
||||
if (*p & 0x80)
|
||||
{
|
||||
uint u = decodeUTF();
|
||||
if (u == PS || u == LS)
|
||||
goto Lnewline;
|
||||
}
|
||||
goto Lerr;
|
||||
}
|
||||
}
|
||||
Lerr:
|
||||
if (linemarker)
|
||||
error(loc, "# integer [\"filespec\"] { 1 | 2 | 3 | 4 }\\n expected");
|
||||
else
|
||||
error(loc, "#line integer [\"filespec\"]\\n expected");
|
||||
if (filespec is null)
|
||||
error(tok.loc, "invalid filename for `#line` directive");
|
||||
else if (linemarker)
|
||||
error(tok.loc, "invalid flag for line marker directive");
|
||||
else if (!Ccompile)
|
||||
error(tok.loc, "found `%s` when expecting new line following `#line` directive", tok.toChars());
|
||||
if (tok.value != TOK.endOfLine)
|
||||
skipToNextLine();
|
||||
}
|
||||
|
||||
/***************************************
|
||||
@ -2768,6 +2750,7 @@ class Lexer
|
||||
break;
|
||||
}
|
||||
endOfLine();
|
||||
tokenizeNewlines = false;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
@ -3004,7 +2987,7 @@ private struct TimeStampInfo
|
||||
if (auto p = getenv("SOURCE_DATE_EPOCH"))
|
||||
{
|
||||
if (!ct.parseDigits(p.toDString()))
|
||||
error(loc, "Value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
|
||||
error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
|
||||
}
|
||||
else
|
||||
.time(&ct);
|
||||
|
@ -4198,6 +4198,8 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
|
||||
ParameterList parameterList; // function parameters
|
||||
|
||||
// These flags can be accessed like `bool` properties,
|
||||
// getters and setters are generated for them
|
||||
private enum FunctionFlag : uint
|
||||
{
|
||||
none = 0,
|
||||
@ -4206,13 +4208,13 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
isproperty = 0x0004, // can be called without parentheses
|
||||
isref = 0x0008, // returns a reference
|
||||
isreturn = 0x0010, // 'this' is returned by ref
|
||||
isscope = 0x0020, // 'this' is scope
|
||||
isScopeQual = 0x0020, // 'this' is scope
|
||||
isreturninferred= 0x0040, // 'this' is return from inference
|
||||
isscopeinferred = 0x0080, // 'this' is scope from inference
|
||||
islive = 0x0100, // is @live
|
||||
incomplete = 0x0200, // return type or default arguments removed
|
||||
inoutParam = 0x0400, // inout on the parameters
|
||||
inoutQual = 0x0800, // inout on the qualifier
|
||||
isInOutParam = 0x0400, // inout on the parameters
|
||||
isInOutQual = 0x0800, // inout on the qualifier
|
||||
isctor = 0x1000, // the function is a constructor
|
||||
isreturnscope = 0x2000, // `this` is returned by value
|
||||
}
|
||||
@ -4480,7 +4482,7 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
{
|
||||
// Check escaping through return value
|
||||
Type tret = nextOf().toBasetype();
|
||||
if (isref || tret.hasPointers())
|
||||
if (isref || tret.hasPointers() || !isnothrow())
|
||||
{
|
||||
return stc;
|
||||
}
|
||||
@ -5084,177 +5086,29 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
return false;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `nothrow` attribute
|
||||
bool isnothrow() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isnothrow) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isnothrow(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isnothrow;
|
||||
else funcFlags &= ~FunctionFlag.isnothrow;
|
||||
}
|
||||
// Generate getter / setter functions for `FunctionFlag` members so they can be
|
||||
// treated like regular `bool` fields, instead of requiring bit twiddling to read/write
|
||||
extern (D) mixin(() {
|
||||
string result = "extern(C++) pure nothrow @safe @nogc {";
|
||||
foreach (string mem; __traits(allMembers, FunctionFlag))
|
||||
{
|
||||
result ~= "
|
||||
/// set or get if the function has the FunctionFlag attribute of the same name
|
||||
bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; }
|
||||
/// ditto
|
||||
void "~mem~"(bool v)
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag."~mem~";
|
||||
else funcFlags &= ~FunctionFlag."~mem~";
|
||||
}";
|
||||
}
|
||||
return result ~ "}\n";
|
||||
}());
|
||||
|
||||
/// set or get if the function has the `@nogc` attribute
|
||||
bool isnogc() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isnogc) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isnogc(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isnogc;
|
||||
else funcFlags &= ~FunctionFlag.isnogc;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `@property` attribute
|
||||
bool isproperty() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isproperty) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isproperty(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isproperty;
|
||||
else funcFlags &= ~FunctionFlag.isproperty;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `ref` attribute
|
||||
bool isref() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isref) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isref(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isref;
|
||||
else funcFlags &= ~FunctionFlag.isref;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `return` attribute
|
||||
bool isreturn() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isreturn) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isreturn(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isreturn;
|
||||
else funcFlags &= ~FunctionFlag.isreturn;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `returnscope` attribute
|
||||
bool isreturnscope() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isreturnscope) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isreturnscope(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isreturnscope;
|
||||
else funcFlags &= ~FunctionFlag.isreturnscope;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `scope` attribute
|
||||
bool isScopeQual() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isscope) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isScopeQual(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isscope;
|
||||
else funcFlags &= ~FunctionFlag.isscope;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `return` attribute inferred
|
||||
bool isreturninferred() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isreturninferred) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isreturninferred(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isreturninferred;
|
||||
else funcFlags &= ~FunctionFlag.isreturninferred;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `scope` attribute inferred
|
||||
bool isscopeinferred() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isscopeinferred) != 0;
|
||||
}
|
||||
/// ditoo
|
||||
void isscopeinferred(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isscopeinferred;
|
||||
else funcFlags &= ~FunctionFlag.isscopeinferred;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `@live` attribute
|
||||
bool islive() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.islive) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void islive(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.islive;
|
||||
else funcFlags &= ~FunctionFlag.islive;
|
||||
}
|
||||
|
||||
/// set or get if the return type or the default arguments are removed
|
||||
bool incomplete() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.incomplete) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void incomplete(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.incomplete;
|
||||
else funcFlags &= ~FunctionFlag.incomplete;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `inout` on the parameters
|
||||
bool isInOutParam() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.inoutParam) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isInOutParam(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.inoutParam;
|
||||
else funcFlags &= ~FunctionFlag.inoutParam;
|
||||
}
|
||||
|
||||
/// set or get if the function has the `inout` on the parameters
|
||||
bool isInOutQual() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.inoutQual) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isInOutQual(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.inoutQual;
|
||||
else funcFlags &= ~FunctionFlag.inoutQual;
|
||||
}
|
||||
/// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
|
||||
bool iswild() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & (FunctionFlag.inoutParam | FunctionFlag.inoutQual)) != 0;
|
||||
}
|
||||
|
||||
/// set or get if the function is a constructor
|
||||
bool isctor() const pure nothrow @safe @nogc
|
||||
{
|
||||
return (funcFlags & FunctionFlag.isctor) != 0;
|
||||
}
|
||||
/// ditto
|
||||
void isctor(bool v) pure nothrow @safe @nogc
|
||||
{
|
||||
if (v) funcFlags |= FunctionFlag.isctor;
|
||||
else funcFlags &= ~FunctionFlag.isctor;
|
||||
return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0;
|
||||
}
|
||||
|
||||
/// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
|
||||
@ -6418,9 +6272,6 @@ extern (C++) final class TypeClass : Type
|
||||
|
||||
override MOD deduceWild(Type t, bool isRef)
|
||||
{
|
||||
// If sym is forward referenced:
|
||||
if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
|
||||
sym.dsymbolSemantic(null);
|
||||
ClassDeclaration cd = t.isClassHandle();
|
||||
if (cd && (sym == cd || cd.isBaseOf(sym, null)))
|
||||
return Type.deduceWild(t, isRef);
|
||||
@ -7176,6 +7027,17 @@ extern (C++) final class Parameter : ASTNode
|
||||
|
||||
extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
|
||||
{
|
||||
// Workaround for failing covariance when finding a common type of delegates,
|
||||
// some of which have parameters with inferred scope
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21285
|
||||
// The root cause is that scopeinferred is not part of the mangle, and mangle
|
||||
// is used for type equality checks
|
||||
if (to & STC.returninferred)
|
||||
to &= ~STC.return_;
|
||||
// note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope
|
||||
if (to & STC.scopeinferred && !(to & STC.return_))
|
||||
to &= ~STC.scope_;
|
||||
|
||||
if (from == to)
|
||||
return true;
|
||||
|
||||
|
@ -137,9 +137,9 @@ public:
|
||||
|
||||
override void visit(DeleteExp e)
|
||||
{
|
||||
if (e.e1.op == EXP.variable)
|
||||
if (VarExp ve = e.e1.isVarExp())
|
||||
{
|
||||
VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
|
||||
VarDeclaration v = ve.var.isVarDeclaration();
|
||||
if (v && v.onstack)
|
||||
return; // delete for scope allocated class object
|
||||
}
|
||||
|
@ -1747,7 +1747,7 @@ PtrState toPtrState(VarDeclaration v)
|
||||
*/
|
||||
|
||||
auto t = v.type;
|
||||
if (v.isRef())
|
||||
if (v.isReference())
|
||||
{
|
||||
return t.hasMutableFields() ? PtrState.Borrowed : PtrState.Readonly;
|
||||
}
|
||||
@ -1775,7 +1775,7 @@ bool hasPointersToMutableFields(Type t)
|
||||
{
|
||||
foreach (v; ts.sym.fields)
|
||||
{
|
||||
if (v.isRef())
|
||||
if (v.isReference())
|
||||
{
|
||||
if (v.type.hasMutableFields())
|
||||
return true;
|
||||
@ -1977,7 +1977,12 @@ void checkObErrors(ref ObState obstate)
|
||||
else if (isReadonlyPtr(v))
|
||||
pvs.state = PtrState.Readonly;
|
||||
else
|
||||
{
|
||||
if (pvs.state == PtrState.Owner && v.type.hasPointersToMutableFields())
|
||||
v.error(e.loc, "assigning to Owner without disposing of owned value");
|
||||
|
||||
pvs.state = PtrState.Owner;
|
||||
}
|
||||
pvs.deps.zero();
|
||||
|
||||
EscapeByResults er;
|
||||
|
@ -711,7 +711,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
if (s)
|
||||
{
|
||||
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
|
||||
{
|
||||
return ErrorExp.get();
|
||||
}
|
||||
@ -720,7 +720,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
if (s_r)
|
||||
{
|
||||
functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
|
||||
{
|
||||
return ErrorExp.get();
|
||||
}
|
||||
@ -793,7 +793,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
if (s_r)
|
||||
{
|
||||
functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2);
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
|
||||
{
|
||||
return ErrorExp.get();
|
||||
}
|
||||
@ -802,7 +802,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
if (s)
|
||||
{
|
||||
functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1);
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
|
||||
{
|
||||
return ErrorExp.get();
|
||||
}
|
||||
@ -1250,7 +1250,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
|
||||
if (s)
|
||||
{
|
||||
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
|
||||
{
|
||||
return ErrorExp.get();
|
||||
}
|
||||
@ -1344,7 +1344,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop
|
||||
if (s)
|
||||
{
|
||||
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
|
||||
return ErrorExp.get();
|
||||
}
|
||||
FuncDeclaration lastf = m.lastf;
|
||||
@ -1352,7 +1352,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop
|
||||
if (s_r)
|
||||
{
|
||||
functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
|
||||
if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
|
||||
return ErrorExp.get();
|
||||
}
|
||||
if (m.count > 1)
|
||||
|
@ -504,6 +504,16 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
||||
{
|
||||
eint = ei;
|
||||
}
|
||||
else if (auto se = ep.e1.isSymOffExp())
|
||||
{
|
||||
if (!se.var.isReference() &&
|
||||
!se.var.isImportedSymbol() &&
|
||||
se.var.isDataseg())
|
||||
{
|
||||
var = se.var.isVarDeclaration();
|
||||
offset += se.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -531,7 +541,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
||||
if (auto ae = e.e1.isIndexExp())
|
||||
{
|
||||
// Convert &array[n] to &array+n
|
||||
if (ae.e2.op == EXP.int64 && ae.e1.isVarExp())
|
||||
if (ae.e2.isIntegerExp() && ae.e1.isVarExp())
|
||||
{
|
||||
sinteger_t index = ae.e2.toInteger();
|
||||
VarExp ve = ae.e1.isVarExp();
|
||||
@ -541,8 +551,13 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
||||
sinteger_t dim = ts.dim.toInteger();
|
||||
if (index < 0 || index >= dim)
|
||||
{
|
||||
e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
|
||||
return error();
|
||||
/* 0 for C static arrays means size is unknown, no need to check
|
||||
*/
|
||||
if (!(dim == 0 && ve.var.isCsymbol()))
|
||||
{
|
||||
e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
|
||||
return error();
|
||||
}
|
||||
}
|
||||
|
||||
import core.checkedint : mulu;
|
||||
@ -559,6 +574,33 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Convert &((a.b)[n]) to (&a.b)+n
|
||||
else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp())
|
||||
{
|
||||
sinteger_t index = ae.e2.toInteger();
|
||||
DotVarExp ve = ae.e1.isDotVarExp();
|
||||
if (ve.type.isTypeSArray() && ve.var.isField() && ve.e1.isPtrExp())
|
||||
{
|
||||
TypeSArray ts = ve.type.isTypeSArray();
|
||||
sinteger_t dim = ts.dim.toInteger();
|
||||
if (index < 0 || index >= dim)
|
||||
{
|
||||
/* 0 for C static arrays means size is unknown, no need to check
|
||||
*/
|
||||
if (!(dim == 0 && ve.var.isCsymbol()))
|
||||
{
|
||||
e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
|
||||
return error();
|
||||
}
|
||||
}
|
||||
|
||||
auto pe = new AddrExp(e.loc, ve);
|
||||
pe.type = e.type;
|
||||
ret = new AddExp(e.loc, pe, ae.e2);
|
||||
ret.type = e.type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3651,7 +3651,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
|
||||
case TOK.traits:
|
||||
if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp())
|
||||
if (te.ident && te.args)
|
||||
if (te.ident)
|
||||
{
|
||||
t = new AST.TypeTraits(token.loc, te);
|
||||
break;
|
||||
|
@ -209,5 +209,3 @@ extern (C++) final class PrintASTVisitor : Visitor
|
||||
putc(' ', stdout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,7 +20,7 @@ private size_t hash(size_t a) pure nothrow @nogc @safe
|
||||
return a ^ (a >> 7) ^ (a >> 4);
|
||||
}
|
||||
|
||||
struct KeyValueTemplate(K,V)
|
||||
private struct KeyValueTemplate(K,V)
|
||||
{
|
||||
K key;
|
||||
V value;
|
||||
@ -31,15 +31,17 @@ alias Value = void*;
|
||||
|
||||
alias KeyValue = KeyValueTemplate!(Key, Value);
|
||||
|
||||
struct aaA
|
||||
private struct aaA
|
||||
{
|
||||
private:
|
||||
aaA* next;
|
||||
KeyValue keyValue;
|
||||
alias keyValue this;
|
||||
}
|
||||
|
||||
struct AA
|
||||
private struct AA
|
||||
{
|
||||
private:
|
||||
aaA** b;
|
||||
size_t b_length;
|
||||
size_t nodes; // total number of aaA nodes
|
||||
|
@ -205,4 +205,3 @@ struct Array
|
||||
return data.ptr[--length];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -187,6 +187,3 @@ nothrow pure unittest
|
||||
a = b;
|
||||
assert(a == b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -45,11 +45,6 @@ struct FileBuffer
|
||||
data = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C++) static FileBuffer* create() pure nothrow @safe
|
||||
{
|
||||
return new FileBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@ -78,12 +73,6 @@ struct File
|
||||
|
||||
nothrow:
|
||||
/// Read the full content of a file.
|
||||
extern (C++) static ReadResult read(const(char)* name)
|
||||
{
|
||||
return read(name.toDString());
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
static ReadResult read(const(char)[] name)
|
||||
{
|
||||
ReadResult result;
|
||||
@ -179,24 +168,18 @@ nothrow:
|
||||
}
|
||||
|
||||
/// Write a file, returning `true` on success.
|
||||
extern (D) static bool write(const(char)* name, const void[] data)
|
||||
static bool write(const(char)* name, const void[] data)
|
||||
{
|
||||
import dmd.common.file : writeFile;
|
||||
return writeFile(name, data);
|
||||
}
|
||||
|
||||
///ditto
|
||||
extern(D) static bool write(const(char)[] name, const void[] data)
|
||||
static bool write(const(char)[] name, const void[] data)
|
||||
{
|
||||
return name.toCStringThen!((fname) => write(fname.ptr, data));
|
||||
}
|
||||
|
||||
/// ditto
|
||||
extern (C++) static bool write(const(char)* name, const(void)* data, size_t size)
|
||||
{
|
||||
return write(name, data[0 .. size]);
|
||||
}
|
||||
|
||||
/// Delete a file.
|
||||
extern (C++) static void remove(const(char)* name)
|
||||
{
|
||||
@ -229,7 +212,7 @@ nothrow:
|
||||
* Returns:
|
||||
* `true` on success
|
||||
*/
|
||||
extern (D) static bool update(const(char)* namez, const void[] data)
|
||||
static bool update(const(char)* namez, const void[] data)
|
||||
{
|
||||
enum log = false;
|
||||
if (log) printf("update %s\n", namez);
|
||||
@ -252,17 +235,11 @@ nothrow:
|
||||
}
|
||||
|
||||
///ditto
|
||||
extern(D) static bool update(const(char)[] name, const void[] data)
|
||||
static bool update(const(char)[] name, const void[] data)
|
||||
{
|
||||
return name.toCStringThen!(fname => update(fname.ptr, data));
|
||||
}
|
||||
|
||||
/// ditto
|
||||
extern (C++) static bool update(const(char)* name, const(void)* data, size_t size)
|
||||
{
|
||||
return update(name, data[0 .. size]);
|
||||
}
|
||||
|
||||
/// Size of a file in bytes.
|
||||
/// Params: namez = null-terminated filename
|
||||
/// Returns: `ulong.max` on any error, the length otherwise.
|
||||
|
@ -224,7 +224,7 @@ public:
|
||||
}
|
||||
|
||||
/// ditto
|
||||
extern(D) int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow
|
||||
int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow
|
||||
{
|
||||
foreach (const se; table)
|
||||
{
|
||||
|
@ -177,4 +177,3 @@ public:
|
||||
doCond(s.statement) || applyTo(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
// Disable generated opAssign, because some members forbid identity assignment.
|
||||
funcdecl.storage_class |= STC.disable;
|
||||
funcdecl.fbody = null; // remove fbody which contains the error
|
||||
funcdecl.semantic3Errors = false;
|
||||
funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -285,7 +285,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
if (funcdecl.semanticRun >= PASS.semantic3)
|
||||
return;
|
||||
funcdecl.semanticRun = PASS.semantic3;
|
||||
funcdecl.semantic3Errors = false;
|
||||
funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
|
||||
|
||||
if (!funcdecl.type || funcdecl.type.ty != Tfunction)
|
||||
return;
|
||||
@ -386,7 +386,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
// functions may be widely used by dmd-compiled projects.
|
||||
// It also gives more time for the implementation of dual-context
|
||||
// functions to be reworked as a frontend-only feature.
|
||||
if (funcdecl.isThis2)
|
||||
if (funcdecl.hasDualContext())
|
||||
{
|
||||
funcdecl.deprecation("function requires a dual-context, which is deprecated");
|
||||
if (auto ti = sc2.parent ? sc2.parent.isInstantiated() : null)
|
||||
@ -603,7 +603,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
if (!funcdecl.fbody)
|
||||
funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements());
|
||||
|
||||
if (funcdecl.naked)
|
||||
if (funcdecl.isNaked())
|
||||
{
|
||||
fpreinv = null; // can't accommodate with no stack frame
|
||||
fpostinv = null;
|
||||
@ -619,8 +619,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
f.next = Type.tvoid;
|
||||
if (f.checkRetType(funcdecl.loc))
|
||||
funcdecl.fbody = new ErrorStatement();
|
||||
else if (funcdecl.isMain())
|
||||
funcdecl.checkDmain(); // Check main() parameters and return type
|
||||
else
|
||||
funcdecl.checkMain(); // Check main() parameters and return type
|
||||
}
|
||||
|
||||
if (f.next !is null)
|
||||
@ -654,7 +654,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
|
||||
// handle NRVO
|
||||
if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO())
|
||||
funcdecl.nrvo_can = 0;
|
||||
funcdecl.flags &= ~FUNCFLAG.NRVO;
|
||||
|
||||
if (funcdecl.fbody.isErrorStatement())
|
||||
{
|
||||
@ -762,7 +762,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
/* Don't generate unwind tables for this function
|
||||
* https://issues.dlang.org/show_bug.cgi?id=17997
|
||||
*/
|
||||
funcdecl.eh_none = true;
|
||||
funcdecl.flags |= FUNCFLAG.noEH;
|
||||
}
|
||||
|
||||
if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
|
||||
@ -927,7 +927,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=10789
|
||||
* If NRVO is not possible, all returned lvalues should call their postblits.
|
||||
*/
|
||||
if (!funcdecl.nrvo_can)
|
||||
if (!funcdecl.isNRVO())
|
||||
exp = doCopyOrMove(sc2, exp, f.next);
|
||||
|
||||
if (tret.hasPointers())
|
||||
@ -996,7 +996,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
freq = freq.statementSemantic(sc2);
|
||||
freq.blockExit(funcdecl, false);
|
||||
|
||||
funcdecl.eh_none = false;
|
||||
funcdecl.flags &= ~FUNCFLAG.noEH;
|
||||
|
||||
sc2 = sc2.pop();
|
||||
|
||||
@ -1030,7 +1030,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
fens = fens.statementSemantic(sc2);
|
||||
fens.blockExit(funcdecl, false);
|
||||
|
||||
funcdecl.eh_none = false;
|
||||
funcdecl.flags &= ~FUNCFLAG.noEH;
|
||||
|
||||
sc2 = sc2.pop();
|
||||
|
||||
@ -1159,7 +1159,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
const blockexit = s.blockExit(funcdecl, isnothrow);
|
||||
if (blockexit & BE.throw_)
|
||||
{
|
||||
funcdecl.eh_none = false;
|
||||
funcdecl.flags &= ~FUNCFLAG.noEH;
|
||||
if (isnothrow)
|
||||
error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
|
||||
else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
|
||||
@ -1195,7 +1195,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
{
|
||||
// 'this' is the monitor
|
||||
vsync = new VarExp(funcdecl.loc, funcdecl.vthis);
|
||||
if (funcdecl.isThis2)
|
||||
if (funcdecl.hasDualContext())
|
||||
{
|
||||
vsync = new PtrExp(funcdecl.loc, vsync);
|
||||
vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0);
|
||||
@ -1230,7 +1230,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
}
|
||||
|
||||
// Fix up forward-referenced gotos
|
||||
if (funcdecl.gotos)
|
||||
if (funcdecl.gotos && !funcdecl.isCsymbol())
|
||||
{
|
||||
for (size_t i = 0; i < funcdecl.gotos.dim; ++i)
|
||||
{
|
||||
@ -1238,7 +1238,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
}
|
||||
}
|
||||
|
||||
if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires))
|
||||
if (funcdecl.isNaked() && (funcdecl.fensures || funcdecl.frequires))
|
||||
funcdecl.error("naked assembly functions with contracts are not supported");
|
||||
|
||||
sc2.ctorflow.callSuper = CSX.none;
|
||||
@ -1370,7 +1370,10 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
||||
* Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
|
||||
*/
|
||||
funcdecl.semanticRun = PASS.semantic3done;
|
||||
funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement());
|
||||
if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement()))
|
||||
funcdecl.flags |= FUNCFLAG.semantic3Errors;
|
||||
else
|
||||
funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
|
||||
if (funcdecl.type.ty == Terror)
|
||||
funcdecl.errors = true;
|
||||
//printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
|
||||
|
@ -1761,6 +1761,9 @@ extern (C++) final class GotoStatement : Statement
|
||||
return new GotoStatement(loc, ident);
|
||||
}
|
||||
|
||||
/**************
|
||||
* Returns: true for error
|
||||
*/
|
||||
extern (D) bool checkLabel()
|
||||
{
|
||||
if (!label.statement)
|
||||
|
@ -211,7 +211,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
if (f.checkForwardRef(s.exp.loc))
|
||||
s.exp = ErrorExp.get();
|
||||
}
|
||||
if (discardValue(s.exp))
|
||||
|
||||
if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
|
||||
s.exp = ErrorExp.get();
|
||||
|
||||
s.exp = s.exp.optimize(WANTvalue);
|
||||
@ -728,12 +729,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
Dsymbol sapply = null; // the inferred opApply() or front() function
|
||||
if (!inferForeachAggregate(sc, fs.op == TOK.foreach_, fs.aggr, sapply))
|
||||
{
|
||||
const(char)* msg = "";
|
||||
if (fs.aggr.type && isAggregate(fs.aggr.type))
|
||||
{
|
||||
msg = ", define `opApply()`, range primitives, or use `.tupleof`";
|
||||
}
|
||||
fs.error("invalid `foreach` aggregate `%s`%s", oaggr.toChars(), msg);
|
||||
assert(oaggr.type);
|
||||
|
||||
fs.error("invalid `foreach` aggregate `%s` of type `%s`", oaggr.toChars(), oaggr.type.toPrettyChars());
|
||||
if (isAggregate(fs.aggr.type))
|
||||
fs.loc.errorSupplemental("maybe define `opApply()`, range primitives, or use `.tupleof`");
|
||||
|
||||
return setError();
|
||||
}
|
||||
|
||||
@ -2310,12 +2311,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
needswitcherror = true;
|
||||
}
|
||||
|
||||
if (!sc.sw.sdefault && !(sc.flags & SCOPE.Cfile) &&
|
||||
if (!sc.sw.sdefault &&
|
||||
(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
|
||||
{
|
||||
ss.hasNoDefault = 1;
|
||||
|
||||
if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()))
|
||||
if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !(sc.flags & SCOPE.Cfile))
|
||||
ss.error("`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`");
|
||||
|
||||
// Generate runtime error if the default is hit
|
||||
@ -2323,7 +2324,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
CompoundStatement cs;
|
||||
Statement s;
|
||||
|
||||
if (global.params.useSwitchError == CHECKENABLE.on &&
|
||||
if (sc.flags & SCOPE.Cfile)
|
||||
{
|
||||
s = new BreakStatement(ss.loc, null); // default for C is `default: break;`
|
||||
}
|
||||
else if (global.params.useSwitchError == CHECKENABLE.on &&
|
||||
global.params.checkAction != CHECKACTION.halt)
|
||||
{
|
||||
if (global.params.checkAction == CHECKACTION.C)
|
||||
@ -2365,7 +2370,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
ss._body = cs;
|
||||
}
|
||||
|
||||
if (ss.checkLabel())
|
||||
if (!(sc.flags & SCOPE.Cfile) && ss.checkLabel())
|
||||
{
|
||||
sc.pop();
|
||||
return setError();
|
||||
@ -3840,7 +3845,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
fd.gotos = new GotoStatements();
|
||||
fd.gotos.push(gs);
|
||||
}
|
||||
else if (gs.checkLabel())
|
||||
else if (!(sc.flags & SCOPE.Cfile) && gs.checkLabel())
|
||||
return setError();
|
||||
|
||||
result = gs;
|
||||
@ -3916,12 +3921,10 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
||||
}
|
||||
|
||||
assert(sc.func);
|
||||
// use setImpure/setGC when the deprecation cycle is over
|
||||
PURE purity;
|
||||
if (!(cas.stc & STC.pure_) && (purity = sc.func.isPureBypassingInference()) != PURE.impure && purity != PURE.fwdref)
|
||||
cas.deprecation("`asm` statement is assumed to be impure - mark it with `pure` if it is not");
|
||||
if (!(cas.stc & STC.nogc) && sc.func.isNogcBypassingInference())
|
||||
cas.deprecation("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
|
||||
if (!(cas.stc & STC.pure_) && sc.func.setImpure())
|
||||
cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not");
|
||||
if (!(cas.stc & STC.nogc) && sc.func.setGC())
|
||||
cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
|
||||
if (!(cas.stc & (STC.trusted | STC.safe)) && sc.func.setUnsafe())
|
||||
cas.error("`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
|
||||
|
||||
|
@ -245,6 +245,7 @@ enum TOK : ubyte
|
||||
arrow, // ->
|
||||
colonColon, // ::
|
||||
wchar_tLiteral,
|
||||
endOfLine, // \n, \r, \u2028, \u2029
|
||||
whitespace,
|
||||
|
||||
// C only keywords
|
||||
@ -851,6 +852,7 @@ extern (C++) struct Token
|
||||
TOK.wcharLiteral: "wcharv",
|
||||
TOK.dcharLiteral: "dcharv",
|
||||
TOK.wchar_tLiteral: "wchar_tv",
|
||||
TOK.endOfLine: "\\n",
|
||||
TOK.whitespace: "whitespace",
|
||||
|
||||
// C only keywords
|
||||
@ -945,20 +947,19 @@ nothrow:
|
||||
sprintf(&buffer[0], "%d", cast(int)intvalue);
|
||||
break;
|
||||
case TOK.uns32Literal:
|
||||
case TOK.wcharLiteral:
|
||||
case TOK.dcharLiteral:
|
||||
case TOK.wchar_tLiteral:
|
||||
sprintf(&buffer[0], "%uU", cast(uint)unsvalue);
|
||||
break;
|
||||
case TOK.wcharLiteral:
|
||||
case TOK.dcharLiteral:
|
||||
case TOK.charLiteral:
|
||||
{
|
||||
const v = cast(int)intvalue;
|
||||
if (v >= ' ' && v <= '~')
|
||||
sprintf(&buffer[0], "'%c'", v);
|
||||
else
|
||||
sprintf(&buffer[0], "'\\x%02x'", v);
|
||||
{
|
||||
OutBuffer buf;
|
||||
buf.writeSingleCharLiteral(cast(dchar) intvalue);
|
||||
buf.writeByte('\0');
|
||||
p = buf.extractSlice().ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOK.int64Literal:
|
||||
sprintf(&buffer[0], "%lldL", cast(long)intvalue);
|
||||
break;
|
||||
@ -1090,7 +1091,7 @@ void writeCharLiteral(ref OutBuffer buf, dchar c)
|
||||
buf.writeByte('\\');
|
||||
goto default;
|
||||
default:
|
||||
if (c <= 0x7F)
|
||||
if (c <= 0xFF)
|
||||
{
|
||||
if (isprint(c))
|
||||
buf.writeByte(c);
|
||||
@ -1114,3 +1115,40 @@ unittest
|
||||
}
|
||||
assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single-quoted character literal
|
||||
*
|
||||
* Useful for printing '' char literals in e.g. error messages, ddoc, or the `.stringof` property
|
||||
*
|
||||
* Params:
|
||||
* buf = buffer to append character in
|
||||
* c = code point to write
|
||||
*/
|
||||
nothrow
|
||||
void writeSingleCharLiteral(ref OutBuffer buf, dchar c)
|
||||
{
|
||||
buf.writeByte('\'');
|
||||
if (c == '\'')
|
||||
buf.writeByte('\\');
|
||||
|
||||
if (c == '"')
|
||||
buf.writeByte('"');
|
||||
else
|
||||
writeCharLiteral(buf, c);
|
||||
|
||||
buf.writeByte('\'');
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
OutBuffer buf;
|
||||
writeSingleCharLiteral(buf, '\'');
|
||||
assert(buf.extractSlice() == `'\''`);
|
||||
buf.reset();
|
||||
writeSingleCharLiteral(buf, '"');
|
||||
assert(buf.extractSlice() == `'"'`);
|
||||
buf.reset();
|
||||
writeSingleCharLiteral(buf, '\n');
|
||||
assert(buf.extractSlice() == `'\n'`);
|
||||
}
|
||||
|
@ -254,6 +254,7 @@ enum class TOK : unsigned char
|
||||
arrow, // ->
|
||||
colonColon, // ::
|
||||
wchar_tLiteral,
|
||||
endOfLine, // \n, \r, \u2028, \u2029
|
||||
whitespace,
|
||||
|
||||
// C only keywords
|
||||
|
@ -80,10 +80,10 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg)
|
||||
{
|
||||
if (auto e = isExpression(oarg))
|
||||
{
|
||||
if (e.op == EXP.dotVariable)
|
||||
return (cast(DotVarExp)e).var;
|
||||
if (e.op == EXP.dotTemplateDeclaration)
|
||||
return (cast(DotTemplateExp)e).td;
|
||||
if (auto dve = e.isDotVarExp())
|
||||
return dve.var;
|
||||
if (auto dte = e.isDotTemplateExp())
|
||||
return dte.td;
|
||||
}
|
||||
return getDsymbol(oarg);
|
||||
}
|
||||
@ -833,7 +833,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
||||
e.error("argument `%s` has no visibility", o.toChars());
|
||||
return ErrorExp.get();
|
||||
}
|
||||
if (s.semanticRun == PASS.init)
|
||||
if (s.semanticRun == PASS.initial)
|
||||
s.dsymbolSemantic(null);
|
||||
|
||||
auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names)
|
||||
@ -1053,9 +1053,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
||||
}
|
||||
else if (e.ident == Id.getMember)
|
||||
{
|
||||
if (ex.op == EXP.dotIdentifier)
|
||||
if (auto die = ex.isDotIdExp())
|
||||
// Prevent semantic() from replacing Symbol with its initializer
|
||||
(cast(DotIdExp)ex).wantsym = true;
|
||||
die.wantsym = true;
|
||||
ex = ex.expressionSemantic(scx);
|
||||
return ex;
|
||||
}
|
||||
@ -2101,13 +2101,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
|
||||
return ErrorExp.get();
|
||||
}
|
||||
|
||||
if (sc.func is null)
|
||||
auto fd = sc.getEnclosingFunction();
|
||||
if (!fd)
|
||||
{
|
||||
e.error("`__traits(parameters)` may only be used inside a function");
|
||||
return ErrorExp.get();
|
||||
}
|
||||
assert(sc.func && sc.parent.isFuncDeclaration());
|
||||
auto tf = sc.parent.isFuncDeclaration.type.isTypeFunction();
|
||||
|
||||
auto tf = fd.type.isTypeFunction();
|
||||
assert(tf);
|
||||
auto exps = new Expressions(0);
|
||||
int addParameterDG(size_t idx, Parameter x)
|
||||
@ -2162,7 +2163,7 @@ private bool isSame(RootObject o1, RootObject o2, Scope* sc)
|
||||
{
|
||||
if (ea.op == EXP.function_)
|
||||
{
|
||||
if (auto fe = cast(FuncExp)ea)
|
||||
if (auto fe = ea.isFuncExp())
|
||||
return fe.fd;
|
||||
}
|
||||
}
|
||||
|
@ -978,7 +978,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
// duplicate a part of StructDeclaration::semanticTypeInfoMembers
|
||||
//printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
|
||||
|
||||
if (sd.xeq && sd.xeq.generated && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
|
||||
if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
|
||||
{
|
||||
uint errors = global.startGagging();
|
||||
sd.xeq.semantic3(sd.xeq._scope);
|
||||
@ -1431,12 +1431,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if ((fparam.storageClass & (STC.ref_ | STC.wild)) == (STC.ref_ | STC.wild))
|
||||
{
|
||||
// 'ref inout' implies 'return'
|
||||
fparam.storageClass |= STC.return_;
|
||||
}
|
||||
|
||||
if (fparam.storageClass & STC.return_)
|
||||
{
|
||||
if (fparam.isReference())
|
||||
@ -1799,6 +1793,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
mtype.exp.ident != Id.derivedMembers &&
|
||||
mtype.exp.ident != Id.getMember &&
|
||||
mtype.exp.ident != Id.parent &&
|
||||
mtype.exp.ident != Id.parameters &&
|
||||
mtype.exp.ident != Id.child &&
|
||||
mtype.exp.ident != Id.toType &&
|
||||
mtype.exp.ident != Id.getOverloads &&
|
||||
@ -3088,7 +3083,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
|
||||
//static int nest; if (++nest == 50) *(char*)0=0;
|
||||
if (sc is null)
|
||||
{
|
||||
error(loc, "Invalid scope.");
|
||||
error(loc, "invalid scope");
|
||||
return returnError();
|
||||
}
|
||||
if (mt.inuse)
|
||||
@ -4076,7 +4071,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
|
||||
return e.expressionSemantic(sc);
|
||||
}
|
||||
}
|
||||
if (d.semanticRun == PASS.init)
|
||||
if (d.semanticRun == PASS.initial)
|
||||
d.dsymbolSemantic(null);
|
||||
checkAccess(e.loc, sc, e, d);
|
||||
auto ve = new VarExp(e.loc, d);
|
||||
@ -4307,7 +4302,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
|
||||
|
||||
if (ident == Id.outer && mt.sym.vthis)
|
||||
{
|
||||
if (mt.sym.vthis.semanticRun == PASS.init)
|
||||
if (mt.sym.vthis.semanticRun == PASS.initial)
|
||||
mt.sym.vthis.dsymbolSemantic(null);
|
||||
|
||||
if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
|
||||
@ -4503,7 +4498,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
|
||||
Expression e1;
|
||||
Type t;
|
||||
/* returns: true to continue, false to return */
|
||||
if (f.isThis2)
|
||||
if (f.hasDualContext())
|
||||
{
|
||||
if (f.followInstantiationContext(ad))
|
||||
{
|
||||
@ -4560,7 +4555,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
|
||||
}
|
||||
}
|
||||
//printf("e = %s, d = %s\n", e.toChars(), d.toChars());
|
||||
if (d.semanticRun == PASS.init)
|
||||
if (d.semanticRun == PASS.initial)
|
||||
d.dsymbolSemantic(null);
|
||||
|
||||
// If static function, get the most visible overload.
|
||||
|
@ -63,7 +63,7 @@ FileBuffer readFile(Loc loc, const(char)[] filename)
|
||||
auto result = File.read(filename);
|
||||
if (!result.success)
|
||||
{
|
||||
error(loc, "Error reading file `%.*s`", cast(int)filename.length, filename.ptr);
|
||||
error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
|
||||
fatal();
|
||||
}
|
||||
return FileBuffer(result.extractSlice());
|
||||
|
@ -1441,7 +1441,7 @@ public:
|
||||
gcc_assert (e->e1->op == EXP::variable);
|
||||
|
||||
VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration ();
|
||||
gcc_assert (v && v->onstack);
|
||||
gcc_assert (v && v->onstack ());
|
||||
|
||||
libcall_fn libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
|
||||
? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
|
||||
|
@ -141,7 +141,7 @@ get_internal_fn (tree ident, const Visibility &visibility)
|
||||
|
||||
FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid,
|
||||
Identifier::idPool (name));
|
||||
fd->generated = true;
|
||||
fd->isGenerated (true);
|
||||
fd->loc = Loc (mod->srcfile.toChars (), 1, 0);
|
||||
fd->parent = mod;
|
||||
fd->visibility = visibility;
|
||||
|
@ -958,7 +958,7 @@ public:
|
||||
/* If returning via NRVO, just refer to the DECL_RESULT; this differs
|
||||
from using NULL_TREE in that it indicates that we care about the
|
||||
value of the DECL_RESULT. */
|
||||
if (this->func_->nrvo_can && this->func_->nrvo_var)
|
||||
if (this->func_->isNRVO () && this->func_->nrvo_var)
|
||||
{
|
||||
add_stmt (return_expr (decl));
|
||||
return;
|
||||
|
27
gcc/testsuite/gdc.dg/nrvo1.d
Normal file
27
gcc/testsuite/gdc.dg/nrvo1.d
Normal file
@ -0,0 +1,27 @@
|
||||
// { dg-do compile }
|
||||
// { dg-additional-options "-fpreview=dip1000" }
|
||||
ThreadInfo* ptr;
|
||||
|
||||
ThreadInfo receiveOnly()
|
||||
{
|
||||
ThreadInfo ret;
|
||||
|
||||
get({ptr = &ret;});
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct ThreadInfo
|
||||
{
|
||||
ThreadInfo* next;
|
||||
}
|
||||
|
||||
bool get(T)(T)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
auto t = receiveOnly();
|
||||
assert(&t == ptr);
|
||||
}
|
@ -25,4 +25,4 @@ static assert(S.foo!([]) == 0);
|
||||
|
||||
alias fooFuns = AliasSeq!(__traits(getOverloads, S, "foo"));
|
||||
static assert(fooFuns.length == 1);
|
||||
static assert(fooFuns[0]("") == 2);
|
||||
static assert(fooFuns[0]("") == 2);
|
||||
|
@ -38,4 +38,3 @@ alias TK2 = reverse!(int, const uint, X2);
|
||||
static assert(TK2[0] == 3);
|
||||
static assert(is(TK2[1] == const(uint)));
|
||||
static assert(is(TK2[2] == int));
|
||||
|
||||
|
@ -16,4 +16,3 @@ struct Vector(T)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// REQUIRED_ARGS: -unittest
|
||||
// PERMUTE_ARGS: -preview=dip1000
|
||||
// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
|
||||
unittest
|
||||
{
|
||||
@ -25,3 +26,36 @@ unittest
|
||||
static assert(is(typeof(a[0]) == dg));
|
||||
static assert(is(typeof(ab[0]) == fn));
|
||||
}
|
||||
|
||||
int f(string s) { throw new Exception(""); }
|
||||
void main()
|
||||
{
|
||||
string path;
|
||||
int bank, preset;
|
||||
void delegate(string value)[string] aa = [
|
||||
"path": (string arg) {
|
||||
path = arg;
|
||||
},
|
||||
"bank": (string arg) {
|
||||
bank = f(arg);
|
||||
},
|
||||
"preset": (string arg) {
|
||||
preset = f(arg);
|
||||
},
|
||||
];
|
||||
|
||||
string delegate(string value)[string] aa2 = [
|
||||
"path": (string arg) {
|
||||
path = arg;
|
||||
return arg;
|
||||
},
|
||||
"bank": (string arg) {
|
||||
bank = f(arg);
|
||||
return arg;
|
||||
},
|
||||
"preset": (string arg) {
|
||||
preset = f(arg);
|
||||
return arg;
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -9,4 +9,3 @@ size_t fn()
|
||||
{
|
||||
return find( "123" );
|
||||
}
|
||||
|
||||
|
@ -22,4 +22,3 @@ void applyNoRemoveRegex()
|
||||
auto a = find!((a){return match(e);})(map!regex(noRemoveStr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,4 +36,3 @@ void main()
|
||||
f(s1.s.tupleof); // OK
|
||||
f((s1.s).tupleof); // Error: need 'this' to access member s
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
import core.stdc.stdio;
|
||||
|
||||
extern (C) int main(char** argv, int argc) {
|
||||
extern (C) int main()
|
||||
{
|
||||
printf("hello world\n");
|
||||
int[3] a;
|
||||
foo(a[], 3);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import core.stdc.stdio;
|
||||
|
||||
extern (C) int main(char** argv, int argc) {
|
||||
extern (C) int main()
|
||||
{
|
||||
printf("hello world\n");
|
||||
foo(3);
|
||||
return 0;
|
||||
|
@ -32,5 +32,3 @@ void funchds(char *p_adults)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,4 +145,3 @@ bool test_eq(double x, double y) { return x == y; }
|
||||
bool test_ne(double x, double y) { return x != y; }
|
||||
bool test_ge(double x, double y) { return x >= y; }
|
||||
bool test_gt(double x, double y) { return x > y; }
|
||||
|
||||
|
@ -37,5 +37,3 @@ static assert(6.0 % 4.0 == 2);
|
||||
static assert(6.0i % 2.0i == 0);
|
||||
static assert(6.0i % 3.0i == 0);
|
||||
static assert(6.0i % 4.0i == 2i);
|
||||
|
||||
|
||||
|
@ -47,7 +47,7 @@ wchar YY; /// ditto
|
||||
* argulid = the argument
|
||||
* u = the other argument
|
||||
*/
|
||||
int foo(char c, int argulid, char u);
|
||||
int foo(char c, int argulid, char u = '\'', wchar v = '\u7233', dchar y = '\U00017233');
|
||||
|
||||
int barr() { return 3; } /// doc for barr()
|
||||
|
||||
|
@ -62,8 +62,3 @@ private:
|
||||
void test1()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,4 +6,3 @@
|
||||
void test()(string[] args) if (args[$])
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -22,4 +22,4 @@ $(BR)
|
||||
1__a $(BR)
|
||||
2__b
|
||||
*/
|
||||
int i;
|
||||
int i;
|
||||
|
@ -23,4 +23,3 @@ struct Bug4107b(T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,3 @@ pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7
|
||||
auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9
|
||||
pure nothrow:
|
||||
V mColon(lazy P p) {} /// 10
|
||||
|
||||
|
||||
|
||||
|
@ -39,4 +39,3 @@ class StreamException: Exception {
|
||||
/********** stars ***************/
|
||||
int stars;
|
||||
}
|
||||
|
||||
|
@ -34,4 +34,3 @@ template staticIndexOf(T, TList...) { alias int staticIndexOf; }
|
||||
alias staticIndexOf IndexOf;
|
||||
|
||||
void main() { }
|
||||
|
||||
|
@ -68,4 +68,3 @@ class StreamException: Exception {
|
||||
/********** stars ***************/
|
||||
int stars;
|
||||
}
|
||||
|
||||
|
@ -28,4 +28,3 @@ class TestMembers(TemplateArg)
|
||||
void main()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -22,4 +22,3 @@ void main()
|
||||
C:\code\d\bugs>dmd -D -o- 148_1.d
|
||||
148_1.d(6): Error: static if conditional cannot be at global scope
|
||||
+/
|
||||
|
||||
|
@ -10,5 +10,3 @@ enum int c6491 = 4;
|
||||
|
||||
/// test
|
||||
void bug6491a(int a = ddoc6491.c6491, string b = core.cpuid.vendor);
|
||||
|
||||
|
||||
|
@ -56,4 +56,3 @@ class C
|
||||
/// Some doc
|
||||
abstract void foo();
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,3 @@ writeln(&a);
|
||||
---
|
||||
*/
|
||||
void foo() { }
|
||||
|
||||
|
||||
|
||||
|
@ -26,4 +26,3 @@ unittest
|
||||
{
|
||||
// bar comment
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,6 @@ struct S final
|
||||
{
|
||||
int32_t y;
|
||||
double z;
|
||||
extern "C" void foo();
|
||||
void bar();
|
||||
};
|
||||
struct
|
||||
|
@ -82,7 +82,9 @@ public:
|
||||
int32_t a;
|
||||
C* c;
|
||||
virtual void foo();
|
||||
extern "C" virtual void bar();
|
||||
private:
|
||||
virtual void __vtable_slot_0();
|
||||
public:
|
||||
virtual void baz(int32_t x = 42);
|
||||
struct
|
||||
{
|
||||
@ -116,7 +118,7 @@ public:
|
||||
{
|
||||
public:
|
||||
int32_t x;
|
||||
A* this;
|
||||
A* outer;
|
||||
};
|
||||
|
||||
typedef Inner I;
|
||||
@ -146,8 +148,8 @@ public:
|
||||
|
||||
class Parent
|
||||
{
|
||||
virtual void __vtable_slot_0();
|
||||
virtual void __vtable_slot_1();
|
||||
virtual void __vtable_slot_2();
|
||||
public:
|
||||
virtual void foo();
|
||||
};
|
||||
|
@ -45,6 +45,9 @@ struct S final
|
||||
int32_t b;
|
||||
int64_t c;
|
||||
_d_dynamicArray< int32_t > arr;
|
||||
private:
|
||||
~S();
|
||||
public:
|
||||
S() :
|
||||
a(),
|
||||
b(),
|
||||
@ -81,7 +84,6 @@ struct S3 final
|
||||
int32_t a;
|
||||
int32_t b;
|
||||
int64_t c;
|
||||
extern "C" S3(int32_t a);
|
||||
S3() :
|
||||
a(42),
|
||||
b(),
|
||||
@ -143,7 +145,6 @@ struct A final
|
||||
{
|
||||
int32_t a;
|
||||
S s;
|
||||
extern "C" void bar();
|
||||
void baz(int32_t x = 42);
|
||||
struct
|
||||
{
|
||||
@ -232,6 +233,7 @@ extern (C++) struct S
|
||||
int b;
|
||||
long c;
|
||||
int[] arr;
|
||||
extern(D) ~this() {}
|
||||
}
|
||||
|
||||
extern (C++) struct S2
|
||||
|
@ -39,7 +39,7 @@ struct _d_dynamicArray final
|
||||
};
|
||||
#endif
|
||||
#if !defined(_d_real)
|
||||
# define _d_real long double
|
||||
#define _d_real long double
|
||||
#endif
|
||||
|
||||
extern "C" int32_t z;
|
||||
|
@ -40,7 +40,7 @@ struct _d_dynamicArray final
|
||||
};
|
||||
#endif
|
||||
#if !defined(_d_real)
|
||||
# define _d_real long double
|
||||
#define _d_real long double
|
||||
#endif
|
||||
|
||||
class ClassFromStruct final
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user