1 /**
2 * Defines the bulk of the classes which represent the AST at the expression level.
3 *
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5 *
6 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d)
10 * Documentation: https://dlang.org/phobos/dmd_expression.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d
12 */
13
14 module dmd.expression;
15
16 import core.stdc.stdarg;
17 import core.stdc.stdio;
18 import core.stdc.string;
19
20 import dmd.aggregate;
21 import dmd.aliasthis;
22 import dmd.apply;
23 import dmd.arrayop;
24 import dmd.arraytypes;
25 import dmd.astenums;
26 import dmd.ast_node;
27 import dmd.gluelayer;
28 import dmd.constfold;
29 import dmd.ctfeexpr;
30 import dmd.ctorflow;
31 import dmd.dcast;
32 import dmd.dclass;
33 import dmd.declaration;
34 import dmd.delegatize;
35 import dmd.dimport;
36 import dmd.dinterpret;
37 import dmd.dmodule;
38 import dmd.dscope;
39 import dmd.dstruct;
40 import dmd.dsymbol;
41 import dmd.dsymbolsem;
42 import dmd.dtemplate;
43 import dmd.errors;
44 import dmd.escape;
45 import dmd.expressionsem;
46 import dmd.func;
47 import dmd.globals;
48 import dmd.hdrgen;
49 import dmd.id;
50 import dmd.identifier;
51 import dmd.init;
52 import dmd.inline;
53 import dmd.mtype;
54 import dmd.nspace;
55 import dmd.objc;
56 import dmd.opover;
57 import dmd.optimize;
58 import dmd.root.complex;
59 import dmd.root.ctfloat;
60 import dmd.root.filename;
61 import dmd.common.outbuffer;
62 import dmd.root.optional;
63 import dmd.root.rmem;
64 import dmd.root.rootobject;
65 import dmd.root.string;
66 import dmd.root.utf;
67 import dmd.safe;
68 import dmd.sideeffect;
69 import dmd.target;
70 import dmd.tokens;
71 import dmd.typesem;
72 import dmd.visitor;
73
74 enum LOGSEMANTIC = false;
75
76 void emplaceExp(T : Expression, Args...)(void* p, Args args)
77 {
78 static if (__VERSION__ < 2099)
79 const init = typeid(T).initializer;
80 else
81 const init = __traits(initSymbol, T);
82 p[0 .. __traits(classInstanceSize, T)] = init[];
83 (cast(T)p).__ctor(args);
84 }
85
86 void emplaceExp(T : UnionExp)(T* p, Expression e)
87 {
88 memcpy(p, cast(void*)e, e.size);
89 }
90
91 /// Return value for `checkModifiable`
92 enum Modifiable
93 {
94 /// Not modifiable
95 no,
96 /// Modifiable (the type is mutable)
97 yes,
98 /// Modifiable because it is initialization
99 initialization,
100 }
101 /**
102 * Specifies how the checkModify deals with certain situations
103 */
104 enum ModifyFlags
105 {
106 /// Issue error messages on invalid modifications of the variable
107 none,
108 /// No errors are emitted for invalid modifications
109 noError = 0x1,
110 /// The modification occurs for a subfield of the current variable
111 fieldAssign = 0x2,
112 }
113
114 /****************************************
115 * Find the first non-comma expression.
116 * Params:
117 * e = Expressions connected by commas
118 * Returns:
119 * left-most non-comma expression
120 */
firstComma(inout Expression e)121 inout(Expression) firstComma(inout Expression e)
122 {
123 Expression ex = cast()e;
124 while (ex.op == EXP.comma)
125 ex = (cast(CommaExp)ex).e1;
126 return cast(inout)ex;
127
128 }
129
130 /****************************************
131 * Find the last non-comma expression.
132 * Params:
133 * e = Expressions connected by commas
134 * Returns:
135 * right-most non-comma expression
136 */
137
lastComma(inout Expression e)138 inout(Expression) lastComma(inout Expression e)
139 {
140 Expression ex = cast()e;
141 while (ex.op == EXP.comma)
142 ex = (cast(CommaExp)ex).e2;
143 return cast(inout)ex;
144
145 }
146
147 /*****************************************
148 * Determine if `this` is available by walking up the enclosing
149 * scopes until a function is found.
150 *
151 * Params:
152 * sc = where to start looking for the enclosing function
153 * Returns:
154 * Found function if it satisfies `isThis()`, otherwise `null`
155 */
hasThis(Scope * sc)156 FuncDeclaration hasThis(Scope* sc)
157 {
158 //printf("hasThis()\n");
159 Dsymbol p = sc.parent;
160 while (p && p.isTemplateMixin())
161 p = p.parent;
162 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
163 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
164
165 // Go upwards until we find the enclosing member function
166 FuncDeclaration fd = fdthis;
167 while (1)
168 {
169 if (!fd)
170 {
171 return null;
172 }
173 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
174 break;
175
176 Dsymbol parent = fd.parent;
177 while (1)
178 {
179 if (!parent)
180 return null;
181 TemplateInstance ti = parent.isTemplateInstance();
182 if (ti)
183 parent = ti.parent;
184 else
185 break;
186 }
187 fd = parent.isFuncDeclaration();
188 }
189
190 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
191 {
192 return null;
193 }
194
195 assert(fd.vthis);
196 return fd;
197
198 }
199
200 /***********************************
201 * Determine if a `this` is needed to access `d`.
202 * Params:
203 * sc = context
204 * d = declaration to check
205 * Returns:
206 * true means a `this` is needed
207 */
isNeedThisScope(Scope * sc,Declaration d)208 bool isNeedThisScope(Scope* sc, Declaration d)
209 {
210 if (sc.intypeof == 1)
211 return false;
212
213 AggregateDeclaration ad = d.isThis();
214 if (!ad)
215 return false;
216 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
217
218 for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
219 {
220 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
221 if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
222 {
223 if (ad2 == ad)
224 return false;
225 else if (ad2.isNested())
226 continue;
227 else
228 return true;
229 }
230 if (FuncDeclaration f = s.isFuncDeclaration())
231 {
232 if (f.isMemberLocal())
233 break;
234 }
235 }
236 return true;
237 }
238
239 /******************************
240 * check e is exp.opDispatch!(tiargs) or not
241 * It's used to switch to UFCS the semantic analysis path
242 */
isDotOpDispatch(Expression e)243 bool isDotOpDispatch(Expression e)
244 {
245 if (auto dtie = e.isDotTemplateInstanceExp())
246 return dtie.ti.name == Id.opDispatch;
247 return false;
248 }
249
250 /****************************************
251 * Expand tuples.
252 * Input:
253 * exps aray of Expressions
254 * Output:
255 * exps rewritten in place
256 */
expandTuples(Expressions * exps)257 extern (C++) void expandTuples(Expressions* exps)
258 {
259 //printf("expandTuples()\n");
260 if (exps is null)
261 return;
262
263 for (size_t i = 0; i < exps.dim; i++)
264 {
265 Expression arg = (*exps)[i];
266 if (!arg)
267 continue;
268
269 // Look for tuple with 0 members
270 if (auto e = arg.isTypeExp())
271 {
272 if (auto tt = e.type.toBasetype().isTypeTuple())
273 {
274 if (!tt.arguments || tt.arguments.dim == 0)
275 {
276 exps.remove(i);
277 if (i == exps.dim)
278 return;
279 }
280 else // Expand a TypeTuple
281 {
282 exps.remove(i);
283 auto texps = new Expressions(tt.arguments.length);
284 foreach (j, a; *tt.arguments)
285 (*texps)[j] = new TypeExp(e.loc, a.type);
286 exps.insert(i, texps);
287 }
288 i--;
289 continue;
290 }
291 }
292
293 // Inline expand all the tuples
294 while (arg.op == EXP.tuple)
295 {
296 TupleExp te = cast(TupleExp)arg;
297 exps.remove(i); // remove arg
298 exps.insert(i, te.exps); // replace with tuple contents
299 if (i == exps.dim)
300 return; // empty tuple, no more arguments
301 (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
302 arg = (*exps)[i];
303 }
304 }
305 }
306
307 /****************************************
308 * Expand alias this tuples.
309 */
isAliasThisTuple(Expression e)310 TupleDeclaration isAliasThisTuple(Expression e)
311 {
312 if (!e.type)
313 return null;
314
315 Type t = e.type.toBasetype();
316 while (true)
317 {
318 if (Dsymbol s = t.toDsymbol(null))
319 {
320 if (auto ad = s.isAggregateDeclaration())
321 {
322 s = ad.aliasthis ? ad.aliasthis.sym : null;
323 if (s && s.isVarDeclaration())
324 {
325 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
326 if (td && td.isexp)
327 return td;
328 }
329 if (Type att = t.aliasthisOf())
330 {
331 t = att;
332 continue;
333 }
334 }
335 }
336 return null;
337 }
338 }
339
340 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
341 {
342 if (!exps || exps.dim == 0)
343 return -1;
344
345 for (size_t u = starti; u < exps.dim; u++)
346 {
347 Expression exp = (*exps)[u];
348 if (TupleDeclaration td = exp.isAliasThisTuple)
349 {
350 exps.remove(u);
351 foreach (i, o; *td.objects)
352 {
353 auto d = o.isExpression().isDsymbolExp().s.isDeclaration();
354 auto e = new DotVarExp(exp.loc, exp, d);
355 assert(d.type);
356 e.type = d.type;
357 exps.insert(u + i, e);
358 }
version(none)359 version (none)
360 {
361 printf("expansion ->\n");
362 foreach (e; exps)
363 {
364 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
365 }
366 }
367 return cast(int)u;
368 }
369 }
370 return -1;
371 }
372
373 /****************************************
374 * If `s` is a function template, i.e. the only member of a template
375 * and that member is a function, return that template.
376 * Params:
377 * s = symbol that might be a function template
378 * Returns:
379 * template for that function, otherwise null
380 */
getFuncTemplateDecl(Dsymbol s)381 TemplateDeclaration getFuncTemplateDecl(Dsymbol s)
382 {
383 FuncDeclaration f = s.isFuncDeclaration();
384 if (f && f.parent)
385 {
386 if (auto ti = f.parent.isTemplateInstance())
387 {
388 if (!ti.isTemplateMixin() && ti.tempdecl)
389 {
390 auto td = ti.tempdecl.isTemplateDeclaration();
391 if (td.onemember && td.ident == f.ident)
392 {
393 return td;
394 }
395 }
396 }
397 }
398 return null;
399 }
400
401 /************************************************
402 * If we want the value of this expression, but do not want to call
403 * the destructor on it.
404 */
valueNoDtor(Expression e)405 Expression valueNoDtor(Expression e)
406 {
407 auto ex = lastComma(e);
408
409 if (auto ce = ex.isCallExp())
410 {
411 /* The struct value returned from the function is transferred
412 * so do not call the destructor on it.
413 * Recognize:
414 * ((S _ctmp = S.init), _ctmp).this(...)
415 * and make sure the destructor is not called on _ctmp
416 * BUG: if ex is a CommaExp, we should go down the right side.
417 */
418 if (auto dve = ce.e1.isDotVarExp())
419 {
420 if (dve.var.isCtorDeclaration())
421 {
422 // It's a constructor call
423 if (auto comma = dve.e1.isCommaExp())
424 {
425 if (auto ve = comma.e2.isVarExp())
426 {
427 VarDeclaration ctmp = ve.var.isVarDeclaration();
428 if (ctmp)
429 {
430 ctmp.storage_class |= STC.nodtor;
431 assert(!ce.isLvalue());
432 }
433 }
434 }
435 }
436 }
437 }
438 else if (auto ve = ex.isVarExp())
439 {
440 auto vtmp = ve.var.isVarDeclaration();
441 if (vtmp && (vtmp.storage_class & STC.rvalue))
442 {
443 vtmp.storage_class |= STC.nodtor;
444 }
445 }
446 return e;
447 }
448
449 /*********************************************
450 * If e is an instance of a struct, and that struct has a copy constructor,
451 * rewrite e as:
452 * (tmp = e),tmp
453 * Input:
454 * sc = just used to specify the scope of created temporary variable
455 * destinationType = the type of the object on which the copy constructor is called;
456 * may be null if the struct defines a postblit
457 */
callCpCtor(Scope * sc,Expression e,Type destinationType)458 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
459 {
460 if (auto ts = e.type.baseElemOf().isTypeStruct())
461 {
462 StructDeclaration sd = ts.sym;
463 if (sd.postblit || sd.hasCopyCtor)
464 {
465 /* Create a variable tmp, and replace the argument e with:
466 * (tmp = e),tmp
467 * and let AssignExp() handle the construction.
468 * This is not the most efficient, ideally tmp would be constructed
469 * directly onto the stack.
470 */
471 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
472 if (sd.hasCopyCtor && destinationType)
473 {
474 // https://issues.dlang.org/show_bug.cgi?id=22619
475 // If the destination type is inout we can preserve it
476 // only if inside an inout function; if we are not inside
477 // an inout function, then we will preserve the type of
478 // the source
479 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
480 tmp.type = e.type;
481 else
482 tmp.type = destinationType;
483 }
484 tmp.storage_class |= STC.nodtor;
485 tmp.dsymbolSemantic(sc);
486 Expression de = new DeclarationExp(e.loc, tmp);
487 Expression ve = new VarExp(e.loc, tmp);
488 de.type = Type.tvoid;
489 ve.type = e.type;
490 return Expression.combine(de, ve);
491 }
492 }
493 return e;
494 }
495
496 /************************************************
497 * Handle the postblit call on lvalue, or the move of rvalue.
498 *
499 * Params:
500 * sc = the scope where the expression is encountered
501 * e = the expression the needs to be moved or copied (source)
502 * t = if the struct defines a copy constructor, the type of the destination
503 *
504 * Returns:
505 * The expression that copy constructs or moves the value.
506 */
507 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
508 {
509 if (auto ce = e.isCondExp())
510 {
511 ce.e1 = doCopyOrMove(sc, ce.e1);
512 ce.e2 = doCopyOrMove(sc, ce.e2);
513 }
514 else
515 {
516 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
517 }
518 return e;
519 }
520
521 /****************************************************************/
522 /* A type meant as a union of all the Expression types,
523 * to serve essentially as a Variant that will sit on the stack
524 * during CTFE to reduce memory consumption.
525 */
526 extern (C++) struct UnionExp
527 {
528 // yes, default constructor does nothing
thisUnionExp529 extern (D) this(Expression e)
530 {
531 memcpy(&this, cast(void*)e, e.size);
532 }
533
534 /* Extract pointer to Expression
535 */
536 extern (C++) Expression exp() return
537 {
538 return cast(Expression)&u;
539 }
540
541 /* Convert to an allocated Expression
542 */
543 extern (C++) Expression copy()
544 {
545 Expression e = exp();
546 //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr);
547 assert(e.size <= u.sizeof);
548 switch (e.op)
549 {
550 case EXP.cantExpression: return CTFEExp.cantexp;
551 case EXP.voidExpression: return CTFEExp.voidexp;
552 case EXP.break_: return CTFEExp.breakexp;
553 case EXP.continue_: return CTFEExp.continueexp;
554 case EXP.goto_: return CTFEExp.gotoexp;
555 default: return e.copy();
556 }
557 }
558
559 private:
560 // Ensure that the union is suitably aligned.
561 align(8) union __AnonStruct__u
562 {
563 char[__traits(classInstanceSize, Expression)] exp;
564 char[__traits(classInstanceSize, IntegerExp)] integerexp;
565 char[__traits(classInstanceSize, ErrorExp)] errorexp;
566 char[__traits(classInstanceSize, RealExp)] realexp;
567 char[__traits(classInstanceSize, ComplexExp)] complexexp;
568 char[__traits(classInstanceSize, SymOffExp)] symoffexp;
569 char[__traits(classInstanceSize, StringExp)] stringexp;
570 char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
571 char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
572 char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
573 char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp;
574 char[__traits(classInstanceSize, NullExp)] nullexp;
575 char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
576 char[__traits(classInstanceSize, AddrExp)] addrexp;
577 char[__traits(classInstanceSize, IndexExp)] indexexp;
578 char[__traits(classInstanceSize, SliceExp)] sliceexp;
579 char[__traits(classInstanceSize, VectorExp)] vectorexp;
580 }
581
582 __AnonStruct__u u;
583 }
584
585 /********************************
586 * Test to see if two reals are the same.
587 * Regard NaN's as equivalent.
588 * Regard +0 and -0 as different.
589 * Params:
590 * x1 = first operand
591 * x2 = second operand
592 * Returns:
593 * true if x1 is x2
594 * else false
595 */
RealIdentical(real_t x1,real_t x2)596 bool RealIdentical(real_t x1, real_t x2)
597 {
598 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
599 }
600
601 /************************ TypeDotIdExp ************************************/
602 /* Things like:
603 * int.size
604 * foo.size
605 * (foo).size
606 * cast(foo).size
607 */
typeDotIdExp(const ref Loc loc,Type type,Identifier ident)608 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident)
609 {
610 return new DotIdExp(loc, new TypeExp(loc, type), ident);
611 }
612
613 /***************************************************
614 * Given an Expression, find the variable it really is.
615 *
616 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
617 * Params:
618 * e = Expression to look at
619 * Returns:
620 * variable if there is one, null if not
621 */
expToVariable(Expression e)622 VarDeclaration expToVariable(Expression e)
623 {
624 while (1)
625 {
626 switch (e.op)
627 {
628 case EXP.variable:
629 return (cast(VarExp)e).var.isVarDeclaration();
630
631 case EXP.dotVariable:
632 e = (cast(DotVarExp)e).e1;
633 continue;
634
635 case EXP.index:
636 {
637 IndexExp ei = cast(IndexExp)e;
638 e = ei.e1;
639 Type ti = e.type.toBasetype();
640 if (ti.ty == Tsarray)
641 continue;
642 return null;
643 }
644
645 case EXP.slice:
646 {
647 SliceExp ei = cast(SliceExp)e;
648 e = ei.e1;
649 Type ti = e.type.toBasetype();
650 if (ti.ty == Tsarray)
651 continue;
652 return null;
653 }
654
655 case EXP.this_:
656 case EXP.super_:
657 return (cast(ThisExp)e).var.isVarDeclaration();
658
659 default:
660 return null;
661 }
662 }
663 }
664
665 enum OwnedBy : ubyte
666 {
667 code, // normal code expression in AST
668 ctfe, // value expression for CTFE
669 cache, // constant value cached for CTFE
670 }
671
672 enum WANTvalue = 0; // default
673 enum WANTexpand = 1; // expand const/immutable variables if possible
674
675 /***********************************************************
676 * https://dlang.org/spec/expression.html#expression
677 */
678 extern (C++) abstract class Expression : ASTNode
679 {
680 const EXP op; // to minimize use of dynamic_cast
681 ubyte size; // # of bytes in Expression so we can copy() it
682 ubyte parens; // if this is a parenthesized expression
683 Type type; // !=null means that semantic() has been run
684 Loc loc; // file location
685
this(const ref Loc loc,EXP op,int size)686 extern (D) this(const ref Loc loc, EXP op, int size)
687 {
688 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
689 this.loc = loc;
690 this.op = op;
691 this.size = cast(ubyte)size;
692 }
693
_init()694 static void _init()
695 {
696 CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
697 CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
698 CTFEExp.breakexp = new CTFEExp(EXP.break_);
699 CTFEExp.continueexp = new CTFEExp(EXP.continue_);
700 CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
701 CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
702 }
703
704 /**
705 * Deinitializes the global state of the compiler.
706 *
707 * This can be used to restore the state set by `_init` to its original
708 * state.
709 */
deinitialize()710 static void deinitialize()
711 {
712 CTFEExp.cantexp = CTFEExp.cantexp.init;
713 CTFEExp.voidexp = CTFEExp.voidexp.init;
714 CTFEExp.breakexp = CTFEExp.breakexp.init;
715 CTFEExp.continueexp = CTFEExp.continueexp.init;
716 CTFEExp.gotoexp = CTFEExp.gotoexp.init;
717 CTFEExp.showcontext = CTFEExp.showcontext.init;
718 }
719
720 /*********************************
721 * Does *not* do a deep copy.
722 */
copy()723 final Expression copy()
724 {
725 Expression e;
726 if (!size)
727 {
728 debug
729 {
730 fprintf(stderr, "No expression copy for: %s\n", toChars());
731 printf("op = %d\n", op);
732 }
733 assert(0);
734 }
735
736 // memory never freed, so can use the faster bump-pointer-allocation
737 e = cast(Expression)allocmemory(size);
738 //printf("Expression::copy(op = %d) e = %p\n", op, e);
739 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
740 }
741
syntaxCopy()742 Expression syntaxCopy()
743 {
744 //printf("Expression::syntaxCopy()\n");
745 //print();
746 return copy();
747 }
748
749 // kludge for template.isExpression()
dyncast()750 override final DYNCAST dyncast() const
751 {
752 return DYNCAST.expression;
753 }
754
toChars()755 override const(char)* toChars() const
756 {
757 OutBuffer buf;
758 HdrGenState hgs;
759 toCBuffer(this, &buf, &hgs);
760 return buf.extractChars();
761 }
762
763 static if (__VERSION__ < 2092)
764 {
error(const (char)* format,...)765 final void error(const(char)* format, ...) const
766 {
767 if (type != Type.terror)
768 {
769 va_list ap;
770 va_start(ap, format);
771 .verror(loc, format, ap);
772 va_end(ap);
773 }
774 }
775
errorSupplemental(const (char)* format,...)776 final void errorSupplemental(const(char)* format, ...)
777 {
778 if (type == Type.terror)
779 return;
780
781 va_list ap;
782 va_start(ap, format);
783 .verrorSupplemental(loc, format, ap);
784 va_end(ap);
785 }
786
warning(const (char)* format,...)787 final void warning(const(char)* format, ...) const
788 {
789 if (type != Type.terror)
790 {
791 va_list ap;
792 va_start(ap, format);
793 .vwarning(loc, format, ap);
794 va_end(ap);
795 }
796 }
797
deprecation(const (char)* format,...)798 final void deprecation(const(char)* format, ...) const
799 {
800 if (type != Type.terror)
801 {
802 va_list ap;
803 va_start(ap, format);
804 .vdeprecation(loc, format, ap);
805 va_end(ap);
806 }
807 }
808 }
809 else
810 {
pragma(printf)811 pragma(printf) final void error(const(char)* format, ...) const
812 {
813 if (type != Type.terror)
814 {
815 va_list ap;
816 va_start(ap, format);
817 .verror(loc, format, ap);
818 va_end(ap);
819 }
820 }
821
pragma(printf)822 pragma(printf) final void errorSupplemental(const(char)* format, ...)
823 {
824 if (type == Type.terror)
825 return;
826
827 va_list ap;
828 va_start(ap, format);
829 .verrorSupplemental(loc, format, ap);
830 va_end(ap);
831 }
832
pragma(printf)833 pragma(printf) final void warning(const(char)* format, ...) const
834 {
835 if (type != Type.terror)
836 {
837 va_list ap;
838 va_start(ap, format);
839 .vwarning(loc, format, ap);
840 va_end(ap);
841 }
842 }
843
pragma(printf)844 pragma(printf) final void deprecation(const(char)* format, ...) const
845 {
846 if (type != Type.terror)
847 {
848 va_list ap;
849 va_start(ap, format);
850 .vdeprecation(loc, format, ap);
851 va_end(ap);
852 }
853 }
854 }
855
856 /**********************************
857 * Combine e1 and e2 by CommaExp if both are not NULL.
858 */
combine(Expression e1,Expression e2)859 extern (D) static Expression combine(Expression e1, Expression e2)
860 {
861 if (e1)
862 {
863 if (e2)
864 {
865 e1 = new CommaExp(e1.loc, e1, e2);
866 e1.type = e2.type;
867 }
868 }
869 else
870 e1 = e2;
871 return e1;
872 }
873
combine(Expression e1,Expression e2,Expression e3)874 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3)
875 {
876 return combine(combine(e1, e2), e3);
877 }
878
combine(Expression e1,Expression e2,Expression e3,Expression e4)879 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4)
880 {
881 return combine(combine(e1, e2), combine(e3, e4));
882 }
883
884 /**********************************
885 * If 'e' is a tree of commas, returns the rightmost expression
886 * by stripping off it from the tree. The remained part of the tree
887 * is returned via e0.
888 * Otherwise 'e' is directly returned and e0 is set to NULL.
889 */
extractLast(Expression e,out Expression e0)890 extern (D) static Expression extractLast(Expression e, out Expression e0)
891 {
892 if (e.op != EXP.comma)
893 {
894 return e;
895 }
896
897 CommaExp ce = cast(CommaExp)e;
898 if (ce.e2.op != EXP.comma)
899 {
900 e0 = ce.e1;
901 return ce.e2;
902 }
903 else
904 {
905 e0 = e;
906
907 Expression* pce = &ce.e2;
908 while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
909 {
910 pce = &(cast(CommaExp)(*pce)).e2;
911 }
912 assert((*pce).op == EXP.comma);
913 ce = cast(CommaExp)(*pce);
914 *pce = ce.e1;
915
916 return ce.e2;
917 }
918 }
919
arraySyntaxCopy(Expressions * exps)920 extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
921 {
922 Expressions* a = null;
923 if (exps)
924 {
925 a = new Expressions(exps.dim);
926 foreach (i, e; *exps)
927 {
928 (*a)[i] = e ? e.syntaxCopy() : null;
929 }
930 }
931 return a;
932 }
933
toInteger()934 dinteger_t toInteger()
935 {
936 //printf("Expression %s\n", EXPtoString(op).ptr);
937 error("integer constant expression expected instead of `%s`", toChars());
938 return 0;
939 }
940
toUInteger()941 uinteger_t toUInteger()
942 {
943 //printf("Expression %s\n", EXPtoString(op).ptr);
944 return cast(uinteger_t)toInteger();
945 }
946
toReal()947 real_t toReal()
948 {
949 error("floating point constant expression expected instead of `%s`", toChars());
950 return CTFloat.zero;
951 }
952
toImaginary()953 real_t toImaginary()
954 {
955 error("floating point constant expression expected instead of `%s`", toChars());
956 return CTFloat.zero;
957 }
958
toComplex()959 complex_t toComplex()
960 {
961 error("floating point constant expression expected instead of `%s`", toChars());
962 return complex_t(CTFloat.zero);
963 }
964
toStringExp()965 StringExp toStringExp()
966 {
967 return null;
968 }
969
970 /***************************************
971 * Return !=0 if expression is an lvalue.
972 */
isLvalue()973 bool isLvalue()
974 {
975 return false;
976 }
977
978 /*******************************
979 * Give error if we're not an lvalue.
980 * If we can, convert expression to be an lvalue.
981 */
toLvalue(Scope * sc,Expression e)982 Expression toLvalue(Scope* sc, Expression e)
983 {
984 if (!e)
985 e = this;
986 else if (!loc.isValid())
987 loc = e.loc;
988
989 if (e.op == EXP.type)
990 error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
991 else
992 error("`%s` is not an lvalue and cannot be modified", e.toChars());
993
994 return ErrorExp.get();
995 }
996
modifiableLvalue(Scope * sc,Expression e)997 Expression modifiableLvalue(Scope* sc, Expression e)
998 {
999 //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars());
1000 // See if this expression is a modifiable lvalue (i.e. not const)
1001 if (checkModifiable(this, sc) == Modifiable.yes)
1002 {
1003 assert(type);
1004 if (!type.isMutable())
1005 {
1006 if (auto dve = this.isDotVarExp())
1007 {
1008 if (isNeedThisScope(sc, dve.var))
1009 for (Dsymbol s = sc.func; s; s = s.toParentLocal())
1010 {
1011 FuncDeclaration ff = s.isFuncDeclaration();
1012 if (!ff)
1013 break;
1014 if (!ff.type.isMutable)
1015 {
1016 error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod));
1017 return ErrorExp.get();
1018 }
1019 }
1020 }
1021 error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars());
1022 return ErrorExp.get();
1023 }
1024 else if (!type.isAssignable())
1025 {
1026 error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
1027 toChars(), type.toChars());
1028 return ErrorExp.get();
1029 }
1030 }
1031 return toLvalue(sc, e);
1032 }
1033
implicitCastTo(Scope * sc,Type t)1034 final Expression implicitCastTo(Scope* sc, Type t)
1035 {
1036 return .implicitCastTo(this, sc, t);
1037 }
1038
implicitConvTo(Type t)1039 final MATCH implicitConvTo(Type t)
1040 {
1041 return .implicitConvTo(this, t);
1042 }
1043
castTo(Scope * sc,Type t)1044 final Expression castTo(Scope* sc, Type t)
1045 {
1046 return .castTo(this, sc, t);
1047 }
1048
1049 /****************************************
1050 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
1051 */
resolveLoc(const ref Loc loc,Scope * sc)1052 Expression resolveLoc(const ref Loc loc, Scope* sc)
1053 {
1054 this.loc = loc;
1055 return this;
1056 }
1057
1058 /****************************************
1059 * Check that the expression has a valid type.
1060 * If not, generates an error "... has no type".
1061 * Returns:
1062 * true if the expression is not valid.
1063 * Note:
1064 * When this function returns true, `checkValue()` should also return true.
1065 */
checkType()1066 bool checkType()
1067 {
1068 return false;
1069 }
1070
1071 /****************************************
1072 * Check that the expression has a valid value.
1073 * If not, generates an error "... has no value".
1074 * Returns:
1075 * true if the expression is not valid or has void type.
1076 */
checkValue()1077 bool checkValue()
1078 {
1079 if (type && type.toBasetype().ty == Tvoid)
1080 {
1081 error("expression `%s` is `void` and has no value", toChars());
1082 //print(); assert(0);
1083 if (!global.gag)
1084 type = Type.terror;
1085 return true;
1086 }
1087 return false;
1088 }
1089
checkScalar()1090 extern (D) final bool checkScalar()
1091 {
1092 if (op == EXP.error)
1093 return true;
1094 if (type.toBasetype().ty == Terror)
1095 return true;
1096 if (!type.isscalar())
1097 {
1098 error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
1099 return true;
1100 }
1101 return checkValue();
1102 }
1103
checkNoBool()1104 extern (D) final bool checkNoBool()
1105 {
1106 if (op == EXP.error)
1107 return true;
1108 if (type.toBasetype().ty == Terror)
1109 return true;
1110 if (type.toBasetype().ty == Tbool)
1111 {
1112 error("operation not allowed on `bool` `%s`", toChars());
1113 return true;
1114 }
1115 return false;
1116 }
1117
checkIntegral()1118 extern (D) final bool checkIntegral()
1119 {
1120 if (op == EXP.error)
1121 return true;
1122 if (type.toBasetype().ty == Terror)
1123 return true;
1124 if (!type.isintegral())
1125 {
1126 error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
1127 return true;
1128 }
1129 return checkValue();
1130 }
1131
checkArithmetic()1132 extern (D) final bool checkArithmetic()
1133 {
1134 if (op == EXP.error)
1135 return true;
1136 if (type.toBasetype().ty == Terror)
1137 return true;
1138 if (!type.isintegral() && !type.isfloating())
1139 {
1140 error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars());
1141 return true;
1142 }
1143 return checkValue();
1144 }
1145
checkDeprecated(Scope * sc,Dsymbol s)1146 final bool checkDeprecated(Scope* sc, Dsymbol s)
1147 {
1148 return s.checkDeprecated(loc, sc);
1149 }
1150
checkDisabled(Scope * sc,Dsymbol s)1151 extern (D) final bool checkDisabled(Scope* sc, Dsymbol s)
1152 {
1153 if (auto d = s.isDeclaration())
1154 {
1155 return d.checkDisabled(loc, sc);
1156 }
1157
1158 return false;
1159 }
1160
1161 /*********************************************
1162 * Calling function f.
1163 * Check the purity, i.e. if we're in a pure function
1164 * we can only call other pure functions.
1165 * Returns true if error occurs.
1166 */
checkPurity(Scope * sc,FuncDeclaration f)1167 extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f)
1168 {
1169 if (!sc.func)
1170 return false;
1171 if (sc.func == f)
1172 return false;
1173 if (sc.intypeof == 1)
1174 return false;
1175 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1176 return false;
1177
1178 // If the call has a pure parent, then the called func must be pure.
1179 if (!f.isPure() && checkImpure(sc))
1180 {
1181 error("`pure` %s `%s` cannot call impure %s `%s`",
1182 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1183 f.toPrettyChars());
1184
1185 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
1186 return true;
1187 }
1188 return false;
1189 }
1190
1191 /**
1192 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1193 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1194 * the generated dtor is not).
1195 * In that case the method will identify and print all members causing the attribute
1196 * missmatch.
1197 *
1198 * Params:
1199 * sc = scope
1200 * f = potential `DtorDeclaration`
1201 * check = current check (e.g. whether it's pure)
1202 * checkName = the kind of check (e.g. `"pure"`)
1203 */
checkOverridenDtor(Scope * sc,FuncDeclaration f,scope bool function (DtorDeclaration)check,const string checkName)1204 extern (D) final void checkOverridenDtor(Scope* sc, FuncDeclaration f,
1205 scope bool function(DtorDeclaration) check, const string checkName
1206 ) {
1207 auto dd = f.isDtorDeclaration();
1208 if (!dd || !dd.isGenerated())
1209 return;
1210
1211 // DtorDeclaration without parents should fail at an earlier stage
1212 auto ad = cast(AggregateDeclaration) f.toParent2();
1213 assert(ad);
1214
1215 if (ad.userDtors.dim)
1216 {
1217 if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
1218 return;
1219
1220 // Sanity check
1221 assert(!check(ad.fieldDtor));
1222 }
1223
1224 dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1225 dd.isGenerated() ? "generated " : "".ptr,
1226 ad.toChars,
1227 cast(int) checkName.length, checkName.ptr);
1228
1229 // Search for the offending fields
1230 foreach (field; ad.fields)
1231 {
1232 // Only structs may define automatically called destructors
1233 auto ts = field.type.isTypeStruct();
1234 if (!ts)
1235 {
1236 // But they might be part of a static array
1237 auto ta = field.type.isTypeSArray();
1238 if (!ta)
1239 continue;
1240
1241 ts = ta.baseElemOf().isTypeStruct();
1242 if (!ts)
1243 continue;
1244 }
1245
1246 auto fieldSym = ts.toDsymbol(sc);
1247 assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
1248
1249 auto fieldSd = fieldSym.isStructDeclaration();
1250 assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
1251
1252 if (fieldSd.dtor && !check(fieldSd.dtor))
1253 {
1254 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
1255
1256 if (fieldSd.dtor.isGenerated())
1257 checkOverridenDtor(sc, fieldSd.dtor, check, checkName);
1258 else
1259 fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
1260 cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
1261 }
1262 }
1263 }
1264
1265 /*******************************************
1266 * Accessing variable v.
1267 * Check for purity and safety violations.
1268 * Returns true if error occurs.
1269 */
checkPurity(Scope * sc,VarDeclaration v)1270 extern (D) final bool checkPurity(Scope* sc, VarDeclaration v)
1271 {
1272 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1273 /* Look for purity and safety violations when accessing variable v
1274 * from current function.
1275 */
1276 if (!sc.func)
1277 return false;
1278 if (sc.intypeof == 1)
1279 return false; // allow violations inside typeof(expression)
1280 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1281 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1282 if (v.ident == Id.ctfe)
1283 return false; // magic variable never violates pure and safe
1284 if (v.isImmutable())
1285 return false; // always safe and pure to access immutables...
1286 if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
1287 return false; // or const global/parameter values which have no mutable indirections
1288 if (v.storage_class & STC.manifest)
1289 return false; // ...or manifest constants
1290
1291 // accessing empty structs is pure
1292 if (v.type.ty == Tstruct)
1293 {
1294 StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1295 if (sd.members) // not opaque
1296 {
1297 sd.determineSize(v.loc);
1298 if (sd.hasNoFields)
1299 return false;
1300 }
1301 }
1302
1303 bool err = false;
1304 if (v.isDataseg())
1305 {
1306 // https://issues.dlang.org/show_bug.cgi?id=7533
1307 // Accessing implicit generated __gate is pure.
1308 if (v.ident == Id.gate)
1309 return false;
1310
1311 if (checkImpure(sc))
1312 {
1313 error("`pure` %s `%s` cannot access mutable static data `%s`",
1314 sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
1315 err = true;
1316 }
1317 }
1318 else
1319 {
1320 /* Given:
1321 * void f() {
1322 * int fx;
1323 * pure void g() {
1324 * int gx;
1325 * /+pure+/ void h() {
1326 * int hx;
1327 * /+pure+/ void i() { }
1328 * }
1329 * }
1330 * }
1331 * i() can modify hx and gx but not fx
1332 */
1333
1334 Dsymbol vparent = v.toParent2();
1335 for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
1336 {
1337 if (s == vparent)
1338 break;
1339
1340 if (AggregateDeclaration ad = s.isAggregateDeclaration())
1341 {
1342 if (ad.isNested())
1343 continue;
1344 break;
1345 }
1346 FuncDeclaration ff = s.isFuncDeclaration();
1347 if (!ff)
1348 break;
1349 if (ff.isNested() || ff.isThis())
1350 {
1351 if (ff.type.isImmutable() ||
1352 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
1353 {
1354 OutBuffer ffbuf;
1355 OutBuffer vbuf;
1356 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
1357 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
1358 error("%s%s `%s` cannot access %sdata `%s`",
1359 ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
1360 err = true;
1361 break;
1362 }
1363 continue;
1364 }
1365 break;
1366 }
1367 }
1368
1369 /* Do not allow safe functions to access __gshared data
1370 */
1371 if (v.storage_class & STC.gshared)
1372 {
1373 if (sc.func.setUnsafe())
1374 {
1375 error("`@safe` %s `%s` cannot access `__gshared` data `%s`",
1376 sc.func.kind(), sc.func.toChars(), v.toChars());
1377 err = true;
1378 }
1379 }
1380
1381 return err;
1382 }
1383
1384 /*
1385 Check if sc.func is impure or can be made impure.
1386 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
1387 */
checkImpure(Scope * sc)1388 private static bool checkImpure(Scope* sc)
1389 {
1390 return sc.func && (sc.flags & SCOPE.compile
1391 ? sc.func.isPureBypassingInference() >= PURE.weak
1392 : sc.func.setImpure());
1393 }
1394
1395 /*********************************************
1396 * Calling function f.
1397 * Check the safety, i.e. if we're in a @safe function
1398 * we can only call @safe or @trusted functions.
1399 * Returns true if error occurs.
1400 */
checkSafety(Scope * sc,FuncDeclaration f)1401 extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f)
1402 {
1403 if (!sc.func)
1404 return false;
1405 if (sc.func == f)
1406 return false;
1407 if (sc.intypeof == 1)
1408 return false;
1409 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1410 return false;
1411
1412 if (!f.isSafe() && !f.isTrusted())
1413 {
1414 if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe())
1415 {
1416 if (!loc.isValid()) // e.g. implicitly generated dtor
1417 loc = sc.func.loc;
1418
1419 const prettyChars = f.toPrettyChars();
1420 error("`@safe` %s `%s` cannot call `@system` %s `%s`",
1421 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1422 prettyChars);
1423 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
1424
1425 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
1426
1427 return true;
1428 }
1429 }
1430 return false;
1431 }
1432
1433 /*********************************************
1434 * Calling function f.
1435 * Check the @nogc-ness, i.e. if we're in a @nogc function
1436 * we can only call other @nogc functions.
1437 * Returns true if error occurs.
1438 */
checkNogc(Scope * sc,FuncDeclaration f)1439 extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f)
1440 {
1441 if (!sc.func)
1442 return false;
1443 if (sc.func == f)
1444 return false;
1445 if (sc.intypeof == 1)
1446 return false;
1447 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1448 return false;
1449
1450 if (!f.isNogc())
1451 {
1452 if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC())
1453 {
1454 if (loc.linnum == 0) // e.g. implicitly generated dtor
1455 loc = sc.func.loc;
1456
1457 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
1458 // so don't print anything to avoid double error messages.
1459 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT))
1460 error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
1461 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
1462
1463 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
1464
1465 return true;
1466 }
1467 }
1468 return false;
1469 }
1470
1471 /********************************************
1472 * Check that the postblit is callable if t is an array of structs.
1473 * Returns true if error happens.
1474 */
checkPostblit(Scope * sc,Type t)1475 extern (D) final bool checkPostblit(Scope* sc, Type t)
1476 {
1477 if (auto ts = t.baseElemOf().isTypeStruct())
1478 {
1479 if (global.params.useTypeInfo && Type.dtypeinfo)
1480 {
1481 // https://issues.dlang.org/show_bug.cgi?id=11395
1482 // Require TypeInfo generation for array concatenation
1483 semanticTypeInfo(sc, t);
1484 }
1485
1486 StructDeclaration sd = ts.sym;
1487 if (sd.postblit)
1488 {
1489 if (sd.postblit.checkDisabled(loc, sc))
1490 return true;
1491
1492 //checkDeprecated(sc, sd.postblit); // necessary?
1493 checkPurity(sc, sd.postblit);
1494 checkSafety(sc, sd.postblit);
1495 checkNogc(sc, sd.postblit);
1496 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
1497 return false;
1498 }
1499 }
1500 return false;
1501 }
1502
checkRightThis(Scope * sc)1503 extern (D) final bool checkRightThis(Scope* sc)
1504 {
1505 if (op == EXP.error)
1506 return true;
1507 if (op == EXP.variable && type.ty != Terror)
1508 {
1509 VarExp ve = cast(VarExp)this;
1510 if (isNeedThisScope(sc, ve.var))
1511 {
1512 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
1513 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
1514 error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars());
1515 return true;
1516 }
1517 }
1518 return false;
1519 }
1520
1521 /*******************************
1522 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
1523 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
1524 * Returns true if error occurs.
1525 */
1526 extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
1527 {
1528 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
1529 if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
1530 return false;
1531
1532 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
1533 switch (rmwOp)
1534 {
1535 case EXP.plusPlus:
1536 case EXP.prePlusPlus:
1537 rmwOp = EXP.addAssign;
1538 break;
1539 case EXP.minusMinus:
1540 case EXP.preMinusMinus:
1541 rmwOp = EXP.minAssign;
1542 break;
1543 default:
1544 break;
1545 }
1546
1547 error("read-modify-write operations are not allowed for `shared` variables");
1548 errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
1549 EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
1550 return true;
1551 }
1552
1553 /************************************************
1554 * Destructors are attached to VarDeclarations.
1555 * Hence, if expression returns a temp that needs a destructor,
1556 * make sure and create a VarDeclaration for that temp.
1557 */
addDtorHook(Scope * sc)1558 Expression addDtorHook(Scope* sc)
1559 {
1560 return this;
1561 }
1562
1563 /******************************
1564 * Take address of expression.
1565 */
addressOf()1566 final Expression addressOf()
1567 {
1568 //printf("Expression::addressOf()\n");
1569 debug
1570 {
1571 assert(op == EXP.error || isLvalue());
1572 }
1573 Expression e = new AddrExp(loc, this, type.pointerTo());
1574 return e;
1575 }
1576
1577 /******************************
1578 * If this is a reference, dereference it.
1579 */
deref()1580 final Expression deref()
1581 {
1582 //printf("Expression::deref()\n");
1583 // type could be null if forward referencing an 'auto' variable
1584 if (type)
1585 if (auto tr = type.isTypeReference())
1586 {
1587 Expression e = new PtrExp(loc, this, tr.next);
1588 return e;
1589 }
1590 return this;
1591 }
1592
1593 final Expression optimize(int result, bool keepLvalue = false)
1594 {
1595 return Expression_optimize(this, result, keepLvalue);
1596 }
1597
1598 // Entry point for CTFE.
1599 // A compile-time result is required. Give an error if not possible
ctfeInterpret()1600 final Expression ctfeInterpret()
1601 {
1602 return .ctfeInterpret(this);
1603 }
1604
isConst()1605 final int isConst()
1606 {
1607 return .isConst(this);
1608 }
1609
1610 /// Statically evaluate this expression to a `bool` if possible
1611 /// Returns: an optional thath either contains the value or is empty
1612 Optional!bool toBool()
1613 {
1614 return typeof(return)();
1615 }
1616
hasCode()1617 bool hasCode()
1618 {
1619 return true;
1620 }
1621
1622 final pure inout nothrow @nogc @safe
1623 {
isIntegerExp()1624 inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
isErrorExp()1625 inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
isVoidInitExp()1626 inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
isRealExp()1627 inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
isComplexExp()1628 inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
isIdentifierExp()1629 inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
isDollarExp()1630 inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
isDsymbolExp()1631 inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
isThisExp()1632 inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
isSuperExp()1633 inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
isNullExp()1634 inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
isStringExp()1635 inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
isTupleExp()1636 inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
isArrayLiteralExp()1637 inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
isAssocArrayLiteralExp()1638 inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
isStructLiteralExp()1639 inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
isCompoundLiteralExp()1640 inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
isTypeExp()1641 inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
isScopeExp()1642 inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
isTemplateExp()1643 inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
isNewExp()1644 inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
isNewAnonClassExp()1645 inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
isSymOffExp()1646 inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
isVarExp()1647 inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
isOverExp()1648 inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
isFuncExp()1649 inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
isDeclarationExp()1650 inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
isTypeidExp()1651 inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
isTraitsExp()1652 inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
isHaltExp()1653 inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
isExp()1654 inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
isMixinExp()1655 inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
isImportExp()1656 inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
isAssertExp()1657 inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
isThrowExp()1658 inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
isDotIdExp()1659 inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
isDotTemplateExp()1660 inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
isDotVarExp()1661 inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
isDotTemplateInstanceExp()1662 inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
isDelegateExp()1663 inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
isDotTypeExp()1664 inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
isCallExp()1665 inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
isAddrExp()1666 inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
isPtrExp()1667 inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
isNegExp()1668 inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
isUAddExp()1669 inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
isComExp()1670 inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
isNotExp()1671 inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
isDeleteExp()1672 inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
isCastExp()1673 inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
isVectorExp()1674 inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
isVectorArrayExp()1675 inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
isSliceExp()1676 inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
isArrayLengthExp()1677 inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
isArrayExp()1678 inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
isDotExp()1679 inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
isCommaExp()1680 inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
isIntervalExp()1681 inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
isDelegatePtrExp()1682 inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
isDelegateFuncptrExp()1683 inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
isIndexExp()1684 inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
isPostExp()1685 inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
isPreExp()1686 inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
isAssignExp()1687 inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
isConstructExp()1688 inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
isBlitExp()1689 inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
isAddAssignExp()1690 inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
isMinAssignExp()1691 inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
isMulAssignExp()1692 inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
1693
isDivAssignExp()1694 inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
isModAssignExp()1695 inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
isAndAssignExp()1696 inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
isOrAssignExp()1697 inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; }
isXorAssignExp()1698 inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
isPowAssignExp()1699 inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
1700
isShlAssignExp()1701 inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
isShrAssignExp()1702 inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
isUshrAssignExp()1703 inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
1704
isCatAssignExp()1705 inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
1706 ? cast(typeof(return))this
1707 : null; }
1708
isCatElemAssignExp()1709 inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
1710 ? cast(typeof(return))this
1711 : null; }
1712
isCatDcharAssignExp()1713 inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
1714 ? cast(typeof(return))this
1715 : null; }
1716
isAddExp()1717 inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
isMinExp()1718 inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
isCatExp()1719 inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
isMulExp()1720 inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
isDivExp()1721 inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
isModExp()1722 inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
isPowExp()1723 inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
isShlExp()1724 inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
isShrExp()1725 inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
isUshrExp()1726 inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
isAndExp()1727 inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
isOrExp()1728 inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
isXorExp()1729 inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
isLogicalExp()1730 inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
1731 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
isInExp()1732 inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
isRemoveExp()1733 inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
isEqualExp()1734 inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
isIdentityExp()1735 inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
isCondExp()1736 inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
isGenericExp()1737 inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
isDefaultInitExp()1738 inout(DefaultInitExp) isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
isFileInitExp()1739 inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
isLineInitExp()1740 inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
isModuleInitExp()1741 inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
isFuncInitExp()1742 inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
isPrettyFuncInitExp()1743 inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
isObjcClassReferenceExp()1744 inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
isClassReferenceExp()1745 inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
isThrownExceptionExp()1746 inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
1747
isUnaExp()1748 inout(UnaExp) isUnaExp() pure inout nothrow @nogc
1749 {
1750 return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
1751 }
1752
isBinExp()1753 inout(BinExp) isBinExp() pure inout nothrow @nogc
1754 {
1755 return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
1756 }
1757
isBinAssignExp()1758 inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
1759 {
1760 return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
1761 }
1762 }
1763
accept(Visitor v)1764 override void accept(Visitor v)
1765 {
1766 v.visit(this);
1767 }
1768 }
1769
1770 /***********************************************************
1771 * A compile-time known integer value
1772 */
1773 extern (C++) final class IntegerExp : Expression
1774 {
1775 private dinteger_t value;
1776
this(const ref Loc loc,dinteger_t value,Type type)1777 extern (D) this(const ref Loc loc, dinteger_t value, Type type)
1778 {
1779 super(loc, EXP.int64, __traits(classInstanceSize, IntegerExp));
1780 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
1781 assert(type);
1782 if (!type.isscalar())
1783 {
1784 //printf("%s, loc = %d\n", toChars(), loc.linnum);
1785 if (type.ty != Terror)
1786 error("integral constant must be scalar type, not `%s`", type.toChars());
1787 type = Type.terror;
1788 }
1789 this.type = type;
1790 this.value = normalize(type.toBasetype().ty, value);
1791 }
1792
this(dinteger_t value)1793 extern (D) this(dinteger_t value)
1794 {
1795 super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp));
1796 this.type = Type.tint32;
1797 this.value = cast(int)value;
1798 }
1799
create(const ref Loc loc,dinteger_t value,Type type)1800 static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
1801 {
1802 return new IntegerExp(loc, value, type);
1803 }
1804
1805 // Same as create, but doesn't allocate memory.
emplace(UnionExp * pue,const ref Loc loc,dinteger_t value,Type type)1806 static void emplace(UnionExp* pue, const ref Loc loc, dinteger_t value, Type type)
1807 {
1808 emplaceExp!(IntegerExp)(pue, loc, value, type);
1809 }
1810
equals(const RootObject o)1811 override bool equals(const RootObject o) const
1812 {
1813 if (this == o)
1814 return true;
1815 if (auto ne = (cast(Expression)o).isIntegerExp())
1816 {
1817 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
1818 {
1819 return true;
1820 }
1821 }
1822 return false;
1823 }
1824
toInteger()1825 override dinteger_t toInteger()
1826 {
1827 // normalize() is necessary until we fix all the paints of 'type'
1828 return value = normalize(type.toBasetype().ty, value);
1829 }
1830
toReal()1831 override real_t toReal()
1832 {
1833 // normalize() is necessary until we fix all the paints of 'type'
1834 const ty = type.toBasetype().ty;
1835 const val = normalize(ty, value);
1836 value = val;
1837 return (ty == Tuns64)
1838 ? real_t(cast(ulong)val)
1839 : real_t(cast(long)val);
1840 }
1841
toImaginary()1842 override real_t toImaginary()
1843 {
1844 return CTFloat.zero;
1845 }
1846
toComplex()1847 override complex_t toComplex()
1848 {
1849 return complex_t(toReal());
1850 }
1851
1852 override Optional!bool toBool()
1853 {
1854 bool r = toInteger() != 0;
1855 return typeof(return)(r);
1856 }
1857
toLvalue(Scope * sc,Expression e)1858 override Expression toLvalue(Scope* sc, Expression e)
1859 {
1860 if (!e)
1861 e = this;
1862 else if (!loc.isValid())
1863 loc = e.loc;
1864 e.error("cannot modify constant `%s`", e.toChars());
1865 return ErrorExp.get();
1866 }
1867
accept(Visitor v)1868 override void accept(Visitor v)
1869 {
1870 v.visit(this);
1871 }
1872
getInteger()1873 dinteger_t getInteger()
1874 {
1875 return value;
1876 }
1877
setInteger(dinteger_t value)1878 void setInteger(dinteger_t value)
1879 {
1880 this.value = normalize(type.toBasetype().ty, value);
1881 }
1882
normalize(TY ty,dinteger_t value)1883 extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
1884 {
1885 /* 'Normalize' the value of the integer to be in range of the type
1886 */
1887 dinteger_t result;
1888 switch (ty)
1889 {
1890 case Tbool:
1891 result = (value != 0);
1892 break;
1893
1894 case Tint8:
1895 result = cast(byte)value;
1896 break;
1897
1898 case Tchar:
1899 case Tuns8:
1900 result = cast(ubyte)value;
1901 break;
1902
1903 case Tint16:
1904 result = cast(short)value;
1905 break;
1906
1907 case Twchar:
1908 case Tuns16:
1909 result = cast(ushort)value;
1910 break;
1911
1912 case Tint32:
1913 result = cast(int)value;
1914 break;
1915
1916 case Tdchar:
1917 case Tuns32:
1918 result = cast(uint)value;
1919 break;
1920
1921 case Tint64:
1922 result = cast(long)value;
1923 break;
1924
1925 case Tuns64:
1926 result = cast(ulong)value;
1927 break;
1928
1929 case Tpointer:
1930 if (target.ptrsize == 8)
1931 goto case Tuns64;
1932 if (target.ptrsize == 4)
1933 goto case Tuns32;
1934 if (target.ptrsize == 2)
1935 goto case Tuns16;
1936 assert(0);
1937
1938 default:
1939 break;
1940 }
1941 return result;
1942 }
1943
syntaxCopy()1944 override IntegerExp syntaxCopy()
1945 {
1946 return this;
1947 }
1948
1949 /**
1950 * Use this instead of creating new instances for commonly used literals
1951 * such as 0 or 1.
1952 *
1953 * Parameters:
1954 * v = The value of the expression
1955 * Returns:
1956 * A static instance of the expression, typed as `Tint32`.
1957 */
literal(int v)1958 static IntegerExp literal(int v)()
1959 {
1960 __gshared IntegerExp theConstant;
1961 if (!theConstant)
1962 theConstant = new IntegerExp(v);
1963 return theConstant;
1964 }
1965
1966 /**
1967 * Use this instead of creating new instances for commonly used bools.
1968 *
1969 * Parameters:
1970 * b = The value of the expression
1971 * Returns:
1972 * A static instance of the expression, typed as `Type.tbool`.
1973 */
createBool(bool b)1974 static IntegerExp createBool(bool b)
1975 {
1976 __gshared IntegerExp trueExp, falseExp;
1977 if (!trueExp)
1978 {
1979 trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
1980 falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
1981 }
1982 return b ? trueExp : falseExp;
1983 }
1984 }
1985
1986 /***********************************************************
1987 * Use this expression for error recovery.
1988 *
1989 * It should behave as a 'sink' to prevent further cascaded error messages.
1990 */
1991 extern (C++) final class ErrorExp : Expression
1992 {
this()1993 private extern (D) this()
1994 {
1995 super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp));
1996 type = Type.terror;
1997 }
1998
get()1999 static ErrorExp get ()
2000 {
2001 if (errorexp is null)
2002 errorexp = new ErrorExp();
2003
2004 if (global.errors == 0 && global.gaggedErrors == 0)
2005 {
2006 /* Unfortunately, errors can still leak out of gagged errors,
2007 * and we need to set the error count to prevent bogus code
2008 * generation. At least give a message.
2009 */
2010 .error(Loc.initial, "unknown, please file report on issues.dlang.org");
2011 }
2012
2013 return errorexp;
2014 }
2015
toLvalue(Scope * sc,Expression e)2016 override Expression toLvalue(Scope* sc, Expression e)
2017 {
2018 return this;
2019 }
2020
accept(Visitor v)2021 override void accept(Visitor v)
2022 {
2023 v.visit(this);
2024 }
2025
2026 extern (C++) __gshared ErrorExp errorexp; // handy shared value
2027 }
2028
2029
2030 /***********************************************************
2031 * An uninitialized value,
2032 * generated from void initializers.
2033 *
2034 * https://dlang.org/spec/declaration.html#void_init
2035 */
2036 extern (C++) final class VoidInitExp : Expression
2037 {
2038 VarDeclaration var; /// the variable from where the void value came from, null if not known
2039 /// Useful for error messages
2040
this(VarDeclaration var)2041 extern (D) this(VarDeclaration var)
2042 {
2043 super(var.loc, EXP.void_, __traits(classInstanceSize, VoidInitExp));
2044 this.var = var;
2045 this.type = var.type;
2046 }
2047
toChars()2048 override const(char)* toChars() const
2049 {
2050 return "void";
2051 }
2052
accept(Visitor v)2053 override void accept(Visitor v)
2054 {
2055 v.visit(this);
2056 }
2057 }
2058
2059
2060 /***********************************************************
2061 * A compile-time known floating point number
2062 */
2063 extern (C++) final class RealExp : Expression
2064 {
2065 real_t value;
2066
this(const ref Loc loc,real_t value,Type type)2067 extern (D) this(const ref Loc loc, real_t value, Type type)
2068 {
2069 super(loc, EXP.float64, __traits(classInstanceSize, RealExp));
2070 //printf("RealExp::RealExp(%Lg)\n", value);
2071 this.value = value;
2072 this.type = type;
2073 }
2074
create(const ref Loc loc,real_t value,Type type)2075 static RealExp create(const ref Loc loc, real_t value, Type type)
2076 {
2077 return new RealExp(loc, value, type);
2078 }
2079
2080 // Same as create, but doesn't allocate memory.
emplace(UnionExp * pue,const ref Loc loc,real_t value,Type type)2081 static void emplace(UnionExp* pue, const ref Loc loc, real_t value, Type type)
2082 {
2083 emplaceExp!(RealExp)(pue, loc, value, type);
2084 }
2085
equals(const RootObject o)2086 override bool equals(const RootObject o) const
2087 {
2088 if (this == o)
2089 return true;
2090 if (auto ne = (cast(Expression)o).isRealExp())
2091 {
2092 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
2093 {
2094 return true;
2095 }
2096 }
2097 return false;
2098 }
2099
toInteger()2100 override dinteger_t toInteger()
2101 {
2102 return cast(sinteger_t)toReal();
2103 }
2104
toUInteger()2105 override uinteger_t toUInteger()
2106 {
2107 return cast(uinteger_t)toReal();
2108 }
2109
toReal()2110 override real_t toReal()
2111 {
2112 return type.isreal() ? value : CTFloat.zero;
2113 }
2114
toImaginary()2115 override real_t toImaginary()
2116 {
2117 return type.isreal() ? CTFloat.zero : value;
2118 }
2119
toComplex()2120 override complex_t toComplex()
2121 {
2122 return complex_t(toReal(), toImaginary());
2123 }
2124
2125 override Optional!bool toBool()
2126 {
2127 return typeof(return)(!!value);
2128 }
2129
accept(Visitor v)2130 override void accept(Visitor v)
2131 {
2132 v.visit(this);
2133 }
2134 }
2135
2136 /***********************************************************
2137 * A compile-time complex number (deprecated)
2138 */
2139 extern (C++) final class ComplexExp : Expression
2140 {
2141 complex_t value;
2142
this(const ref Loc loc,complex_t value,Type type)2143 extern (D) this(const ref Loc loc, complex_t value, Type type)
2144 {
2145 super(loc, EXP.complex80, __traits(classInstanceSize, ComplexExp));
2146 this.value = value;
2147 this.type = type;
2148 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
2149 }
2150
create(const ref Loc loc,complex_t value,Type type)2151 static ComplexExp create(const ref Loc loc, complex_t value, Type type)
2152 {
2153 return new ComplexExp(loc, value, type);
2154 }
2155
2156 // Same as create, but doesn't allocate memory.
emplace(UnionExp * pue,const ref Loc loc,complex_t value,Type type)2157 static void emplace(UnionExp* pue, const ref Loc loc, complex_t value, Type type)
2158 {
2159 emplaceExp!(ComplexExp)(pue, loc, value, type);
2160 }
2161
equals(const RootObject o)2162 override bool equals(const RootObject o) const
2163 {
2164 if (this == o)
2165 return true;
2166 if (auto ne = (cast(Expression)o).isComplexExp())
2167 {
2168 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(creall(value), creall(ne.value)) && RealIdentical(cimagl(value), cimagl(ne.value)))
2169 {
2170 return true;
2171 }
2172 }
2173 return false;
2174 }
2175
toInteger()2176 override dinteger_t toInteger()
2177 {
2178 return cast(sinteger_t)toReal();
2179 }
2180
toUInteger()2181 override uinteger_t toUInteger()
2182 {
2183 return cast(uinteger_t)toReal();
2184 }
2185
toReal()2186 override real_t toReal()
2187 {
2188 return creall(value);
2189 }
2190
toImaginary()2191 override real_t toImaginary()
2192 {
2193 return cimagl(value);
2194 }
2195
toComplex()2196 override complex_t toComplex()
2197 {
2198 return value;
2199 }
2200
2201 override Optional!bool toBool()
2202 {
2203 return typeof(return)(!!value);
2204 }
2205
accept(Visitor v)2206 override void accept(Visitor v)
2207 {
2208 v.visit(this);
2209 }
2210 }
2211
2212 /***********************************************************
2213 * An identifier in the context of an expression (as opposed to a declaration)
2214 *
2215 * ---
2216 * int x; // VarDeclaration with Identifier
2217 * x++; // PostExp with IdentifierExp
2218 * ---
2219 */
2220 extern (C++) class IdentifierExp : Expression
2221 {
2222 Identifier ident;
2223
this(const ref Loc loc,Identifier ident)2224 extern (D) this(const ref Loc loc, Identifier ident)
2225 {
2226 super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp));
2227 this.ident = ident;
2228 }
2229
create(const ref Loc loc,Identifier ident)2230 static IdentifierExp create(const ref Loc loc, Identifier ident)
2231 {
2232 return new IdentifierExp(loc, ident);
2233 }
2234
isLvalue()2235 override final bool isLvalue()
2236 {
2237 return true;
2238 }
2239
toLvalue(Scope * sc,Expression e)2240 override final Expression toLvalue(Scope* sc, Expression e)
2241 {
2242 return this;
2243 }
2244
accept(Visitor v)2245 override void accept(Visitor v)
2246 {
2247 v.visit(this);
2248 }
2249 }
2250
2251 /***********************************************************
2252 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
2253 *
2254 * https://dlang.org/spec/arrays.html#array-length
2255 */
2256 extern (C++) final class DollarExp : IdentifierExp
2257 {
this(const ref Loc loc)2258 extern (D) this(const ref Loc loc)
2259 {
2260 super(loc, Id.dollar);
2261 }
2262
accept(Visitor v)2263 override void accept(Visitor v)
2264 {
2265 v.visit(this);
2266 }
2267 }
2268
2269 /***********************************************************
2270 * Won't be generated by parser.
2271 */
2272 extern (C++) final class DsymbolExp : Expression
2273 {
2274 Dsymbol s;
2275 bool hasOverloads;
2276
2277 extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
2278 {
2279 super(loc, EXP.dSymbol, __traits(classInstanceSize, DsymbolExp));
2280 this.s = s;
2281 this.hasOverloads = hasOverloads;
2282 }
2283
isLvalue()2284 override bool isLvalue()
2285 {
2286 return true;
2287 }
2288
toLvalue(Scope * sc,Expression e)2289 override Expression toLvalue(Scope* sc, Expression e)
2290 {
2291 return this;
2292 }
2293
accept(Visitor v)2294 override void accept(Visitor v)
2295 {
2296 v.visit(this);
2297 }
2298 }
2299
2300 /***********************************************************
2301 * https://dlang.org/spec/expression.html#this
2302 */
2303 extern (C++) class ThisExp : Expression
2304 {
2305 VarDeclaration var;
2306
this(const ref Loc loc)2307 extern (D) this(const ref Loc loc)
2308 {
2309 super(loc, EXP.this_, __traits(classInstanceSize, ThisExp));
2310 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2311 }
2312
this(const ref Loc loc,const EXP tok)2313 this(const ref Loc loc, const EXP tok)
2314 {
2315 super(loc, tok, __traits(classInstanceSize, ThisExp));
2316 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2317 }
2318
syntaxCopy()2319 override ThisExp syntaxCopy()
2320 {
2321 auto r = cast(ThisExp) super.syntaxCopy();
2322 // require new semantic (possibly new `var` etc.)
2323 r.type = null;
2324 r.var = null;
2325 return r;
2326 }
2327
2328 override Optional!bool toBool()
2329 {
2330 // `this` is never null (what about structs?)
2331 return typeof(return)(true);
2332 }
2333
isLvalue()2334 override final bool isLvalue()
2335 {
2336 // Class `this` should be an rvalue; struct `this` should be an lvalue.
2337 return type.toBasetype().ty != Tclass;
2338 }
2339
toLvalue(Scope * sc,Expression e)2340 override final Expression toLvalue(Scope* sc, Expression e)
2341 {
2342 if (type.toBasetype().ty == Tclass)
2343 {
2344 // Class `this` is an rvalue; struct `this` is an lvalue.
2345 return Expression.toLvalue(sc, e);
2346 }
2347 return this;
2348 }
2349
accept(Visitor v)2350 override void accept(Visitor v)
2351 {
2352 v.visit(this);
2353 }
2354 }
2355
2356 /***********************************************************
2357 * https://dlang.org/spec/expression.html#super
2358 */
2359 extern (C++) final class SuperExp : ThisExp
2360 {
this(const ref Loc loc)2361 extern (D) this(const ref Loc loc)
2362 {
2363 super(loc, EXP.super_);
2364 }
2365
accept(Visitor v)2366 override void accept(Visitor v)
2367 {
2368 v.visit(this);
2369 }
2370 }
2371
2372 /***********************************************************
2373 * A compile-time known `null` value
2374 *
2375 * https://dlang.org/spec/expression.html#null
2376 */
2377 extern (C++) final class NullExp : Expression
2378 {
2379 extern (D) this(const ref Loc loc, Type type = null)
2380 {
2381 super(loc, EXP.null_, __traits(classInstanceSize, NullExp));
2382 this.type = type;
2383 }
2384
equals(const RootObject o)2385 override bool equals(const RootObject o) const
2386 {
2387 if (auto e = o.isExpression())
2388 {
2389 if (e.op == EXP.null_ && type.equals(e.type))
2390 {
2391 return true;
2392 }
2393 }
2394 return false;
2395 }
2396
2397 override Optional!bool toBool()
2398 {
2399 // null in any type is false
2400 return typeof(return)(false);
2401 }
2402
toStringExp()2403 override StringExp toStringExp()
2404 {
2405 if (implicitConvTo(Type.tstring))
2406 {
2407 auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
2408 se.type = Type.tstring;
2409 return se;
2410 }
2411 return null;
2412 }
2413
accept(Visitor v)2414 override void accept(Visitor v)
2415 {
2416 v.visit(this);
2417 }
2418 }
2419
2420 /***********************************************************
2421 * https://dlang.org/spec/expression.html#string_literals
2422 */
2423 extern (C++) final class StringExp : Expression
2424 {
2425 private union
2426 {
2427 char* string; // if sz == 1
2428 wchar* wstring; // if sz == 2
2429 dchar* dstring; // if sz == 4
2430 } // (const if ownedByCtfe == OwnedBy.code)
2431 size_t len; // number of code units
2432 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
2433 ubyte committed; // !=0 if type is committed
2434 enum char NoPostfix = 0;
2435 char postfix = NoPostfix; // 'c', 'w', 'd'
2436 OwnedBy ownedByCtfe = OwnedBy.code;
2437
this(const ref Loc loc,const (void)[]string)2438 extern (D) this(const ref Loc loc, const(void)[] string)
2439 {
2440 super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
2441 this.string = cast(char*)string.ptr; // note that this.string should be const
2442 this.len = string.length;
2443 this.sz = 1; // work around LDC bug #1286
2444 }
2445
2446 extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
2447 {
2448 super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
2449 this.string = cast(char*)string.ptr; // note that this.string should be const
2450 this.len = len;
2451 this.sz = sz;
2452 this.postfix = postfix;
2453 }
2454
create(const ref Loc loc,const (char)* s)2455 static StringExp create(const ref Loc loc, const(char)* s)
2456 {
2457 return new StringExp(loc, s.toDString());
2458 }
2459
create(const ref Loc loc,const (void)* string,size_t len)2460 static StringExp create(const ref Loc loc, const(void)* string, size_t len)
2461 {
2462 return new StringExp(loc, string[0 .. len]);
2463 }
2464
2465 // Same as create, but doesn't allocate memory.
emplace(UnionExp * pue,const ref Loc loc,const (char)* s)2466 static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s)
2467 {
2468 emplaceExp!(StringExp)(pue, loc, s.toDString());
2469 }
2470
emplace(UnionExp * pue,const ref Loc loc,const (void)[]string)2471 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string)
2472 {
2473 emplaceExp!(StringExp)(pue, loc, string);
2474 }
2475
emplace(UnionExp * pue,const ref Loc loc,const (void)[]string,size_t len,ubyte sz,char postfix)2476 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
2477 {
2478 emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
2479 }
2480
equals(const RootObject o)2481 override bool equals(const RootObject o) const
2482 {
2483 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
2484 if (auto e = o.isExpression())
2485 {
2486 if (auto se = e.isStringExp())
2487 {
2488 return compare(se) == 0;
2489 }
2490 }
2491 return false;
2492 }
2493
2494 /**********************************
2495 * Return the number of code units the string would be if it were re-encoded
2496 * as tynto.
2497 * Params:
2498 * tynto = code unit type of the target encoding
2499 * Returns:
2500 * number of code units
2501 */
2502 size_t numberOfCodeUnits(int tynto = 0) const
2503 {
2504 int encSize;
2505 switch (tynto)
2506 {
2507 case 0: return len;
2508 case Tchar: encSize = 1; break;
2509 case Twchar: encSize = 2; break;
2510 case Tdchar: encSize = 4; break;
2511 default:
2512 assert(0);
2513 }
2514 if (sz == encSize)
2515 return len;
2516
2517 size_t result = 0;
2518 dchar c;
2519
2520 switch (sz)
2521 {
2522 case 1:
2523 for (size_t u = 0; u < len;)
2524 {
2525 if (const s = utf_decodeChar(string[0 .. len], u, c))
2526 {
2527 error("%.*s", cast(int)s.length, s.ptr);
2528 return 0;
2529 }
2530 result += utf_codeLength(encSize, c);
2531 }
2532 break;
2533
2534 case 2:
2535 for (size_t u = 0; u < len;)
2536 {
2537 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
2538 {
2539 error("%.*s", cast(int)s.length, s.ptr);
2540 return 0;
2541 }
2542 result += utf_codeLength(encSize, c);
2543 }
2544 break;
2545
2546 case 4:
2547 foreach (u; 0 .. len)
2548 {
2549 result += utf_codeLength(encSize, dstring[u]);
2550 }
2551 break;
2552
2553 default:
2554 assert(0);
2555 }
2556 return result;
2557 }
2558
2559 /**********************************************
2560 * Write the contents of the string to dest.
2561 * Use numberOfCodeUnits() to determine size of result.
2562 * Params:
2563 * dest = destination
2564 * tyto = encoding type of the result
2565 * zero = add terminating 0
2566 */
2567 void writeTo(void* dest, bool zero, int tyto = 0) const
2568 {
2569 int encSize;
2570 switch (tyto)
2571 {
2572 case 0: encSize = sz; break;
2573 case Tchar: encSize = 1; break;
2574 case Twchar: encSize = 2; break;
2575 case Tdchar: encSize = 4; break;
2576 default:
2577 assert(0);
2578 }
2579 if (sz == encSize)
2580 {
2581 memcpy(dest, string, len * sz);
2582 if (zero)
2583 memset(dest + len * sz, 0, sz);
2584 }
2585 else
2586 assert(0);
2587 }
2588
2589 /*********************************************
2590 * Get the code unit at index i
2591 * Params:
2592 * i = index
2593 * Returns:
2594 * code unit at index i
2595 */
getCodeUnit(size_t i)2596 dchar getCodeUnit(size_t i) const pure
2597 {
2598 assert(i < len);
2599 final switch (sz)
2600 {
2601 case 1:
2602 return string[i];
2603 case 2:
2604 return wstring[i];
2605 case 4:
2606 return dstring[i];
2607 }
2608 }
2609
2610 /*********************************************
2611 * Set the code unit at index i to c
2612 * Params:
2613 * i = index
2614 * c = code unit to set it to
2615 */
setCodeUnit(size_t i,dchar c)2616 void setCodeUnit(size_t i, dchar c)
2617 {
2618 assert(i < len);
2619 final switch (sz)
2620 {
2621 case 1:
2622 string[i] = cast(char)c;
2623 break;
2624 case 2:
2625 wstring[i] = cast(wchar)c;
2626 break;
2627 case 4:
2628 dstring[i] = c;
2629 break;
2630 }
2631 }
2632
toStringExp()2633 override StringExp toStringExp()
2634 {
2635 return this;
2636 }
2637
2638 /****************************************
2639 * Convert string to char[].
2640 */
toUTF8(Scope * sc)2641 StringExp toUTF8(Scope* sc)
2642 {
2643 if (sz != 1)
2644 {
2645 // Convert to UTF-8 string
2646 committed = 0;
2647 Expression e = castTo(sc, Type.tchar.arrayOf());
2648 e = e.optimize(WANTvalue);
2649 auto se = e.isStringExp();
2650 assert(se.sz == 1);
2651 return se;
2652 }
2653 return this;
2654 }
2655
2656 /**
2657 * Compare two `StringExp` by length, then value
2658 *
2659 * The comparison is not the usual C-style comparison as seen with
2660 * `strcmp` or `memcmp`, but instead first compare based on the length.
2661 * This allows both faster lookup and sorting when comparing sparse data.
2662 *
2663 * This ordering scheme is relied on by the string-switching feature.
2664 * Code in Druntime's `core.internal.switch_` relies on this ordering
2665 * when doing a binary search among case statements.
2666 *
2667 * Both `StringExp` should be of the same encoding.
2668 *
2669 * Params:
2670 * se2 = String expression to compare `this` to
2671 *
2672 * Returns:
2673 * `0` when `this` is equal to se2, a value greater than `0` if
2674 * `this` should be considered greater than `se2`,
2675 * and a value less than `0` if `this` is lesser than `se2`.
2676 */
compare(const StringExp se2)2677 int compare(const StringExp se2) const nothrow pure @nogc
2678 {
2679 //printf("StringExp::compare()\n");
2680 const len1 = len;
2681 const len2 = se2.len;
2682
2683 assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
2684 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
2685 if (len1 == len2)
2686 {
2687 switch (sz)
2688 {
2689 case 1:
2690 return memcmp(string, se2.string, len1);
2691
2692 case 2:
2693 {
2694 wchar* s1 = cast(wchar*)string;
2695 wchar* s2 = cast(wchar*)se2.string;
2696 foreach (u; 0 .. len)
2697 {
2698 if (s1[u] != s2[u])
2699 return s1[u] - s2[u];
2700 }
2701 }
2702 break;
2703 case 4:
2704 {
2705 dchar* s1 = cast(dchar*)string;
2706 dchar* s2 = cast(dchar*)se2.string;
2707 foreach (u; 0 .. len)
2708 {
2709 if (s1[u] != s2[u])
2710 return s1[u] - s2[u];
2711 }
2712 }
2713 break;
2714 default:
2715 assert(0);
2716 }
2717 }
2718 return cast(int)(len1 - len2);
2719 }
2720
2721 override Optional!bool toBool()
2722 {
2723 // Keep the old behaviour for this refactoring
2724 // Should probably match language spec instead and check for length
2725 return typeof(return)(true);
2726 }
2727
isLvalue()2728 override bool isLvalue()
2729 {
2730 /* string literal is rvalue in default, but
2731 * conversion to reference of static array is only allowed.
2732 */
2733 return (type && type.toBasetype().ty == Tsarray);
2734 }
2735
toLvalue(Scope * sc,Expression e)2736 override Expression toLvalue(Scope* sc, Expression e)
2737 {
2738 //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
2739 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
2740 }
2741
modifiableLvalue(Scope * sc,Expression e)2742 override Expression modifiableLvalue(Scope* sc, Expression e)
2743 {
2744 error("cannot modify string literal `%s`", toChars());
2745 return ErrorExp.get();
2746 }
2747
2748 /********************************
2749 * Convert string contents to a 0 terminated string,
2750 * allocated by mem.xmalloc().
2751 */
toStringz()2752 extern (D) const(char)[] toStringz() const
2753 {
2754 auto nbytes = len * sz;
2755 char* s = cast(char*)mem.xmalloc(nbytes + sz);
2756 writeTo(s, true);
2757 return s[0 .. nbytes];
2758 }
2759
peekString()2760 extern (D) const(char)[] peekString() const
2761 {
2762 assert(sz == 1);
2763 return this.string[0 .. len];
2764 }
2765
peekWstring()2766 extern (D) const(wchar)[] peekWstring() const
2767 {
2768 assert(sz == 2);
2769 return this.wstring[0 .. len];
2770 }
2771
peekDstring()2772 extern (D) const(dchar)[] peekDstring() const
2773 {
2774 assert(sz == 4);
2775 return this.dstring[0 .. len];
2776 }
2777
2778 /*******************
2779 * Get a slice of the data.
2780 */
peekData()2781 extern (D) const(ubyte)[] peekData() const
2782 {
2783 return cast(const(ubyte)[])this.string[0 .. len * sz];
2784 }
2785
2786 /*******************
2787 * Borrow a slice of the data, so the caller can modify
2788 * it in-place (!)
2789 */
borrowData()2790 extern (D) ubyte[] borrowData()
2791 {
2792 return cast(ubyte[])this.string[0 .. len * sz];
2793 }
2794
2795 /***********************
2796 * Set new string data.
2797 * `this` becomes the new owner of the data.
2798 */
setData(void * s,size_t len,ubyte sz)2799 extern (D) void setData(void* s, size_t len, ubyte sz)
2800 {
2801 this.string = cast(char*)s;
2802 this.len = len;
2803 this.sz = sz;
2804 }
2805
accept(Visitor v)2806 override void accept(Visitor v)
2807 {
2808 v.visit(this);
2809 }
2810 }
2811
2812 /***********************************************************
2813 * A sequence of expressions
2814 *
2815 * ---
2816 * alias AliasSeq(T...) = T;
2817 * alias Tup = AliasSeq!(3, int, "abc");
2818 * ---
2819 */
2820 extern (C++) final class TupleExp : Expression
2821 {
2822 /* Tuple-field access may need to take out its side effect part.
2823 * For example:
2824 * foo().tupleof
2825 * is rewritten as:
2826 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
2827 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
2828 */
2829 Expression e0;
2830
2831 Expressions* exps;
2832
this(const ref Loc loc,Expression e0,Expressions * exps)2833 extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
2834 {
2835 super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
2836 //printf("TupleExp(this = %p)\n", this);
2837 this.e0 = e0;
2838 this.exps = exps;
2839 }
2840
this(const ref Loc loc,Expressions * exps)2841 extern (D) this(const ref Loc loc, Expressions* exps)
2842 {
2843 super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
2844 //printf("TupleExp(this = %p)\n", this);
2845 this.exps = exps;
2846 }
2847
this(const ref Loc loc,TupleDeclaration tup)2848 extern (D) this(const ref Loc loc, TupleDeclaration tup)
2849 {
2850 super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
2851 this.exps = new Expressions();
2852
2853 this.exps.reserve(tup.objects.dim);
2854 foreach (o; *tup.objects)
2855 {
2856 if (Dsymbol s = getDsymbol(o))
2857 {
2858 /* If tuple element represents a symbol, translate to DsymbolExp
2859 * to supply implicit 'this' if needed later.
2860 */
2861 Expression e = new DsymbolExp(loc, s);
2862 this.exps.push(e);
2863 }
2864 else if (auto eo = o.isExpression())
2865 {
2866 auto e = eo.copy();
2867 e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669
2868 this.exps.push(e);
2869 }
2870 else if (auto t = o.isType())
2871 {
2872 Expression e = new TypeExp(loc, t);
2873 this.exps.push(e);
2874 }
2875 else
2876 {
2877 error("`%s` is not an expression", o.toChars());
2878 }
2879 }
2880 }
2881
create(const ref Loc loc,Expressions * exps)2882 static TupleExp create(const ref Loc loc, Expressions* exps)
2883 {
2884 return new TupleExp(loc, exps);
2885 }
2886
syntaxCopy()2887 override TupleExp syntaxCopy()
2888 {
2889 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
2890 }
2891
equals(const RootObject o)2892 override bool equals(const RootObject o) const
2893 {
2894 if (this == o)
2895 return true;
2896 if (auto e = o.isExpression())
2897 if (auto te = e.isTupleExp())
2898 {
2899 if (exps.dim != te.exps.dim)
2900 return false;
2901 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
2902 return false;
2903 foreach (i, e1; *exps)
2904 {
2905 auto e2 = (*te.exps)[i];
2906 if (!e1.equals(e2))
2907 return false;
2908 }
2909 return true;
2910 }
2911 return false;
2912 }
2913
accept(Visitor v)2914 override void accept(Visitor v)
2915 {
2916 v.visit(this);
2917 }
2918 }
2919
2920 /***********************************************************
2921 * [ e1, e2, e3, ... ]
2922 *
2923 * https://dlang.org/spec/expression.html#array_literals
2924 */
2925 extern (C++) final class ArrayLiteralExp : Expression
2926 {
2927 /** If !is null, elements[] can be sparse and basis is used for the
2928 * "default" element value. In other words, non-null elements[i] overrides
2929 * this 'basis' value.
2930 */
2931 Expression basis;
2932
2933 Expressions* elements;
2934 OwnedBy ownedByCtfe = OwnedBy.code;
2935
2936
this(const ref Loc loc,Type type,Expressions * elements)2937 extern (D) this(const ref Loc loc, Type type, Expressions* elements)
2938 {
2939 super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2940 this.type = type;
2941 this.elements = elements;
2942 }
2943
this(const ref Loc loc,Type type,Expression e)2944 extern (D) this(const ref Loc loc, Type type, Expression e)
2945 {
2946 super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2947 this.type = type;
2948 elements = new Expressions();
2949 elements.push(e);
2950 }
2951
this(const ref Loc loc,Type type,Expression basis,Expressions * elements)2952 extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
2953 {
2954 super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2955 this.type = type;
2956 this.basis = basis;
2957 this.elements = elements;
2958 }
2959
create(const ref Loc loc,Expressions * elements)2960 static ArrayLiteralExp create(const ref Loc loc, Expressions* elements)
2961 {
2962 return new ArrayLiteralExp(loc, null, elements);
2963 }
2964
2965 // Same as create, but doesn't allocate memory.
emplace(UnionExp * pue,const ref Loc loc,Expressions * elements)2966 static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements)
2967 {
2968 emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
2969 }
2970
syntaxCopy()2971 override ArrayLiteralExp syntaxCopy()
2972 {
2973 return new ArrayLiteralExp(loc,
2974 null,
2975 basis ? basis.syntaxCopy() : null,
2976 arraySyntaxCopy(elements));
2977 }
2978
equals(const RootObject o)2979 override bool equals(const RootObject o) const
2980 {
2981 if (this == o)
2982 return true;
2983 auto e = o.isExpression();
2984 if (!e)
2985 return false;
2986 if (auto ae = e.isArrayLiteralExp())
2987 {
2988 if (elements.dim != ae.elements.dim)
2989 return false;
2990 if (elements.dim == 0 && !type.equals(ae.type))
2991 {
2992 return false;
2993 }
2994
2995 foreach (i, e1; *elements)
2996 {
2997 auto e2 = (*ae.elements)[i];
2998 auto e1x = e1 ? e1 : basis;
2999 auto e2x = e2 ? e2 : ae.basis;
3000
3001 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
3002 return false;
3003 }
3004 return true;
3005 }
3006 return false;
3007 }
3008
getElement(size_t i)3009 Expression getElement(size_t i)
3010 {
3011 return this[i];
3012 }
3013
opIndex(size_t i)3014 Expression opIndex(size_t i)
3015 {
3016 auto el = (*elements)[i];
3017 return el ? el : basis;
3018 }
3019
3020 override Optional!bool toBool()
3021 {
3022 size_t dim = elements ? elements.dim : 0;
3023 return typeof(return)(dim != 0);
3024 }
3025
toStringExp()3026 override StringExp toStringExp()
3027 {
3028 TY telem = type.nextOf().toBasetype().ty;
3029 if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.dim == 0)))
3030 {
3031 ubyte sz = 1;
3032 if (telem == Twchar)
3033 sz = 2;
3034 else if (telem == Tdchar)
3035 sz = 4;
3036
3037 OutBuffer buf;
3038 if (elements)
3039 {
3040 foreach (i; 0 .. elements.dim)
3041 {
3042 auto ch = this[i];
3043 if (ch.op != EXP.int64)
3044 return null;
3045 if (sz == 1)
3046 buf.writeByte(cast(uint)ch.toInteger());
3047 else if (sz == 2)
3048 buf.writeword(cast(uint)ch.toInteger());
3049 else
3050 buf.write4(cast(uint)ch.toInteger());
3051 }
3052 }
3053 char prefix;
3054 if (sz == 1)
3055 {
3056 prefix = 'c';
3057 buf.writeByte(0);
3058 }
3059 else if (sz == 2)
3060 {
3061 prefix = 'w';
3062 buf.writeword(0);
3063 }
3064 else
3065 {
3066 prefix = 'd';
3067 buf.write4(0);
3068 }
3069
3070 const size_t len = buf.length / sz - 1;
3071 auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
3072 se.sz = sz;
3073 se.type = type;
3074 return se;
3075 }
3076 return null;
3077 }
3078
accept(Visitor v)3079 override void accept(Visitor v)
3080 {
3081 v.visit(this);
3082 }
3083 }
3084
3085 /***********************************************************
3086 * [ key0 : value0, key1 : value1, ... ]
3087 *
3088 * https://dlang.org/spec/expression.html#associative_array_literals
3089 */
3090 extern (C++) final class AssocArrayLiteralExp : Expression
3091 {
3092 Expressions* keys;
3093 Expressions* values;
3094
3095 OwnedBy ownedByCtfe = OwnedBy.code;
3096
this(const ref Loc loc,Expressions * keys,Expressions * values)3097 extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
3098 {
3099 super(loc, EXP.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
3100 assert(keys.dim == values.dim);
3101 this.keys = keys;
3102 this.values = values;
3103 }
3104
equals(const RootObject o)3105 override bool equals(const RootObject o) const
3106 {
3107 if (this == o)
3108 return true;
3109 auto e = o.isExpression();
3110 if (!e)
3111 return false;
3112 if (auto ae = e.isAssocArrayLiteralExp())
3113 {
3114 if (keys.dim != ae.keys.dim)
3115 return false;
3116 size_t count = 0;
3117 foreach (i, key; *keys)
3118 {
3119 foreach (j, akey; *ae.keys)
3120 {
3121 if (key.equals(akey))
3122 {
3123 if (!(*values)[i].equals((*ae.values)[j]))
3124 return false;
3125 ++count;
3126 }
3127 }
3128 }
3129 return count == keys.dim;
3130 }
3131 return false;
3132 }
3133
syntaxCopy()3134 override AssocArrayLiteralExp syntaxCopy()
3135 {
3136 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
3137 }
3138
3139 override Optional!bool toBool()
3140 {
3141 size_t dim = keys.dim;
3142 return typeof(return)(dim != 0);
3143 }
3144
accept(Visitor v)3145 override void accept(Visitor v)
3146 {
3147 v.visit(this);
3148 }
3149 }
3150
3151 enum stageScrub = 0x1; /// scrubReturnValue is running
3152 enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
3153 enum stageOptimize = 0x4; /// optimize is running
3154 enum stageApply = 0x8; /// apply is running
3155 enum stageInlineScan = 0x10; /// inlineScan is running
3156 enum stageToCBuffer = 0x20; /// toCBuffer is running
3157
3158 /***********************************************************
3159 * sd( e1, e2, e3, ... )
3160 */
3161 extern (C++) final class StructLiteralExp : Expression
3162 {
3163 StructDeclaration sd; /// which aggregate this is for
3164 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
3165 Type stype; /// final type of result (can be different from sd's type)
3166
3167 Symbol* sym; /// back end symbol to initialize with literal
3168
3169 /** pointer to the origin instance of the expression.
3170 * once a new expression is created, origin is set to 'this'.
3171 * anytime when an expression copy is created, 'origin' pointer is set to
3172 * 'origin' pointer value of the original expression.
3173 */
3174 StructLiteralExp origin;
3175
3176 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
3177 StructLiteralExp inlinecopy;
3178
3179 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
3180 * current stage and unmarks before return from this function.
3181 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
3182 * (with infinite recursion) of this expression.
3183 */
3184 int stageflags;
3185
3186 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
3187 bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
3188 OwnedBy ownedByCtfe = OwnedBy.code;
3189
3190 extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
3191 {
3192 super(loc, EXP.structLiteral, __traits(classInstanceSize, StructLiteralExp));
3193 this.sd = sd;
3194 if (!elements)
3195 elements = new Expressions();
3196 this.elements = elements;
3197 this.stype = stype;
3198 this.origin = this;
3199 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
3200 }
3201
3202 static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
3203 {
3204 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
3205 }
3206
equals(const RootObject o)3207 override bool equals(const RootObject o) const
3208 {
3209 if (this == o)
3210 return true;
3211 auto e = o.isExpression();
3212 if (!e)
3213 return false;
3214 if (auto se = e.isStructLiteralExp())
3215 {
3216 if (!type.equals(se.type))
3217 return false;
3218 if (elements.dim != se.elements.dim)
3219 return false;
3220 foreach (i, e1; *elements)
3221 {
3222 auto e2 = (*se.elements)[i];
3223 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3224 return false;
3225 }
3226 return true;
3227 }
3228 return false;
3229 }
3230
syntaxCopy()3231 override StructLiteralExp syntaxCopy()
3232 {
3233 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
3234 exp.origin = this;
3235 return exp;
3236 }
3237
3238 /**************************************
3239 * Gets expression at offset of type.
3240 * Returns NULL if not found.
3241 */
getField(Type type,uint offset)3242 Expression getField(Type type, uint offset)
3243 {
3244 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
3245 // /*toChars()*/"", type.toChars(), offset);
3246 Expression e = null;
3247 int i = getFieldIndex(type, offset);
3248
3249 if (i != -1)
3250 {
3251 //printf("\ti = %d\n", i);
3252 if (i >= sd.nonHiddenFields())
3253 return null;
3254
3255 assert(i < elements.dim);
3256 e = (*elements)[i];
3257 if (e)
3258 {
3259 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
3260
3261 /* If type is a static array, and e is an initializer for that array,
3262 * then the field initializer should be an array literal of e.
3263 */
3264 auto tsa = type.isTypeSArray();
3265 if (tsa && e.type.castMod(0) != type.castMod(0))
3266 {
3267 const length = cast(size_t)tsa.dim.toInteger();
3268 auto z = new Expressions(length);
3269 foreach (ref q; *z)
3270 q = e.copy();
3271 e = new ArrayLiteralExp(loc, type, z);
3272 }
3273 else
3274 {
3275 e = e.copy();
3276 e.type = type;
3277 }
3278 if (useStaticInit && e.type.needsNested())
3279 if (auto se = e.isStructLiteralExp())
3280 {
3281 se.useStaticInit = true;
3282 }
3283 }
3284 }
3285 return e;
3286 }
3287
3288 /************************************
3289 * Get index of field.
3290 * Returns -1 if not found.
3291 */
getFieldIndex(Type type,uint offset)3292 int getFieldIndex(Type type, uint offset)
3293 {
3294 /* Find which field offset is by looking at the field offsets
3295 */
3296 if (elements.dim)
3297 {
3298 const sz = type.size();
3299 if (sz == SIZE_INVALID)
3300 return -1;
3301 foreach (i, v; sd.fields)
3302 {
3303 if (offset == v.offset && sz == v.type.size())
3304 {
3305 /* context fields might not be filled. */
3306 if (i >= sd.nonHiddenFields())
3307 return cast(int)i;
3308 if (auto e = (*elements)[i])
3309 {
3310 return cast(int)i;
3311 }
3312 break;
3313 }
3314 }
3315 }
3316 return -1;
3317 }
3318
addDtorHook(Scope * sc)3319 override Expression addDtorHook(Scope* sc)
3320 {
3321 /* If struct requires a destructor, rewrite as:
3322 * (S tmp = S()),tmp
3323 * so that the destructor can be hung on tmp.
3324 */
3325 if (sd.dtor && sc.func)
3326 {
3327 /* Make an identifier for the temporary of the form:
3328 * __sl%s%d, where %s is the struct name
3329 */
3330 char[10] buf = void;
3331 const prefix = "__sl";
3332 const ident = sd.ident.toString;
3333 const fullLen = prefix.length + ident.length;
3334 const len = fullLen < buf.length ? fullLen : buf.length;
3335 buf[0 .. prefix.length] = prefix;
3336 buf[prefix.length .. len] = ident[0 .. len - prefix.length];
3337
3338 auto tmp = copyToTemp(0, buf[0 .. len], this);
3339 Expression ae = new DeclarationExp(loc, tmp);
3340 Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
3341 e = e.expressionSemantic(sc);
3342 return e;
3343 }
3344 return this;
3345 }
3346
toLvalue(Scope * sc,Expression e)3347 override Expression toLvalue(Scope* sc, Expression e)
3348 {
3349 if (sc.flags & SCOPE.Cfile)
3350 return this; // C struct literals are lvalues
3351 else
3352 return Expression.toLvalue(sc, e);
3353 }
3354
accept(Visitor v)3355 override void accept(Visitor v)
3356 {
3357 v.visit(this);
3358 }
3359 }
3360
3361 /***********************************************************
3362 * C11 6.5.2.5
3363 * ( type-name ) { initializer-list }
3364 */
3365 extern (C++) final class CompoundLiteralExp : Expression
3366 {
3367 Initializer initializer; /// initializer-list
3368
this(const ref Loc loc,Type type_name,Initializer initializer)3369 extern (D) this(const ref Loc loc, Type type_name, Initializer initializer)
3370 {
3371 super(loc, EXP.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
3372 super.type = type_name;
3373 this.initializer = initializer;
3374 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
3375 }
3376
accept(Visitor v)3377 override void accept(Visitor v)
3378 {
3379 v.visit(this);
3380 }
3381 }
3382
3383 /***********************************************************
3384 * Mainly just a placeholder
3385 */
3386 extern (C++) final class TypeExp : Expression
3387 {
this(const ref Loc loc,Type type)3388 extern (D) this(const ref Loc loc, Type type)
3389 {
3390 super(loc, EXP.type, __traits(classInstanceSize, TypeExp));
3391 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
3392 this.type = type;
3393 }
3394
syntaxCopy()3395 override TypeExp syntaxCopy()
3396 {
3397 return new TypeExp(loc, type.syntaxCopy());
3398 }
3399
checkType()3400 override bool checkType()
3401 {
3402 error("type `%s` is not an expression", toChars());
3403 return true;
3404 }
3405
checkValue()3406 override bool checkValue()
3407 {
3408 error("type `%s` has no value", toChars());
3409 return true;
3410 }
3411
accept(Visitor v)3412 override void accept(Visitor v)
3413 {
3414 v.visit(this);
3415 }
3416 }
3417
3418 /***********************************************************
3419 * Mainly just a placeholder of
3420 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
3421 *
3422 * A template instance that requires IFTI:
3423 * foo!tiargs(fargs) // foo!tiargs
3424 * is left until CallExp::semantic() or resolveProperties()
3425 */
3426 extern (C++) final class ScopeExp : Expression
3427 {
3428 ScopeDsymbol sds;
3429
this(const ref Loc loc,ScopeDsymbol sds)3430 extern (D) this(const ref Loc loc, ScopeDsymbol sds)
3431 {
3432 super(loc, EXP.scope_, __traits(classInstanceSize, ScopeExp));
3433 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
3434 //static int count; if (++count == 38) *(char*)0=0;
3435 this.sds = sds;
3436 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp
3437 }
3438
syntaxCopy()3439 override ScopeExp syntaxCopy()
3440 {
3441 return new ScopeExp(loc, sds.syntaxCopy(null));
3442 }
3443
checkType()3444 override bool checkType()
3445 {
3446 if (sds.isPackage())
3447 {
3448 error("%s `%s` has no type", sds.kind(), sds.toChars());
3449 return true;
3450 }
3451 if (auto ti = sds.isTemplateInstance())
3452 {
3453 //assert(ti.needsTypeInference(sc));
3454 if (ti.tempdecl &&
3455 ti.semantictiargsdone &&
3456 ti.semanticRun == PASS.initial)
3457 {
3458 error("partial %s `%s` has no type", sds.kind(), toChars());
3459 return true;
3460 }
3461 }
3462 return false;
3463 }
3464
checkValue()3465 override bool checkValue()
3466 {
3467 error("%s `%s` has no value", sds.kind(), sds.toChars());
3468 return true;
3469 }
3470
accept(Visitor v)3471 override void accept(Visitor v)
3472 {
3473 v.visit(this);
3474 }
3475 }
3476
3477 /***********************************************************
3478 * Mainly just a placeholder
3479 */
3480 extern (C++) final class TemplateExp : Expression
3481 {
3482 TemplateDeclaration td;
3483 FuncDeclaration fd;
3484
3485 extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
3486 {
3487 super(loc, EXP.template_, __traits(classInstanceSize, TemplateExp));
3488 //printf("TemplateExp(): %s\n", td.toChars());
3489 this.td = td;
3490 this.fd = fd;
3491 }
3492
isLvalue()3493 override bool isLvalue()
3494 {
3495 return fd !is null;
3496 }
3497
toLvalue(Scope * sc,Expression e)3498 override Expression toLvalue(Scope* sc, Expression e)
3499 {
3500 if (!fd)
3501 return Expression.toLvalue(sc, e);
3502
3503 assert(sc);
3504 return symbolToExp(fd, loc, sc, true);
3505 }
3506
checkType()3507 override bool checkType()
3508 {
3509 error("%s `%s` has no type", td.kind(), toChars());
3510 return true;
3511 }
3512
checkValue()3513 override bool checkValue()
3514 {
3515 error("%s `%s` has no value", td.kind(), toChars());
3516 return true;
3517 }
3518
accept(Visitor v)3519 override void accept(Visitor v)
3520 {
3521 v.visit(this);
3522 }
3523 }
3524
3525 /***********************************************************
3526 * newtype(arguments)
3527 */
3528 extern (C++) final class NewExp : Expression
3529 {
3530 Expression thisexp; // if !=null, 'this' for class being allocated
3531 Type newtype;
3532 Expressions* arguments; // Array of Expression's
3533
3534 Expression argprefix; // expression to be evaluated just before arguments[]
3535 CtorDeclaration member; // constructor function
3536 bool onstack; // allocate on stack
3537 bool thrownew; // this NewExp is the expression of a ThrowStatement
3538
this(const ref Loc loc,Expression thisexp,Type newtype,Expressions * arguments)3539 extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
3540 {
3541 super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
3542 this.thisexp = thisexp;
3543 this.newtype = newtype;
3544 this.arguments = arguments;
3545 }
3546
create(const ref Loc loc,Expression thisexp,Type newtype,Expressions * arguments)3547 static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
3548 {
3549 return new NewExp(loc, thisexp, newtype, arguments);
3550 }
3551
syntaxCopy()3552 override NewExp syntaxCopy()
3553 {
3554 return new NewExp(loc,
3555 thisexp ? thisexp.syntaxCopy() : null,
3556 newtype.syntaxCopy(),
3557 arraySyntaxCopy(arguments));
3558 }
3559
accept(Visitor v)3560 override void accept(Visitor v)
3561 {
3562 v.visit(this);
3563 }
3564 }
3565
3566 /***********************************************************
3567 * class baseclasses { } (arguments)
3568 */
3569 extern (C++) final class NewAnonClassExp : Expression
3570 {
3571 Expression thisexp; // if !=null, 'this' for class being allocated
3572 ClassDeclaration cd; // class being instantiated
3573 Expressions* arguments; // Array of Expression's to call class constructor
3574
this(const ref Loc loc,Expression thisexp,ClassDeclaration cd,Expressions * arguments)3575 extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
3576 {
3577 super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
3578 this.thisexp = thisexp;
3579 this.cd = cd;
3580 this.arguments = arguments;
3581 }
3582
syntaxCopy()3583 override NewAnonClassExp syntaxCopy()
3584 {
3585 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
3586 }
3587
accept(Visitor v)3588 override void accept(Visitor v)
3589 {
3590 v.visit(this);
3591 }
3592 }
3593
3594 /***********************************************************
3595 */
3596 extern (C++) class SymbolExp : Expression
3597 {
3598 Declaration var;
3599 Dsymbol originalScope; // original scope before inlining
3600 bool hasOverloads;
3601
this(const ref Loc loc,EXP op,int size,Declaration var,bool hasOverloads)3602 extern (D) this(const ref Loc loc, EXP op, int size, Declaration var, bool hasOverloads)
3603 {
3604 super(loc, op, size);
3605 assert(var);
3606 this.var = var;
3607 this.hasOverloads = hasOverloads;
3608 }
3609
accept(Visitor v)3610 override void accept(Visitor v)
3611 {
3612 v.visit(this);
3613 }
3614 }
3615
3616 /***********************************************************
3617 * Offset from symbol
3618 */
3619 extern (C++) final class SymOffExp : SymbolExp
3620 {
3621 dinteger_t offset;
3622
3623 extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
3624 {
3625 if (auto v = var.isVarDeclaration())
3626 {
3627 // FIXME: This error report will never be handled anyone.
3628 // It should be done before the SymOffExp construction.
3629 if (v.needThis())
3630 .error(loc, "need `this` for address of `%s`", v.toChars());
3631 hasOverloads = false;
3632 }
3633 super(loc, EXP.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
3634 this.offset = offset;
3635 }
3636
3637 override Optional!bool toBool()
3638 {
3639 return typeof(return)(true);
3640 }
3641
accept(Visitor v)3642 override void accept(Visitor v)
3643 {
3644 v.visit(this);
3645 }
3646 }
3647
3648 /***********************************************************
3649 * Variable
3650 */
3651 extern (C++) final class VarExp : SymbolExp
3652 {
3653 bool delegateWasExtracted;
3654 extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true)
3655 {
3656 if (var.isVarDeclaration())
3657 hasOverloads = false;
3658
3659 super(loc, EXP.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
3660 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
3661 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
3662 this.type = var.type;
3663 }
3664
3665 static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true)
3666 {
3667 return new VarExp(loc, var, hasOverloads);
3668 }
3669
equals(const RootObject o)3670 override bool equals(const RootObject o) const
3671 {
3672 if (this == o)
3673 return true;
3674 if (auto ne = o.isExpression().isVarExp())
3675 {
3676 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
3677 {
3678 return true;
3679 }
3680 }
3681 return false;
3682 }
3683
isLvalue()3684 override bool isLvalue()
3685 {
3686 if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
3687 return false;
3688 return true;
3689 }
3690
toLvalue(Scope * sc,Expression e)3691 override Expression toLvalue(Scope* sc, Expression e)
3692 {
3693 if (var.storage_class & STC.manifest)
3694 {
3695 error("manifest constant `%s` cannot be modified", var.toChars());
3696 return ErrorExp.get();
3697 }
3698 if (var.storage_class & STC.lazy_ && !delegateWasExtracted)
3699 {
3700 error("lazy variable `%s` cannot be modified", var.toChars());
3701 return ErrorExp.get();
3702 }
3703 if (var.ident == Id.ctfe)
3704 {
3705 error("cannot modify compiler-generated variable `__ctfe`");
3706 return ErrorExp.get();
3707 }
3708 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
3709 {
3710 error("cannot modify operator `$`");
3711 return ErrorExp.get();
3712 }
3713 return this;
3714 }
3715
modifiableLvalue(Scope * sc,Expression e)3716 override Expression modifiableLvalue(Scope* sc, Expression e)
3717 {
3718 //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
3719 if (var.storage_class & STC.manifest)
3720 {
3721 error("cannot modify manifest constant `%s`", toChars());
3722 return ErrorExp.get();
3723 }
3724 // See if this expression is a modifiable lvalue (i.e. not const)
3725 return Expression.modifiableLvalue(sc, e);
3726 }
3727
accept(Visitor v)3728 override void accept(Visitor v)
3729 {
3730 v.visit(this);
3731 }
3732 }
3733
3734 /***********************************************************
3735 * Overload Set
3736 */
3737 extern (C++) final class OverExp : Expression
3738 {
3739 OverloadSet vars;
3740
this(const ref Loc loc,OverloadSet s)3741 extern (D) this(const ref Loc loc, OverloadSet s)
3742 {
3743 super(loc, EXP.overloadSet, __traits(classInstanceSize, OverExp));
3744 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
3745 vars = s;
3746 type = Type.tvoid;
3747 }
3748
isLvalue()3749 override bool isLvalue()
3750 {
3751 return true;
3752 }
3753
toLvalue(Scope * sc,Expression e)3754 override Expression toLvalue(Scope* sc, Expression e)
3755 {
3756 return this;
3757 }
3758
accept(Visitor v)3759 override void accept(Visitor v)
3760 {
3761 v.visit(this);
3762 }
3763 }
3764
3765 /***********************************************************
3766 * Function/Delegate literal
3767 */
3768
3769 extern (C++) final class FuncExp : Expression
3770 {
3771 FuncLiteralDeclaration fd;
3772 TemplateDeclaration td;
3773 TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
3774
this(const ref Loc loc,Dsymbol s)3775 extern (D) this(const ref Loc loc, Dsymbol s)
3776 {
3777 super(loc, EXP.function_, __traits(classInstanceSize, FuncExp));
3778 this.td = s.isTemplateDeclaration();
3779 this.fd = s.isFuncLiteralDeclaration();
3780 if (td)
3781 {
3782 assert(td.literal);
3783 assert(td.members && td.members.dim == 1);
3784 fd = (*td.members)[0].isFuncLiteralDeclaration();
3785 }
3786 tok = fd.tok; // save original kind of function/delegate/(infer)
3787 assert(fd.fbody);
3788 }
3789
equals(const RootObject o)3790 override bool equals(const RootObject o) const
3791 {
3792 if (this == o)
3793 return true;
3794 auto e = o.isExpression();
3795 if (!e)
3796 return false;
3797 if (auto fe = e.isFuncExp())
3798 {
3799 return fd == fe.fd;
3800 }
3801 return false;
3802 }
3803
genIdent(Scope * sc)3804 extern (D) void genIdent(Scope* sc)
3805 {
3806 if (fd.ident == Id.empty)
3807 {
3808 const(char)[] s;
3809 if (fd.fes)
3810 s = "__foreachbody";
3811 else if (fd.tok == TOK.reserved)
3812 s = "__lambda";
3813 else if (fd.tok == TOK.delegate_)
3814 s = "__dgliteral";
3815 else
3816 s = "__funcliteral";
3817
3818 DsymbolTable symtab;
3819 if (FuncDeclaration func = sc.parent.isFuncDeclaration())
3820 {
3821 if (func.localsymtab is null)
3822 {
3823 // Inside template constraint, symtab is not set yet.
3824 // Initialize it lazily.
3825 func.localsymtab = new DsymbolTable();
3826 }
3827 symtab = func.localsymtab;
3828 }
3829 else
3830 {
3831 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
3832 if (!sds.symtab)
3833 {
3834 // Inside template constraint, symtab may not be set yet.
3835 // Initialize it lazily.
3836 assert(sds.isTemplateInstance());
3837 sds.symtab = new DsymbolTable();
3838 }
3839 symtab = sds.symtab;
3840 }
3841 assert(symtab);
3842 Identifier id = Identifier.generateId(s, symtab.length() + 1);
3843 fd.ident = id;
3844 if (td)
3845 td.ident = id;
3846 symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd);
3847 }
3848 }
3849
syntaxCopy()3850 override FuncExp syntaxCopy()
3851 {
3852 if (td)
3853 return new FuncExp(loc, td.syntaxCopy(null));
3854 else if (fd.semanticRun == PASS.initial)
3855 return new FuncExp(loc, fd.syntaxCopy(null));
3856 else // https://issues.dlang.org/show_bug.cgi?id=13481
3857 // Prevent multiple semantic analysis of lambda body.
3858 return new FuncExp(loc, fd);
3859 }
3860
3861 extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0)
3862 {
3863
cannotInfer(Expression e,Type to,int flag)3864 static MATCH cannotInfer(Expression e, Type to, int flag)
3865 {
3866 if (!flag)
3867 e.error("cannot infer parameter types from `%s`", to.toChars());
3868 return MATCH.nomatch;
3869 }
3870
3871 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
3872 if (presult)
3873 *presult = null;
3874
3875 TypeFunction tof = null;
3876 if (to.ty == Tdelegate)
3877 {
3878 if (tok == TOK.function_)
3879 {
3880 if (!flag)
3881 error("cannot match function literal to delegate type `%s`", to.toChars());
3882 return MATCH.nomatch;
3883 }
3884 tof = cast(TypeFunction)to.nextOf();
3885 }
3886 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
3887 {
3888 if (tok == TOK.delegate_)
3889 {
3890 if (!flag)
3891 error("cannot match delegate literal to function pointer type `%s`", to.toChars());
3892 return MATCH.nomatch;
3893 }
3894 }
3895
3896 if (td)
3897 {
3898 if (!tof)
3899 {
3900 return cannotInfer(this, to, flag);
3901 }
3902
3903 // Parameter types inference from 'tof'
3904 assert(td._scope);
3905 TypeFunction tf = fd.type.isTypeFunction();
3906 //printf("\ttof = %s\n", tof.toChars());
3907 //printf("\ttf = %s\n", tf.toChars());
3908 const dim = tf.parameterList.length;
3909
3910 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
3911 return cannotInfer(this, to, flag);
3912
3913 auto tiargs = new Objects();
3914 tiargs.reserve(td.parameters.dim);
3915
3916 foreach (tp; *td.parameters)
3917 {
3918 size_t u = 0;
3919 foreach (i, p; tf.parameterList)
3920 {
3921 if (auto ti = p.type.isTypeIdentifier())
3922 if (ti && ti.ident == tp.ident)
3923 break;
3924
3925 ++u;
3926 }
3927 assert(u < dim);
3928 Parameter pto = tof.parameterList[u];
3929 Type t = pto.type;
3930 if (t.ty == Terror)
3931 return cannotInfer(this, to, flag);
3932 tiargs.push(t);
3933 }
3934
3935 // Set target of return type inference
3936 if (!tf.next && tof.next)
3937 fd.treq = to;
3938
3939 auto ti = new TemplateInstance(loc, td, tiargs);
3940 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
3941
3942 // Reset inference target for the later re-semantic
3943 fd.treq = null;
3944
3945 if (ex.op == EXP.error)
3946 return MATCH.nomatch;
3947 if (auto ef = ex.isFuncExp())
3948 return ef.matchType(to, sc, presult, flag);
3949 else
3950 return cannotInfer(this, to, flag);
3951 }
3952
3953 if (!tof || !tof.next)
3954 return MATCH.nomatch;
3955
3956 assert(type && type != Type.tvoid);
3957 if (fd.type.ty == Terror)
3958 return MATCH.nomatch;
3959 auto tfx = fd.type.isTypeFunction();
3960 bool convertMatch = (type.ty != to.ty);
3961
3962 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
3963 {
3964 /* If return type is inferred and covariant return,
3965 * tweak return statements to required return type.
3966 *
3967 * interface I {}
3968 * class C : Object, I{}
3969 *
3970 * I delegate() dg = delegate() { return new class C(); }
3971 */
3972 convertMatch = true;
3973
3974 auto tfy = new TypeFunction(tfx.parameterList, tof.next,
3975 tfx.linkage, STC.undefined_);
3976 tfy.mod = tfx.mod;
3977 tfy.trust = tfx.trust;
3978 tfy.isnothrow = tfx.isnothrow;
3979 tfy.isnogc = tfx.isnogc;
3980 tfy.purity = tfx.purity;
3981 tfy.isproperty = tfx.isproperty;
3982 tfy.isref = tfx.isref;
3983 tfy.isInOutParam = tfx.isInOutParam;
3984 tfy.isInOutQual = tfx.isInOutQual;
3985 tfy.deco = tfy.merge().deco;
3986
3987 tfx = tfy;
3988 }
3989 Type tx;
3990 if (tok == TOK.delegate_ ||
3991 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
3992 {
3993 // Allow conversion from implicit function pointer to delegate
3994 tx = new TypeDelegate(tfx);
3995 tx.deco = tx.merge().deco;
3996 }
3997 else
3998 {
3999 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
4000 tx = tfx.pointerTo();
4001 }
4002 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
4003
4004 MATCH m = tx.implicitConvTo(to);
4005 if (m > MATCH.nomatch)
4006 {
4007 // MATCH.exact: exact type match
4008 // MATCH.constant: covairiant type match (eg. attributes difference)
4009 // MATCH.convert: context conversion
4010 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
4011
4012 if (presult)
4013 {
4014 (*presult) = cast(FuncExp)copy();
4015 (*presult).type = to;
4016
4017 // https://issues.dlang.org/show_bug.cgi?id=12508
4018 // Tweak function body for covariant returns.
4019 (*presult).fd.modifyReturns(sc, tof.next);
4020 }
4021 }
4022 else if (!flag)
4023 {
4024 auto ts = toAutoQualChars(tx, to);
4025 error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
4026 toChars(), ts[0], ts[1]);
4027 }
4028 return m;
4029 }
4030
toChars()4031 override const(char)* toChars() const
4032 {
4033 return fd.toChars();
4034 }
4035
checkType()4036 override bool checkType()
4037 {
4038 if (td)
4039 {
4040 error("template lambda has no type");
4041 return true;
4042 }
4043 return false;
4044 }
4045
checkValue()4046 override bool checkValue()
4047 {
4048 if (td)
4049 {
4050 error("template lambda has no value");
4051 return true;
4052 }
4053 return false;
4054 }
4055
accept(Visitor v)4056 override void accept(Visitor v)
4057 {
4058 v.visit(this);
4059 }
4060 }
4061
4062 /***********************************************************
4063 * Declaration of a symbol
4064 *
4065 * D grammar allows declarations only as statements. However in AST representation
4066 * it can be part of any expression. This is used, for example, during internal
4067 * syntax re-writes to inject hidden symbols.
4068 */
4069 extern (C++) final class DeclarationExp : Expression
4070 {
4071 Dsymbol declaration;
4072
this(const ref Loc loc,Dsymbol declaration)4073 extern (D) this(const ref Loc loc, Dsymbol declaration)
4074 {
4075 super(loc, EXP.declaration, __traits(classInstanceSize, DeclarationExp));
4076 this.declaration = declaration;
4077 }
4078
syntaxCopy()4079 override DeclarationExp syntaxCopy()
4080 {
4081 return new DeclarationExp(loc, declaration.syntaxCopy(null));
4082 }
4083
hasCode()4084 override bool hasCode()
4085 {
4086 if (auto vd = declaration.isVarDeclaration())
4087 {
4088 return !(vd.storage_class & (STC.manifest | STC.static_));
4089 }
4090 return false;
4091 }
4092
accept(Visitor v)4093 override void accept(Visitor v)
4094 {
4095 v.visit(this);
4096 }
4097 }
4098
4099 /***********************************************************
4100 * typeid(int)
4101 */
4102 extern (C++) final class TypeidExp : Expression
4103 {
4104 RootObject obj;
4105
this(const ref Loc loc,RootObject o)4106 extern (D) this(const ref Loc loc, RootObject o)
4107 {
4108 super(loc, EXP.typeid_, __traits(classInstanceSize, TypeidExp));
4109 this.obj = o;
4110 }
4111
syntaxCopy()4112 override TypeidExp syntaxCopy()
4113 {
4114 return new TypeidExp(loc, objectSyntaxCopy(obj));
4115 }
4116
accept(Visitor v)4117 override void accept(Visitor v)
4118 {
4119 v.visit(this);
4120 }
4121 }
4122
4123 /***********************************************************
4124 * __traits(identifier, args...)
4125 */
4126 extern (C++) final class TraitsExp : Expression
4127 {
4128 Identifier ident;
4129 Objects* args;
4130
this(const ref Loc loc,Identifier ident,Objects * args)4131 extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
4132 {
4133 super(loc, EXP.traits, __traits(classInstanceSize, TraitsExp));
4134 this.ident = ident;
4135 this.args = args;
4136 }
4137
syntaxCopy()4138 override TraitsExp syntaxCopy()
4139 {
4140 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
4141 }
4142
accept(Visitor v)4143 override void accept(Visitor v)
4144 {
4145 v.visit(this);
4146 }
4147 }
4148
4149 /***********************************************************
4150 * Generates a halt instruction
4151 *
4152 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
4153 */
4154 extern (C++) final class HaltExp : Expression
4155 {
this(const ref Loc loc)4156 extern (D) this(const ref Loc loc)
4157 {
4158 super(loc, EXP.halt, __traits(classInstanceSize, HaltExp));
4159 }
4160
accept(Visitor v)4161 override void accept(Visitor v)
4162 {
4163 v.visit(this);
4164 }
4165 }
4166
4167 /***********************************************************
4168 * is(targ id tok tspec)
4169 * is(targ id == tok2)
4170 */
4171 extern (C++) final class IsExp : Expression
4172 {
4173 Type targ;
4174 Identifier id; // can be null
4175 Type tspec; // can be null
4176 TemplateParameters* parameters;
4177 TOK tok; // ':' or '=='
4178 TOK tok2; // 'struct', 'union', etc.
4179
this(const ref Loc loc,Type targ,Identifier id,TOK tok,Type tspec,TOK tok2,TemplateParameters * parameters)4180 extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
4181 {
4182 super(loc, EXP.is_, __traits(classInstanceSize, IsExp));
4183 this.targ = targ;
4184 this.id = id;
4185 this.tok = tok;
4186 this.tspec = tspec;
4187 this.tok2 = tok2;
4188 this.parameters = parameters;
4189 }
4190
syntaxCopy()4191 override IsExp syntaxCopy()
4192 {
4193 // This section is identical to that in TemplateDeclaration::syntaxCopy()
4194 TemplateParameters* p = null;
4195 if (parameters)
4196 {
4197 p = new TemplateParameters(parameters.dim);
4198 foreach (i, el; *parameters)
4199 (*p)[i] = el.syntaxCopy();
4200 }
4201 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
4202 }
4203
accept(Visitor v)4204 override void accept(Visitor v)
4205 {
4206 v.visit(this);
4207 }
4208 }
4209
4210 /***********************************************************
4211 * Base class for unary operators
4212 *
4213 * https://dlang.org/spec/expression.html#unary-expression
4214 */
4215 extern (C++) abstract class UnaExp : Expression
4216 {
4217 Expression e1;
4218 Type att1; // Save alias this type to detect recursion
4219
this(const ref Loc loc,EXP op,int size,Expression e1)4220 extern (D) this(const ref Loc loc, EXP op, int size, Expression e1)
4221 {
4222 super(loc, op, size);
4223 this.e1 = e1;
4224 }
4225
syntaxCopy()4226 override UnaExp syntaxCopy()
4227 {
4228 UnaExp e = cast(UnaExp)copy();
4229 e.type = null;
4230 e.e1 = e.e1.syntaxCopy();
4231 return e;
4232 }
4233
4234 /********************************
4235 * The type for a unary expression is incompatible.
4236 * Print error message.
4237 * Returns:
4238 * ErrorExp
4239 */
incompatibleTypes()4240 final Expression incompatibleTypes()
4241 {
4242 if (e1.type.toBasetype() == Type.terror)
4243 return e1;
4244
4245 if (e1.op == EXP.type)
4246 {
4247 error("incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
4248 }
4249 else
4250 {
4251 error("incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
4252 }
4253 return ErrorExp.get();
4254 }
4255
4256 /*********************
4257 * Mark the operand as will never be dereferenced,
4258 * which is useful info for @safe checks.
4259 * Do before semantic() on operands rewrites them.
4260 */
setNoderefOperand()4261 final void setNoderefOperand()
4262 {
4263 if (auto edi = e1.isDotIdExp())
4264 edi.noderef = true;
4265
4266 }
4267
resolveLoc(const ref Loc loc,Scope * sc)4268 override final Expression resolveLoc(const ref Loc loc, Scope* sc)
4269 {
4270 e1 = e1.resolveLoc(loc, sc);
4271 return this;
4272 }
4273
accept(Visitor v)4274 override void accept(Visitor v)
4275 {
4276 v.visit(this);
4277 }
4278 }
4279
4280 alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
4281 alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression);
4282
4283 /***********************************************************
4284 * Base class for binary operators
4285 */
4286 extern (C++) abstract class BinExp : Expression
4287 {
4288 Expression e1;
4289 Expression e2;
4290 Type att1; // Save alias this type to detect recursion
4291 Type att2; // Save alias this type to detect recursion
4292
this(const ref Loc loc,EXP op,int size,Expression e1,Expression e2)4293 extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
4294 {
4295 super(loc, op, size);
4296 this.e1 = e1;
4297 this.e2 = e2;
4298 }
4299
syntaxCopy()4300 override BinExp syntaxCopy()
4301 {
4302 BinExp e = cast(BinExp)copy();
4303 e.type = null;
4304 e.e1 = e.e1.syntaxCopy();
4305 e.e2 = e.e2.syntaxCopy();
4306 return e;
4307 }
4308
4309 /********************************
4310 * The types for a binary expression are incompatible.
4311 * Print error message.
4312 * Returns:
4313 * ErrorExp
4314 */
incompatibleTypes()4315 final Expression incompatibleTypes()
4316 {
4317 if (e1.type.toBasetype() == Type.terror)
4318 return e1;
4319 if (e2.type.toBasetype() == Type.terror)
4320 return e2;
4321
4322 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
4323 const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
4324 if (e1.op == EXP.type || e2.op == EXP.type)
4325 {
4326 error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
4327 e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
4328 }
4329 else if (e1.type.equals(e2.type))
4330 {
4331 error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
4332 e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
4333 }
4334 else
4335 {
4336 auto ts = toAutoQualChars(e1.type, e2.type);
4337 error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
4338 e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
4339 }
4340 return ErrorExp.get();
4341 }
4342
checkOpAssignTypes(Scope * sc)4343 extern (D) final Expression checkOpAssignTypes(Scope* sc)
4344 {
4345 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
4346 Type t1 = e1.type;
4347 Type t2 = e2.type;
4348
4349 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
4350 // See issue 3841.
4351 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
4352 if (op == EXP.addAssign || op == EXP.minAssign ||
4353 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
4354 op == EXP.powAssign)
4355 {
4356 if ((type.isintegral() && t2.isfloating()))
4357 {
4358 warning("`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
4359 }
4360 }
4361
4362 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
4363 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
4364 {
4365 // Any multiplication by an imaginary or complex number yields a complex result.
4366 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
4367 const(char)* opstr = EXPtoString(op).ptr;
4368 if (t1.isreal() && t2.iscomplex())
4369 {
4370 error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4371 return ErrorExp.get();
4372 }
4373 else if (t1.isimaginary() && t2.iscomplex())
4374 {
4375 error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4376 return ErrorExp.get();
4377 }
4378 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
4379 {
4380 error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
4381 return ErrorExp.get();
4382 }
4383 }
4384
4385 // generate an error if this is a nonsensical += or -=, eg real += imaginary
4386 if (op == EXP.addAssign || op == EXP.minAssign)
4387 {
4388 // Addition or subtraction of a real and an imaginary is a complex result.
4389 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
4390 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
4391 {
4392 error("`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
4393 return ErrorExp.get();
4394 }
4395 if (type.isreal() || type.isimaginary())
4396 {
4397 assert(global.errors || t2.isfloating());
4398 e2 = e2.castTo(sc, t1);
4399 }
4400 }
4401 if (op == EXP.mulAssign)
4402 {
4403 if (t2.isfloating())
4404 {
4405 if (t1.isreal())
4406 {
4407 if (t2.isimaginary() || t2.iscomplex())
4408 {
4409 e2 = e2.castTo(sc, t1);
4410 }
4411 }
4412 else if (t1.isimaginary())
4413 {
4414 if (t2.isimaginary() || t2.iscomplex())
4415 {
4416 switch (t1.ty)
4417 {
4418 case Timaginary32:
4419 t2 = Type.tfloat32;
4420 break;
4421
4422 case Timaginary64:
4423 t2 = Type.tfloat64;
4424 break;
4425
4426 case Timaginary80:
4427 t2 = Type.tfloat80;
4428 break;
4429
4430 default:
4431 assert(0);
4432 }
4433 e2 = e2.castTo(sc, t2);
4434 }
4435 }
4436 }
4437 }
4438 else if (op == EXP.divAssign)
4439 {
4440 if (t2.isimaginary())
4441 {
4442 if (t1.isreal())
4443 {
4444 // x/iv = i(-x/v)
4445 // Therefore, the result is 0
4446 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
4447 e2.type = t1;
4448 Expression e = new AssignExp(loc, e1, e2);
4449 e.type = t1;
4450 return e;
4451 }
4452 else if (t1.isimaginary())
4453 {
4454 Type t3;
4455 switch (t1.ty)
4456 {
4457 case Timaginary32:
4458 t3 = Type.tfloat32;
4459 break;
4460
4461 case Timaginary64:
4462 t3 = Type.tfloat64;
4463 break;
4464
4465 case Timaginary80:
4466 t3 = Type.tfloat80;
4467 break;
4468
4469 default:
4470 assert(0);
4471 }
4472 e2 = e2.castTo(sc, t3);
4473 Expression e = new AssignExp(loc, e1, e2);
4474 e.type = t1;
4475 return e;
4476 }
4477 }
4478 }
4479 else if (op == EXP.modAssign)
4480 {
4481 if (t2.iscomplex())
4482 {
4483 error("cannot perform modulo complex arithmetic");
4484 return ErrorExp.get();
4485 }
4486 }
4487 return this;
4488 }
4489
checkIntegralBin()4490 extern (D) final bool checkIntegralBin()
4491 {
4492 bool r1 = e1.checkIntegral();
4493 bool r2 = e2.checkIntegral();
4494 return (r1 || r2);
4495 }
4496
checkArithmeticBin()4497 extern (D) final bool checkArithmeticBin()
4498 {
4499 bool r1 = e1.checkArithmetic();
4500 bool r2 = e2.checkArithmetic();
4501 return (r1 || r2);
4502 }
4503
checkSharedAccessBin(Scope * sc)4504 extern (D) final bool checkSharedAccessBin(Scope* sc)
4505 {
4506 const r1 = e1.checkSharedAccess(sc);
4507 const r2 = e2.checkSharedAccess(sc);
4508 return (r1 || r2);
4509 }
4510
4511 /*********************
4512 * Mark the operands as will never be dereferenced,
4513 * which is useful info for @safe checks.
4514 * Do before semantic() on operands rewrites them.
4515 */
setNoderefOperands()4516 final void setNoderefOperands()
4517 {
4518 if (auto edi = e1.isDotIdExp())
4519 edi.noderef = true;
4520 if (auto edi = e2.isDotIdExp())
4521 edi.noderef = true;
4522
4523 }
4524
reorderSettingAAElem(Scope * sc)4525 final Expression reorderSettingAAElem(Scope* sc)
4526 {
4527 BinExp be = this;
4528
4529 auto ie = be.e1.isIndexExp();
4530 if (!ie)
4531 return be;
4532 if (ie.e1.type.toBasetype().ty != Taarray)
4533 return be;
4534
4535 /* Fix evaluation order of setting AA element
4536 * https://issues.dlang.org/show_bug.cgi?id=3825
4537 * Rewrite:
4538 * aa[k1][k2][k3] op= val;
4539 * as:
4540 * auto ref __aatmp = aa;
4541 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
4542 * auto ref __aaval = val;
4543 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
4544 */
4545
4546 Expression e0;
4547 while (1)
4548 {
4549 Expression de;
4550 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
4551 e0 = Expression.combine(de, e0);
4552
4553 auto ie1 = ie.e1.isIndexExp();
4554 if (!ie1 ||
4555 ie1.e1.type.toBasetype().ty != Taarray)
4556 {
4557 break;
4558 }
4559 ie = ie1;
4560 }
4561 assert(ie.e1.type.toBasetype().ty == Taarray);
4562
4563 Expression de;
4564 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
4565 e0 = Expression.combine(de, e0);
4566
4567 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
4568
4569 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
4570 return Expression.combine(e0, be);
4571 }
4572
accept(Visitor v)4573 override void accept(Visitor v)
4574 {
4575 v.visit(this);
4576 }
4577 }
4578
4579 /***********************************************************
4580 * Binary operator assignment, `+=` `-=` `*=` etc.
4581 */
4582 extern (C++) class BinAssignExp : BinExp
4583 {
this(const ref Loc loc,EXP op,int size,Expression e1,Expression e2)4584 extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
4585 {
4586 super(loc, op, size, e1, e2);
4587 }
4588
isLvalue()4589 override final bool isLvalue()
4590 {
4591 return true;
4592 }
4593
toLvalue(Scope * sc,Expression ex)4594 override final Expression toLvalue(Scope* sc, Expression ex)
4595 {
4596 // Lvalue-ness will be handled in glue layer.
4597 return this;
4598 }
4599
modifiableLvalue(Scope * sc,Expression e)4600 override final Expression modifiableLvalue(Scope* sc, Expression e)
4601 {
4602 // should check e1.checkModifiable() ?
4603 return toLvalue(sc, this);
4604 }
4605
accept(Visitor v)4606 override void accept(Visitor v)
4607 {
4608 v.visit(this);
4609 }
4610 }
4611
4612 /***********************************************************
4613 * A string mixin, `mixin("x")`
4614 *
4615 * https://dlang.org/spec/expression.html#mixin_expressions
4616 */
4617 extern (C++) final class MixinExp : Expression
4618 {
4619 Expressions* exps;
4620
this(const ref Loc loc,Expressions * exps)4621 extern (D) this(const ref Loc loc, Expressions* exps)
4622 {
4623 super(loc, EXP.mixin_, __traits(classInstanceSize, MixinExp));
4624 this.exps = exps;
4625 }
4626
syntaxCopy()4627 override MixinExp syntaxCopy()
4628 {
4629 return new MixinExp(loc, arraySyntaxCopy(exps));
4630 }
4631
equals(const RootObject o)4632 override bool equals(const RootObject o) const
4633 {
4634 if (this == o)
4635 return true;
4636 auto e = o.isExpression();
4637 if (!e)
4638 return false;
4639 if (auto ce = e.isMixinExp())
4640 {
4641 if (exps.dim != ce.exps.dim)
4642 return false;
4643 foreach (i, e1; *exps)
4644 {
4645 auto e2 = (*ce.exps)[i];
4646 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
4647 return false;
4648 }
4649 return true;
4650 }
4651 return false;
4652 }
4653
accept(Visitor v)4654 override void accept(Visitor v)
4655 {
4656 v.visit(this);
4657 }
4658 }
4659
4660 /***********************************************************
4661 * An import expression, `import("file.txt")`
4662 *
4663 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
4664 *
4665 * https://dlang.org/spec/expression.html#import_expressions
4666 */
4667 extern (C++) final class ImportExp : UnaExp
4668 {
this(const ref Loc loc,Expression e)4669 extern (D) this(const ref Loc loc, Expression e)
4670 {
4671 super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e);
4672 }
4673
accept(Visitor v)4674 override void accept(Visitor v)
4675 {
4676 v.visit(this);
4677 }
4678 }
4679
4680 /***********************************************************
4681 * An assert expression, `assert(x == y)`
4682 *
4683 * https://dlang.org/spec/expression.html#assert_expressions
4684 */
4685 extern (C++) final class AssertExp : UnaExp
4686 {
4687 Expression msg;
4688
4689 extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
4690 {
4691 super(loc, EXP.assert_, __traits(classInstanceSize, AssertExp), e);
4692 this.msg = msg;
4693 }
4694
syntaxCopy()4695 override AssertExp syntaxCopy()
4696 {
4697 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
4698 }
4699
accept(Visitor v)4700 override void accept(Visitor v)
4701 {
4702 v.visit(this);
4703 }
4704 }
4705
4706 /***********************************************************
4707 * `throw <e1>` as proposed by DIP 1034.
4708 *
4709 * Replacement for the deprecated `ThrowStatement` that can be nested
4710 * in other expression.
4711 */
4712 extern (C++) final class ThrowExp : UnaExp
4713 {
this(const ref Loc loc,Expression e)4714 extern (D) this(const ref Loc loc, Expression e)
4715 {
4716 super(loc, EXP.throw_, __traits(classInstanceSize, ThrowExp), e);
4717 this.type = Type.tnoreturn;
4718 }
4719
syntaxCopy()4720 override ThrowExp syntaxCopy()
4721 {
4722 return new ThrowExp(loc, e1.syntaxCopy());
4723 }
4724
accept(Visitor v)4725 override void accept(Visitor v)
4726 {
4727 v.visit(this);
4728 }
4729 }
4730
4731 /***********************************************************
4732 */
4733 extern (C++) final class DotIdExp : UnaExp
4734 {
4735 Identifier ident;
4736 bool noderef; // true if the result of the expression will never be dereferenced
4737 bool wantsym; // do not replace Symbol with its initializer during semantic()
4738 bool arrow; // ImportC: if -> instead of .
4739
this(const ref Loc loc,Expression e,Identifier ident)4740 extern (D) this(const ref Loc loc, Expression e, Identifier ident)
4741 {
4742 super(loc, EXP.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
4743 this.ident = ident;
4744 }
4745
create(const ref Loc loc,Expression e,Identifier ident)4746 static DotIdExp create(const ref Loc loc, Expression e, Identifier ident)
4747 {
4748 return new DotIdExp(loc, e, ident);
4749 }
4750
accept(Visitor v)4751 override void accept(Visitor v)
4752 {
4753 v.visit(this);
4754 }
4755 }
4756
4757 /***********************************************************
4758 * Mainly just a placeholder
4759 */
4760 extern (C++) final class DotTemplateExp : UnaExp
4761 {
4762 TemplateDeclaration td;
4763
this(const ref Loc loc,Expression e,TemplateDeclaration td)4764 extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
4765 {
4766 super(loc, EXP.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
4767 this.td = td;
4768 }
4769
checkType()4770 override bool checkType()
4771 {
4772 error("%s `%s` has no type", td.kind(), toChars());
4773 return true;
4774 }
4775
checkValue()4776 override bool checkValue()
4777 {
4778 error("%s `%s` has no value", td.kind(), toChars());
4779 return true;
4780 }
4781
accept(Visitor v)4782 override void accept(Visitor v)
4783 {
4784 v.visit(this);
4785 }
4786 }
4787
4788 /***********************************************************
4789 */
4790 extern (C++) final class DotVarExp : UnaExp
4791 {
4792 Declaration var;
4793 bool hasOverloads;
4794
4795 extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true)
4796 {
4797 if (var.isVarDeclaration())
4798 hasOverloads = false;
4799
4800 super(loc, EXP.dotVariable, __traits(classInstanceSize, DotVarExp), e);
4801 //printf("DotVarExp()\n");
4802 this.var = var;
4803 this.hasOverloads = hasOverloads;
4804 }
4805
isLvalue()4806 override bool isLvalue()
4807 {
4808 if (e1.op != EXP.structLiteral)
4809 return true;
4810 auto vd = var.isVarDeclaration();
4811 return !(vd && vd.isField());
4812 }
4813
toLvalue(Scope * sc,Expression e)4814 override Expression toLvalue(Scope* sc, Expression e)
4815 {
4816 //printf("DotVarExp::toLvalue(%s)\n", toChars());
4817 if (sc && sc.flags & SCOPE.Cfile)
4818 {
4819 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
4820 * is an lvalue if the first expression is an lvalue.
4821 */
4822 if (!e1.isLvalue())
4823 return Expression.toLvalue(sc, e);
4824 }
4825 if (!isLvalue())
4826 return Expression.toLvalue(sc, e);
4827 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
4828 {
4829 if (VarDeclaration vd = var.isVarDeclaration())
4830 {
4831 auto ad = vd.isMember2();
4832 if (ad && ad.fields.dim == sc.ctorflow.fieldinit.length)
4833 {
4834 foreach (i, f; ad.fields)
4835 {
4836 if (f == vd)
4837 {
4838 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
4839 {
4840 /* If the address of vd is taken, assume it is thereby initialized
4841 * https://issues.dlang.org/show_bug.cgi?id=15869
4842 */
4843 modifyFieldVar(loc, sc, vd, e1);
4844 }
4845 break;
4846 }
4847 }
4848 }
4849 }
4850 }
4851 return this;
4852 }
4853
modifiableLvalue(Scope * sc,Expression e)4854 override Expression modifiableLvalue(Scope* sc, Expression e)
4855 {
4856 version (none)
4857 {
4858 printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
4859 printf("e1.type = %s\n", e1.type.toChars());
4860 printf("var.type = %s\n", var.type.toChars());
4861 }
4862
4863 return Expression.modifiableLvalue(sc, e);
4864 }
4865
accept(Visitor v)4866 override void accept(Visitor v)
4867 {
4868 v.visit(this);
4869 }
4870 }
4871
4872 /***********************************************************
4873 * foo.bar!(args)
4874 */
4875 extern (C++) final class DotTemplateInstanceExp : UnaExp
4876 {
4877 TemplateInstance ti;
4878
this(const ref Loc loc,Expression e,Identifier name,Objects * tiargs)4879 extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
4880 {
4881 super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
4882 //printf("DotTemplateInstanceExp()\n");
4883 this.ti = new TemplateInstance(loc, name, tiargs);
4884 }
4885
this(const ref Loc loc,Expression e,TemplateInstance ti)4886 extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
4887 {
4888 super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
4889 this.ti = ti;
4890 }
4891
syntaxCopy()4892 override DotTemplateInstanceExp syntaxCopy()
4893 {
4894 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
4895 }
4896
findTempDecl(Scope * sc)4897 bool findTempDecl(Scope* sc)
4898 {
4899 static if (LOGSEMANTIC)
4900 {
4901 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
4902 }
4903 if (ti.tempdecl)
4904 return true;
4905
4906 Expression e = new DotIdExp(loc, e1, ti.name);
4907 e = e.expressionSemantic(sc);
4908 if (e.op == EXP.dot)
4909 e = (cast(DotExp)e).e2;
4910
4911 Dsymbol s = null;
4912 switch (e.op)
4913 {
4914 case EXP.overloadSet:
4915 s = (cast(OverExp)e).vars;
4916 break;
4917
4918 case EXP.dotTemplateDeclaration:
4919 s = (cast(DotTemplateExp)e).td;
4920 break;
4921
4922 case EXP.scope_:
4923 s = (cast(ScopeExp)e).sds;
4924 break;
4925
4926 case EXP.dotVariable:
4927 s = (cast(DotVarExp)e).var;
4928 break;
4929
4930 case EXP.variable:
4931 s = (cast(VarExp)e).var;
4932 break;
4933
4934 default:
4935 return false;
4936 }
4937 return ti.updateTempDecl(sc, s);
4938 }
4939
checkType()4940 override bool checkType()
4941 {
4942 // Same logic as ScopeExp.checkType()
4943 if (ti.tempdecl &&
4944 ti.semantictiargsdone &&
4945 ti.semanticRun == PASS.initial)
4946 {
4947 error("partial %s `%s` has no type", ti.kind(), toChars());
4948 return true;
4949 }
4950 return false;
4951 }
4952
checkValue()4953 override bool checkValue()
4954 {
4955 if (ti.tempdecl &&
4956 ti.semantictiargsdone &&
4957 ti.semanticRun == PASS.initial)
4958
4959 error("partial %s `%s` has no value", ti.kind(), toChars());
4960 else
4961 error("%s `%s` has no value", ti.kind(), ti.toChars());
4962 return true;
4963 }
4964
accept(Visitor v)4965 override void accept(Visitor v)
4966 {
4967 v.visit(this);
4968 }
4969 }
4970
4971 /***********************************************************
4972 */
4973 extern (C++) final class DelegateExp : UnaExp
4974 {
4975 FuncDeclaration func;
4976 bool hasOverloads;
4977 VarDeclaration vthis2; // container for multi-context
4978
4979 extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
4980 {
4981 super(loc, EXP.delegate_, __traits(classInstanceSize, DelegateExp), e);
4982 this.func = f;
4983 this.hasOverloads = hasOverloads;
4984 this.vthis2 = vthis2;
4985 }
4986
accept(Visitor v)4987 override void accept(Visitor v)
4988 {
4989 v.visit(this);
4990 }
4991 }
4992
4993 /***********************************************************
4994 */
4995 extern (C++) final class DotTypeExp : UnaExp
4996 {
4997 Dsymbol sym; // symbol that represents a type
4998
this(const ref Loc loc,Expression e,Dsymbol s)4999 extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
5000 {
5001 super(loc, EXP.dotType, __traits(classInstanceSize, DotTypeExp), e);
5002 this.sym = s;
5003 }
5004
accept(Visitor v)5005 override void accept(Visitor v)
5006 {
5007 v.visit(this);
5008 }
5009 }
5010
5011 /***********************************************************
5012 */
5013 extern (C++) final class CallExp : UnaExp
5014 {
5015 Expressions* arguments; // function arguments
5016 FuncDeclaration f; // symbol to call
5017 bool directcall; // true if a virtual call is devirtualized
5018 bool inDebugStatement; /// true if this was in a debug statement
5019 bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
5020 VarDeclaration vthis2; // container for multi-context
5021
this(const ref Loc loc,Expression e,Expressions * exps)5022 extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
5023 {
5024 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5025 this.arguments = exps;
5026 }
5027
this(const ref Loc loc,Expression e)5028 extern (D) this(const ref Loc loc, Expression e)
5029 {
5030 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5031 }
5032
this(const ref Loc loc,Expression e,Expression earg1)5033 extern (D) this(const ref Loc loc, Expression e, Expression earg1)
5034 {
5035 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5036 this.arguments = new Expressions();
5037 if (earg1)
5038 this.arguments.push(earg1);
5039 }
5040
this(const ref Loc loc,Expression e,Expression earg1,Expression earg2)5041 extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
5042 {
5043 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5044 auto arguments = new Expressions(2);
5045 (*arguments)[0] = earg1;
5046 (*arguments)[1] = earg2;
5047 this.arguments = arguments;
5048 }
5049
5050 /***********************************************************
5051 * Instatiates a new function call expression
5052 * Params:
5053 * loc = location
5054 * fd = the declaration of the function to call
5055 * earg1 = the function argument
5056 */
this(const ref Loc loc,FuncDeclaration fd,Expression earg1)5057 extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5058 {
5059 this(loc, new VarExp(loc, fd, false), earg1);
5060 this.f = fd;
5061 }
5062
create(const ref Loc loc,Expression e,Expressions * exps)5063 static CallExp create(const ref Loc loc, Expression e, Expressions* exps)
5064 {
5065 return new CallExp(loc, e, exps);
5066 }
5067
create(const ref Loc loc,Expression e)5068 static CallExp create(const ref Loc loc, Expression e)
5069 {
5070 return new CallExp(loc, e);
5071 }
5072
create(const ref Loc loc,Expression e,Expression earg1)5073 static CallExp create(const ref Loc loc, Expression e, Expression earg1)
5074 {
5075 return new CallExp(loc, e, earg1);
5076 }
5077
5078 /***********************************************************
5079 * Creates a new function call expression
5080 * Params:
5081 * loc = location
5082 * fd = the declaration of the function to call
5083 * earg1 = the function argument
5084 */
create(const ref Loc loc,FuncDeclaration fd,Expression earg1)5085 static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5086 {
5087 return new CallExp(loc, fd, earg1);
5088 }
5089
syntaxCopy()5090 override CallExp syntaxCopy()
5091 {
5092 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5093 }
5094
isLvalue()5095 override bool isLvalue()
5096 {
5097 Type tb = e1.type.toBasetype();
5098 if (tb.ty == Tdelegate || tb.ty == Tpointer)
5099 tb = tb.nextOf();
5100 auto tf = tb.isTypeFunction();
5101 if (tf && tf.isref)
5102 {
5103 if (auto dve = e1.isDotVarExp())
5104 if (dve.var.isCtorDeclaration())
5105 return false;
5106 return true; // function returns a reference
5107 }
5108 return false;
5109 }
5110
toLvalue(Scope * sc,Expression e)5111 override Expression toLvalue(Scope* sc, Expression e)
5112 {
5113 if (isLvalue())
5114 return this;
5115 return Expression.toLvalue(sc, e);
5116 }
5117
addDtorHook(Scope * sc)5118 override Expression addDtorHook(Scope* sc)
5119 {
5120 /* Only need to add dtor hook if it's a type that needs destruction.
5121 * Use same logic as VarDeclaration::callScopeDtor()
5122 */
5123
5124 if (auto tf = e1.type.isTypeFunction())
5125 {
5126 if (tf.isref)
5127 return this;
5128 }
5129
5130 Type tv = type.baseElemOf();
5131 if (auto ts = tv.isTypeStruct())
5132 {
5133 StructDeclaration sd = ts.sym;
5134 if (sd.dtor)
5135 {
5136 /* Type needs destruction, so declare a tmp
5137 * which the back end will recognize and call dtor on
5138 */
5139 auto tmp = copyToTemp(0, "__tmpfordtor", this);
5140 auto de = new DeclarationExp(loc, tmp);
5141 auto ve = new VarExp(loc, tmp);
5142 Expression e = new CommaExp(loc, de, ve);
5143 e = e.expressionSemantic(sc);
5144 return e;
5145 }
5146 }
5147 return this;
5148 }
5149
accept(Visitor v)5150 override void accept(Visitor v)
5151 {
5152 v.visit(this);
5153 }
5154 }
5155
5156 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null)
5157 {
5158 if (auto ae = e.isAddrExp())
5159 {
5160 auto ae1 = ae.e1;
5161 if (auto ve = ae1.isVarExp())
5162 {
5163 if (hasOverloads)
5164 *hasOverloads = ve.hasOverloads;
5165 return ve.var.isFuncDeclaration();
5166 }
5167 if (auto dve = ae1.isDotVarExp())
5168 {
5169 if (hasOverloads)
5170 *hasOverloads = dve.hasOverloads;
5171 return dve.var.isFuncDeclaration();
5172 }
5173 }
5174 else
5175 {
5176 if (auto soe = e.isSymOffExp())
5177 {
5178 if (hasOverloads)
5179 *hasOverloads = soe.hasOverloads;
5180 return soe.var.isFuncDeclaration();
5181 }
5182 if (auto dge = e.isDelegateExp())
5183 {
5184 if (hasOverloads)
5185 *hasOverloads = dge.hasOverloads;
5186 return dge.func.isFuncDeclaration();
5187 }
5188 }
5189 return null;
5190 }
5191
5192 /***********************************************************
5193 * The 'address of' operator, `&p`
5194 */
5195 extern (C++) final class AddrExp : UnaExp
5196 {
this(const ref Loc loc,Expression e)5197 extern (D) this(const ref Loc loc, Expression e)
5198 {
5199 super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e);
5200 }
5201
this(const ref Loc loc,Expression e,Type t)5202 extern (D) this(const ref Loc loc, Expression e, Type t)
5203 {
5204 this(loc, e);
5205 type = t;
5206 }
5207
accept(Visitor v)5208 override void accept(Visitor v)
5209 {
5210 v.visit(this);
5211 }
5212 }
5213
5214 /***********************************************************
5215 * The pointer dereference operator, `*p`
5216 */
5217 extern (C++) final class PtrExp : UnaExp
5218 {
this(const ref Loc loc,Expression e)5219 extern (D) this(const ref Loc loc, Expression e)
5220 {
5221 super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
5222 //if (e.type)
5223 // type = ((TypePointer *)e.type).next;
5224 }
5225
this(const ref Loc loc,Expression e,Type t)5226 extern (D) this(const ref Loc loc, Expression e, Type t)
5227 {
5228 super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
5229 type = t;
5230 }
5231
isLvalue()5232 override bool isLvalue()
5233 {
5234 return true;
5235 }
5236
toLvalue(Scope * sc,Expression e)5237 override Expression toLvalue(Scope* sc, Expression e)
5238 {
5239 return this;
5240 }
5241
modifiableLvalue(Scope * sc,Expression e)5242 override Expression modifiableLvalue(Scope* sc, Expression e)
5243 {
5244 //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
5245 Declaration var;
5246 if (auto se = e1.isSymOffExp())
5247 var = se.var;
5248 else if (auto ve = e1.isVarExp())
5249 var = ve.var;
5250 if (var && var.type.isFunction_Delegate_PtrToFunction())
5251 {
5252 if (var.type.isTypeFunction())
5253 error("function `%s` is not an lvalue and cannot be modified", var.toChars());
5254 else
5255 error("function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
5256 return ErrorExp.get();
5257 }
5258 return Expression.modifiableLvalue(sc, e);
5259 }
5260
accept(Visitor v)5261 override void accept(Visitor v)
5262 {
5263 v.visit(this);
5264 }
5265 }
5266
5267 /***********************************************************
5268 * The negation operator, `-x`
5269 */
5270 extern (C++) final class NegExp : UnaExp
5271 {
this(const ref Loc loc,Expression e)5272 extern (D) this(const ref Loc loc, Expression e)
5273 {
5274 super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e);
5275 }
5276
accept(Visitor v)5277 override void accept(Visitor v)
5278 {
5279 v.visit(this);
5280 }
5281 }
5282
5283 /***********************************************************
5284 * The unary add operator, `+x`
5285 */
5286 extern (C++) final class UAddExp : UnaExp
5287 {
this(const ref Loc loc,Expression e)5288 extern (D) this(const ref Loc loc, Expression e)
5289 {
5290 super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e);
5291 }
5292
accept(Visitor v)5293 override void accept(Visitor v)
5294 {
5295 v.visit(this);
5296 }
5297 }
5298
5299 /***********************************************************
5300 * The bitwise complement operator, `~x`
5301 */
5302 extern (C++) final class ComExp : UnaExp
5303 {
this(const ref Loc loc,Expression e)5304 extern (D) this(const ref Loc loc, Expression e)
5305 {
5306 super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e);
5307 }
5308
accept(Visitor v)5309 override void accept(Visitor v)
5310 {
5311 v.visit(this);
5312 }
5313 }
5314
5315 /***********************************************************
5316 * The logical not operator, `!x`
5317 */
5318 extern (C++) final class NotExp : UnaExp
5319 {
this(const ref Loc loc,Expression e)5320 extern (D) this(const ref Loc loc, Expression e)
5321 {
5322 super(loc, EXP.not, __traits(classInstanceSize, NotExp), e);
5323 }
5324
accept(Visitor v)5325 override void accept(Visitor v)
5326 {
5327 v.visit(this);
5328 }
5329 }
5330
5331 /***********************************************************
5332 * The delete operator, `delete x` (deprecated)
5333 *
5334 * https://dlang.org/spec/expression.html#delete_expressions
5335 */
5336 extern (C++) final class DeleteExp : UnaExp
5337 {
5338 bool isRAII; // true if called automatically as a result of scoped destruction
5339
this(const ref Loc loc,Expression e,bool isRAII)5340 extern (D) this(const ref Loc loc, Expression e, bool isRAII)
5341 {
5342 super(loc, EXP.delete_, __traits(classInstanceSize, DeleteExp), e);
5343 this.isRAII = isRAII;
5344 }
5345
accept(Visitor v)5346 override void accept(Visitor v)
5347 {
5348 v.visit(this);
5349 }
5350 }
5351
5352 /***********************************************************
5353 * The type cast operator, `cast(T) x`
5354 *
5355 * It's possible to cast to one type while painting to another type
5356 *
5357 * https://dlang.org/spec/expression.html#cast_expressions
5358 */
5359 extern (C++) final class CastExp : UnaExp
5360 {
5361 Type to; // type to cast to
5362 ubyte mod = cast(ubyte)~0; // MODxxxxx
5363
this(const ref Loc loc,Expression e,Type t)5364 extern (D) this(const ref Loc loc, Expression e, Type t)
5365 {
5366 super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
5367 this.to = t;
5368 }
5369
5370 /* For cast(const) and cast(immutable)
5371 */
this(const ref Loc loc,Expression e,ubyte mod)5372 extern (D) this(const ref Loc loc, Expression e, ubyte mod)
5373 {
5374 super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
5375 this.mod = mod;
5376 }
5377
syntaxCopy()5378 override CastExp syntaxCopy()
5379 {
5380 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
5381 }
5382
isLvalue()5383 override bool isLvalue()
5384 {
5385 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
5386 if (!e1.isLvalue())
5387 return false;
5388 return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
5389 e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
5390 }
5391
toLvalue(Scope * sc,Expression e)5392 override Expression toLvalue(Scope* sc, Expression e)
5393 {
5394 if (sc && sc.flags & SCOPE.Cfile)
5395 {
5396 /* C11 6.5.4-5: A cast does not yield an lvalue.
5397 */
5398 return Expression.toLvalue(sc, e);
5399 }
5400 if (isLvalue())
5401 return this;
5402 return Expression.toLvalue(sc, e);
5403 }
5404
addDtorHook(Scope * sc)5405 override Expression addDtorHook(Scope* sc)
5406 {
5407 if (to.toBasetype().ty == Tvoid) // look past the cast(void)
5408 e1 = e1.addDtorHook(sc);
5409 return this;
5410 }
5411
accept(Visitor v)5412 override void accept(Visitor v)
5413 {
5414 v.visit(this);
5415 }
5416 }
5417
5418 /***********************************************************
5419 */
5420 extern (C++) final class VectorExp : UnaExp
5421 {
5422 TypeVector to; // the target vector type before semantic()
5423 uint dim = ~0; // number of elements in the vector
5424 OwnedBy ownedByCtfe = OwnedBy.code;
5425
this(const ref Loc loc,Expression e,Type t)5426 extern (D) this(const ref Loc loc, Expression e, Type t)
5427 {
5428 super(loc, EXP.vector, __traits(classInstanceSize, VectorExp), e);
5429 assert(t.ty == Tvector);
5430 to = cast(TypeVector)t;
5431 }
5432
create(const ref Loc loc,Expression e,Type t)5433 static VectorExp create(const ref Loc loc, Expression e, Type t)
5434 {
5435 return new VectorExp(loc, e, t);
5436 }
5437
5438 // Same as create, but doesn't allocate memory.
emplace(UnionExp * pue,const ref Loc loc,Expression e,Type type)5439 static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type)
5440 {
5441 emplaceExp!(VectorExp)(pue, loc, e, type);
5442 }
5443
syntaxCopy()5444 override VectorExp syntaxCopy()
5445 {
5446 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
5447 }
5448
accept(Visitor v)5449 override void accept(Visitor v)
5450 {
5451 v.visit(this);
5452 }
5453 }
5454
5455 /***********************************************************
5456 * e1.array property for vectors.
5457 *
5458 * https://dlang.org/spec/simd.html#properties
5459 */
5460 extern (C++) final class VectorArrayExp : UnaExp
5461 {
this(const ref Loc loc,Expression e1)5462 extern (D) this(const ref Loc loc, Expression e1)
5463 {
5464 super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
5465 }
5466
isLvalue()5467 override bool isLvalue()
5468 {
5469 return e1.isLvalue();
5470 }
5471
toLvalue(Scope * sc,Expression e)5472 override Expression toLvalue(Scope* sc, Expression e)
5473 {
5474 e1 = e1.toLvalue(sc, e);
5475 return this;
5476 }
5477
accept(Visitor v)5478 override void accept(Visitor v)
5479 {
5480 v.visit(this);
5481 }
5482 }
5483
5484 /***********************************************************
5485 * e1 [lwr .. upr]
5486 *
5487 * https://dlang.org/spec/expression.html#slice_expressions
5488 */
5489 extern (C++) final class SliceExp : UnaExp
5490 {
5491 Expression upr; // null if implicit 0
5492 Expression lwr; // null if implicit [length - 1]
5493
5494 VarDeclaration lengthVar;
5495 bool upperIsInBounds; // true if upr <= e1.length
5496 bool lowerIsLessThanUpper; // true if lwr <= upr
5497 bool arrayop; // an array operation, rather than a slice
5498
5499 /************************************************************/
this(const ref Loc loc,Expression e1,IntervalExp ie)5500 extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
5501 {
5502 super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
5503 this.upr = ie ? ie.upr : null;
5504 this.lwr = ie ? ie.lwr : null;
5505 }
5506
this(const ref Loc loc,Expression e1,Expression lwr,Expression upr)5507 extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
5508 {
5509 super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
5510 this.upr = upr;
5511 this.lwr = lwr;
5512 }
5513
syntaxCopy()5514 override SliceExp syntaxCopy()
5515 {
5516 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
5517 se.lengthVar = this.lengthVar; // bug7871
5518 return se;
5519 }
5520
isLvalue()5521 override bool isLvalue()
5522 {
5523 /* slice expression is rvalue in default, but
5524 * conversion to reference of static array is only allowed.
5525 */
5526 return (type && type.toBasetype().ty == Tsarray);
5527 }
5528
toLvalue(Scope * sc,Expression e)5529 override Expression toLvalue(Scope* sc, Expression e)
5530 {
5531 //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
5532 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
5533 }
5534
modifiableLvalue(Scope * sc,Expression e)5535 override Expression modifiableLvalue(Scope* sc, Expression e)
5536 {
5537 error("slice expression `%s` is not a modifiable lvalue", toChars());
5538 return this;
5539 }
5540
5541 override Optional!bool toBool()
5542 {
5543 return e1.toBool();
5544 }
5545
accept(Visitor v)5546 override void accept(Visitor v)
5547 {
5548 v.visit(this);
5549 }
5550 }
5551
5552 /***********************************************************
5553 * The `.length` property of an array
5554 */
5555 extern (C++) final class ArrayLengthExp : UnaExp
5556 {
this(const ref Loc loc,Expression e1)5557 extern (D) this(const ref Loc loc, Expression e1)
5558 {
5559 super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
5560 }
5561
accept(Visitor v)5562 override void accept(Visitor v)
5563 {
5564 v.visit(this);
5565 }
5566 }
5567
5568 /***********************************************************
5569 * e1 [ a0, a1, a2, a3 ,... ]
5570 *
5571 * https://dlang.org/spec/expression.html#index_expressions
5572 */
5573 extern (C++) final class ArrayExp : UnaExp
5574 {
5575 Expressions* arguments; // Array of Expression's a0..an
5576
5577 size_t currentDimension; // for opDollar
5578 VarDeclaration lengthVar;
5579
5580 extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
5581 {
5582 super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
5583 arguments = new Expressions();
5584 if (index)
5585 arguments.push(index);
5586 }
5587
this(const ref Loc loc,Expression e1,Expressions * args)5588 extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
5589 {
5590 super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
5591 arguments = args;
5592 }
5593
syntaxCopy()5594 override ArrayExp syntaxCopy()
5595 {
5596 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5597 ae.lengthVar = this.lengthVar; // bug7871
5598 return ae;
5599 }
5600
isLvalue()5601 override bool isLvalue()
5602 {
5603 if (type && type.toBasetype().ty == Tvoid)
5604 return false;
5605 return true;
5606 }
5607
toLvalue(Scope * sc,Expression e)5608 override Expression toLvalue(Scope* sc, Expression e)
5609 {
5610 if (type && type.toBasetype().ty == Tvoid)
5611 error("`void`s have no value");
5612 return this;
5613 }
5614
accept(Visitor v)5615 override void accept(Visitor v)
5616 {
5617 v.visit(this);
5618 }
5619 }
5620
5621 /***********************************************************
5622 */
5623 extern (C++) final class DotExp : BinExp
5624 {
this(const ref Loc loc,Expression e1,Expression e2)5625 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5626 {
5627 super(loc, EXP.dot, __traits(classInstanceSize, DotExp), e1, e2);
5628 }
5629
accept(Visitor v)5630 override void accept(Visitor v)
5631 {
5632 v.visit(this);
5633 }
5634 }
5635
5636 /***********************************************************
5637 */
5638 extern (C++) final class CommaExp : BinExp
5639 {
5640 /// This is needed because AssignExp rewrites CommaExp, hence it needs
5641 /// to trigger the deprecation.
5642 const bool isGenerated;
5643
5644 /// Temporary variable to enable / disable deprecation of comma expression
5645 /// depending on the context.
5646 /// Since most constructor calls are rewritting, the only place where
5647 /// false will be passed will be from the parser.
5648 bool allowCommaExp;
5649
5650
5651 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
5652 {
5653 super(loc, EXP.comma, __traits(classInstanceSize, CommaExp), e1, e2);
5654 allowCommaExp = isGenerated = generated;
5655 }
5656
isLvalue()5657 override bool isLvalue()
5658 {
5659 return e2.isLvalue();
5660 }
5661
toLvalue(Scope * sc,Expression e)5662 override Expression toLvalue(Scope* sc, Expression e)
5663 {
5664 e2 = e2.toLvalue(sc, null);
5665 return this;
5666 }
5667
modifiableLvalue(Scope * sc,Expression e)5668 override Expression modifiableLvalue(Scope* sc, Expression e)
5669 {
5670 e2 = e2.modifiableLvalue(sc, e);
5671 return this;
5672 }
5673
5674 override Optional!bool toBool()
5675 {
5676 return e2.toBool();
5677 }
5678
addDtorHook(Scope * sc)5679 override Expression addDtorHook(Scope* sc)
5680 {
5681 e2 = e2.addDtorHook(sc);
5682 return this;
5683 }
5684
accept(Visitor v)5685 override void accept(Visitor v)
5686 {
5687 v.visit(this);
5688 }
5689
5690 /**
5691 * If the argument is a CommaExp, set a flag to prevent deprecation messages
5692 *
5693 * It's impossible to know from CommaExp.semantic if the result will
5694 * be used, hence when there is a result (type != void), a deprecation
5695 * message is always emitted.
5696 * However, some construct can produce a result but won't use it
5697 * (ExpStatement and for loop increment). Those should call this function
5698 * to prevent unwanted deprecations to be emitted.
5699 *
5700 * Params:
5701 * exp = An expression that discards its result.
5702 * If the argument is null or not a CommaExp, nothing happens.
5703 */
allow(Expression exp)5704 static void allow(Expression exp)
5705 {
5706 if (exp)
5707 if (auto ce = exp.isCommaExp())
5708 ce.allowCommaExp = true;
5709 }
5710 }
5711
5712 /***********************************************************
5713 * Mainly just a placeholder
5714 */
5715 extern (C++) final class IntervalExp : Expression
5716 {
5717 Expression lwr;
5718 Expression upr;
5719
this(const ref Loc loc,Expression lwr,Expression upr)5720 extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
5721 {
5722 super(loc, EXP.interval, __traits(classInstanceSize, IntervalExp));
5723 this.lwr = lwr;
5724 this.upr = upr;
5725 }
5726
syntaxCopy()5727 override Expression syntaxCopy()
5728 {
5729 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
5730 }
5731
accept(Visitor v)5732 override void accept(Visitor v)
5733 {
5734 v.visit(this);
5735 }
5736 }
5737
5738 /***********************************************************
5739 * The `dg.ptr` property, pointing to the delegate's 'context'
5740 *
5741 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
5742 */
5743 extern (C++) final class DelegatePtrExp : UnaExp
5744 {
this(const ref Loc loc,Expression e1)5745 extern (D) this(const ref Loc loc, Expression e1)
5746 {
5747 super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
5748 }
5749
isLvalue()5750 override bool isLvalue()
5751 {
5752 return e1.isLvalue();
5753 }
5754
toLvalue(Scope * sc,Expression e)5755 override Expression toLvalue(Scope* sc, Expression e)
5756 {
5757 e1 = e1.toLvalue(sc, e);
5758 return this;
5759 }
5760
modifiableLvalue(Scope * sc,Expression e)5761 override Expression modifiableLvalue(Scope* sc, Expression e)
5762 {
5763 if (sc.func.setUnsafe())
5764 {
5765 error("cannot modify delegate pointer in `@safe` code `%s`", toChars());
5766 return ErrorExp.get();
5767 }
5768 return Expression.modifiableLvalue(sc, e);
5769 }
5770
accept(Visitor v)5771 override void accept(Visitor v)
5772 {
5773 v.visit(this);
5774 }
5775 }
5776
5777 /***********************************************************
5778 * The `dg.funcptr` property, pointing to the delegate's function
5779 *
5780 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
5781 */
5782 extern (C++) final class DelegateFuncptrExp : UnaExp
5783 {
this(const ref Loc loc,Expression e1)5784 extern (D) this(const ref Loc loc, Expression e1)
5785 {
5786 super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
5787 }
5788
isLvalue()5789 override bool isLvalue()
5790 {
5791 return e1.isLvalue();
5792 }
5793
toLvalue(Scope * sc,Expression e)5794 override Expression toLvalue(Scope* sc, Expression e)
5795 {
5796 e1 = e1.toLvalue(sc, e);
5797 return this;
5798 }
5799
modifiableLvalue(Scope * sc,Expression e)5800 override Expression modifiableLvalue(Scope* sc, Expression e)
5801 {
5802 if (sc.func.setUnsafe())
5803 {
5804 error("cannot modify delegate function pointer in `@safe` code `%s`", toChars());
5805 return ErrorExp.get();
5806 }
5807 return Expression.modifiableLvalue(sc, e);
5808 }
5809
accept(Visitor v)5810 override void accept(Visitor v)
5811 {
5812 v.visit(this);
5813 }
5814 }
5815
5816 /***********************************************************
5817 * e1 [ e2 ]
5818 */
5819 extern (C++) final class IndexExp : BinExp
5820 {
5821 VarDeclaration lengthVar;
5822 bool modifiable = false; // assume it is an rvalue
5823 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
5824
this(const ref Loc loc,Expression e1,Expression e2)5825 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5826 {
5827 super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
5828 //printf("IndexExp::IndexExp('%s')\n", toChars());
5829 }
5830
this(const ref Loc loc,Expression e1,Expression e2,bool indexIsInBounds)5831 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds)
5832 {
5833 super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
5834 this.indexIsInBounds = indexIsInBounds;
5835 //printf("IndexExp::IndexExp('%s')\n", toChars());
5836 }
5837
syntaxCopy()5838 override IndexExp syntaxCopy()
5839 {
5840 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
5841 ie.lengthVar = this.lengthVar; // bug7871
5842 return ie;
5843 }
5844
isLvalue()5845 override bool isLvalue()
5846 {
5847 if (e1.op == EXP.assocArrayLiteral)
5848 return false;
5849 if (e1.type.ty == Tsarray ||
5850 (e1.op == EXP.index && e1.type.ty != Tarray))
5851 {
5852 return e1.isLvalue();
5853 }
5854 return true;
5855 }
5856
toLvalue(Scope * sc,Expression e)5857 override Expression toLvalue(Scope* sc, Expression e)
5858 {
5859 if (isLvalue())
5860 return this;
5861 return Expression.toLvalue(sc, e);
5862 }
5863
modifiableLvalue(Scope * sc,Expression e)5864 override Expression modifiableLvalue(Scope* sc, Expression e)
5865 {
5866 //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
5867 Expression ex = markSettingAAElem();
5868 if (ex.op == EXP.error)
5869 return ex;
5870
5871 return Expression.modifiableLvalue(sc, e);
5872 }
5873
markSettingAAElem()5874 extern (D) Expression markSettingAAElem()
5875 {
5876 if (e1.type.toBasetype().ty == Taarray)
5877 {
5878 Type t2b = e2.type.toBasetype();
5879 if (t2b.ty == Tarray && t2b.nextOf().isMutable())
5880 {
5881 error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
5882 return ErrorExp.get();
5883 }
5884 modifiable = true;
5885
5886 if (auto ie = e1.isIndexExp())
5887 {
5888 Expression ex = ie.markSettingAAElem();
5889 if (ex.op == EXP.error)
5890 return ex;
5891 assert(ex == e1);
5892 }
5893 }
5894 return this;
5895 }
5896
accept(Visitor v)5897 override void accept(Visitor v)
5898 {
5899 v.visit(this);
5900 }
5901 }
5902
5903 /***********************************************************
5904 * The postfix increment/decrement operator, `i++` / `i--`
5905 */
5906 extern (C++) final class PostExp : BinExp
5907 {
this(EXP op,const ref Loc loc,Expression e)5908 extern (D) this(EXP op, const ref Loc loc, Expression e)
5909 {
5910 super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1);
5911 assert(op == EXP.minusMinus || op == EXP.plusPlus);
5912 }
5913
accept(Visitor v)5914 override void accept(Visitor v)
5915 {
5916 v.visit(this);
5917 }
5918 }
5919
5920 /***********************************************************
5921 * The prefix increment/decrement operator, `++i` / `--i`
5922 */
5923 extern (C++) final class PreExp : UnaExp
5924 {
this(EXP op,const ref Loc loc,Expression e)5925 extern (D) this(EXP op, const ref Loc loc, Expression e)
5926 {
5927 super(loc, op, __traits(classInstanceSize, PreExp), e);
5928 assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
5929 }
5930
accept(Visitor v)5931 override void accept(Visitor v)
5932 {
5933 v.visit(this);
5934 }
5935 }
5936
5937 enum MemorySet
5938 {
5939 none = 0, // simple assignment
5940 blockAssign = 1, // setting the contents of an array
5941 referenceInit = 2, // setting the reference of STC.ref_ variable
5942 }
5943
5944 /***********************************************************
5945 * The assignment / initialization operator, `=`
5946 *
5947 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
5948 */
5949 extern (C++) class AssignExp : BinExp
5950 {
5951 MemorySet memset;
5952
5953 /************************************************************/
5954 /* op can be EXP.assign, EXP.construct, or EXP.blit */
this(const ref Loc loc,Expression e1,Expression e2)5955 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5956 {
5957 super(loc, EXP.assign, __traits(classInstanceSize, AssignExp), e1, e2);
5958 }
5959
this(const ref Loc loc,EXP tok,Expression e1,Expression e2)5960 this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
5961 {
5962 super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
5963 }
5964
isLvalue()5965 override final bool isLvalue()
5966 {
5967 // Array-op 'x[] = y[]' should make an rvalue.
5968 // Setting array length 'x.length = v' should make an rvalue.
5969 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
5970 {
5971 return false;
5972 }
5973 return true;
5974 }
5975
toLvalue(Scope * sc,Expression ex)5976 override final Expression toLvalue(Scope* sc, Expression ex)
5977 {
5978 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
5979 {
5980 return Expression.toLvalue(sc, ex);
5981 }
5982
5983 /* In front-end level, AssignExp should make an lvalue of e1.
5984 * Taking the address of e1 will be handled in low level layer,
5985 * so this function does nothing.
5986 */
5987 return this;
5988 }
5989
accept(Visitor v)5990 override void accept(Visitor v)
5991 {
5992 v.visit(this);
5993 }
5994 }
5995
5996 /***********************************************************
5997 */
5998 extern (C++) final class ConstructExp : AssignExp
5999 {
this(const ref Loc loc,Expression e1,Expression e2)6000 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6001 {
6002 super(loc, EXP.construct, e1, e2);
6003 }
6004
6005 // Internal use only. If `v` is a reference variable, the assignment
6006 // will become a reference initialization automatically.
this(const ref Loc loc,VarDeclaration v,Expression e2)6007 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6008 {
6009 auto ve = new VarExp(loc, v);
6010 assert(v.type && ve.type);
6011
6012 super(loc, EXP.construct, ve, e2);
6013
6014 if (v.isReference())
6015 memset = MemorySet.referenceInit;
6016 }
6017
accept(Visitor v)6018 override void accept(Visitor v)
6019 {
6020 v.visit(this);
6021 }
6022 }
6023
6024 /***********************************************************
6025 * A bit-for-bit copy from `e2` to `e1`
6026 */
6027 extern (C++) final class BlitExp : AssignExp
6028 {
this(const ref Loc loc,Expression e1,Expression e2)6029 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6030 {
6031 super(loc, EXP.blit, e1, e2);
6032 }
6033
6034 // Internal use only. If `v` is a reference variable, the assinment
6035 // will become a reference rebinding automatically.
this(const ref Loc loc,VarDeclaration v,Expression e2)6036 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6037 {
6038 auto ve = new VarExp(loc, v);
6039 assert(v.type && ve.type);
6040
6041 super(loc, EXP.blit, ve, e2);
6042
6043 if (v.isReference())
6044 memset = MemorySet.referenceInit;
6045 }
6046
accept(Visitor v)6047 override void accept(Visitor v)
6048 {
6049 v.visit(this);
6050 }
6051 }
6052
6053 /***********************************************************
6054 * `x += y`
6055 */
6056 extern (C++) final class AddAssignExp : BinAssignExp
6057 {
this(const ref Loc loc,Expression e1,Expression e2)6058 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6059 {
6060 super(loc, EXP.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
6061 }
6062
accept(Visitor v)6063 override void accept(Visitor v)
6064 {
6065 v.visit(this);
6066 }
6067 }
6068
6069 /***********************************************************
6070 * `x -= y`
6071 */
6072 extern (C++) final class MinAssignExp : BinAssignExp
6073 {
this(const ref Loc loc,Expression e1,Expression e2)6074 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6075 {
6076 super(loc, EXP.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
6077 }
6078
accept(Visitor v)6079 override void accept(Visitor v)
6080 {
6081 v.visit(this);
6082 }
6083 }
6084
6085 /***********************************************************
6086 * `x *= y`
6087 */
6088 extern (C++) final class MulAssignExp : BinAssignExp
6089 {
this(const ref Loc loc,Expression e1,Expression e2)6090 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6091 {
6092 super(loc, EXP.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
6093 }
6094
accept(Visitor v)6095 override void accept(Visitor v)
6096 {
6097 v.visit(this);
6098 }
6099 }
6100
6101 /***********************************************************
6102 * `x /= y`
6103 */
6104 extern (C++) final class DivAssignExp : BinAssignExp
6105 {
this(const ref Loc loc,Expression e1,Expression e2)6106 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6107 {
6108 super(loc, EXP.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
6109 }
6110
accept(Visitor v)6111 override void accept(Visitor v)
6112 {
6113 v.visit(this);
6114 }
6115 }
6116
6117 /***********************************************************
6118 * `x %= y`
6119 */
6120 extern (C++) final class ModAssignExp : BinAssignExp
6121 {
this(const ref Loc loc,Expression e1,Expression e2)6122 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6123 {
6124 super(loc, EXP.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
6125 }
6126
accept(Visitor v)6127 override void accept(Visitor v)
6128 {
6129 v.visit(this);
6130 }
6131 }
6132
6133 /***********************************************************
6134 * `x &= y`
6135 */
6136 extern (C++) final class AndAssignExp : BinAssignExp
6137 {
this(const ref Loc loc,Expression e1,Expression e2)6138 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6139 {
6140 super(loc, EXP.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
6141 }
6142
accept(Visitor v)6143 override void accept(Visitor v)
6144 {
6145 v.visit(this);
6146 }
6147 }
6148
6149 /***********************************************************
6150 * `x |= y`
6151 */
6152 extern (C++) final class OrAssignExp : BinAssignExp
6153 {
this(const ref Loc loc,Expression e1,Expression e2)6154 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6155 {
6156 super(loc, EXP.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
6157 }
6158
accept(Visitor v)6159 override void accept(Visitor v)
6160 {
6161 v.visit(this);
6162 }
6163 }
6164
6165 /***********************************************************
6166 * `x ^= y`
6167 */
6168 extern (C++) final class XorAssignExp : BinAssignExp
6169 {
this(const ref Loc loc,Expression e1,Expression e2)6170 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6171 {
6172 super(loc, EXP.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
6173 }
6174
accept(Visitor v)6175 override void accept(Visitor v)
6176 {
6177 v.visit(this);
6178 }
6179 }
6180
6181 /***********************************************************
6182 * `x ^^= y`
6183 */
6184 extern (C++) final class PowAssignExp : BinAssignExp
6185 {
this(const ref Loc loc,Expression e1,Expression e2)6186 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6187 {
6188 super(loc, EXP.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
6189 }
6190
accept(Visitor v)6191 override void accept(Visitor v)
6192 {
6193 v.visit(this);
6194 }
6195 }
6196
6197 /***********************************************************
6198 * `x <<= y`
6199 */
6200 extern (C++) final class ShlAssignExp : BinAssignExp
6201 {
this(const ref Loc loc,Expression e1,Expression e2)6202 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6203 {
6204 super(loc, EXP.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
6205 }
6206
accept(Visitor v)6207 override void accept(Visitor v)
6208 {
6209 v.visit(this);
6210 }
6211 }
6212
6213 /***********************************************************
6214 * `x >>= y`
6215 */
6216 extern (C++) final class ShrAssignExp : BinAssignExp
6217 {
this(const ref Loc loc,Expression e1,Expression e2)6218 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6219 {
6220 super(loc, EXP.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
6221 }
6222
accept(Visitor v)6223 override void accept(Visitor v)
6224 {
6225 v.visit(this);
6226 }
6227 }
6228
6229 /***********************************************************
6230 * `x >>>= y`
6231 */
6232 extern (C++) final class UshrAssignExp : BinAssignExp
6233 {
this(const ref Loc loc,Expression e1,Expression e2)6234 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6235 {
6236 super(loc, EXP.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
6237 }
6238
accept(Visitor v)6239 override void accept(Visitor v)
6240 {
6241 v.visit(this);
6242 }
6243 }
6244
6245 /***********************************************************
6246 * The `~=` operator.
6247 *
6248 * It can have one of the following operators:
6249 *
6250 * EXP.concatenateAssign - appending T[] to T[]
6251 * EXP.concatenateElemAssign - appending T to T[]
6252 * EXP.concatenateDcharAssign - appending dchar to T[]
6253 *
6254 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
6255 * of the three it will be set to.
6256 */
6257 extern (C++) class CatAssignExp : BinAssignExp
6258 {
this(const ref Loc loc,Expression e1,Expression e2)6259 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6260 {
6261 super(loc, EXP.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
6262 }
6263
this(const ref Loc loc,EXP tok,Expression e1,Expression e2)6264 extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
6265 {
6266 super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
6267 }
6268
accept(Visitor v)6269 override void accept(Visitor v)
6270 {
6271 v.visit(this);
6272 }
6273 }
6274
6275 /***********************************************************
6276 * The `~=` operator when appending a single element
6277 */
6278 extern (C++) final class CatElemAssignExp : CatAssignExp
6279 {
this(const ref Loc loc,Type type,Expression e1,Expression e2)6280 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6281 {
6282 super(loc, EXP.concatenateElemAssign, e1, e2);
6283 this.type = type;
6284 }
6285
accept(Visitor v)6286 override void accept(Visitor v)
6287 {
6288 v.visit(this);
6289 }
6290 }
6291
6292 /***********************************************************
6293 * The `~=` operator when appending a single `dchar`
6294 */
6295 extern (C++) final class CatDcharAssignExp : CatAssignExp
6296 {
this(const ref Loc loc,Type type,Expression e1,Expression e2)6297 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6298 {
6299 super(loc, EXP.concatenateDcharAssign, e1, e2);
6300 this.type = type;
6301 }
6302
accept(Visitor v)6303 override void accept(Visitor v)
6304 {
6305 v.visit(this);
6306 }
6307 }
6308
6309 /***********************************************************
6310 * The addition operator, `x + y`
6311 *
6312 * https://dlang.org/spec/expression.html#add_expressions
6313 */
6314 extern (C++) final class AddExp : BinExp
6315 {
this(const ref Loc loc,Expression e1,Expression e2)6316 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6317 {
6318 super(loc, EXP.add, __traits(classInstanceSize, AddExp), e1, e2);
6319 }
6320
accept(Visitor v)6321 override void accept(Visitor v)
6322 {
6323 v.visit(this);
6324 }
6325 }
6326
6327 /***********************************************************
6328 * The minus operator, `x - y`
6329 *
6330 * https://dlang.org/spec/expression.html#add_expressions
6331 */
6332 extern (C++) final class MinExp : BinExp
6333 {
this(const ref Loc loc,Expression e1,Expression e2)6334 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6335 {
6336 super(loc, EXP.min, __traits(classInstanceSize, MinExp), e1, e2);
6337 }
6338
accept(Visitor v)6339 override void accept(Visitor v)
6340 {
6341 v.visit(this);
6342 }
6343 }
6344
6345 /***********************************************************
6346 * The concatenation operator, `x ~ y`
6347 *
6348 * https://dlang.org/spec/expression.html#cat_expressions
6349 */
6350 extern (C++) final class CatExp : BinExp
6351 {
this(const ref Loc loc,Expression e1,Expression e2)6352 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6353 {
6354 super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
6355 }
6356
resolveLoc(const ref Loc loc,Scope * sc)6357 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6358 {
6359 e1 = e1.resolveLoc(loc, sc);
6360 e2 = e2.resolveLoc(loc, sc);
6361 return this;
6362 }
6363
accept(Visitor v)6364 override void accept(Visitor v)
6365 {
6366 v.visit(this);
6367 }
6368 }
6369
6370 /***********************************************************
6371 * The multiplication operator, `x * y`
6372 *
6373 * https://dlang.org/spec/expression.html#mul_expressions
6374 */
6375 extern (C++) final class MulExp : BinExp
6376 {
this(const ref Loc loc,Expression e1,Expression e2)6377 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6378 {
6379 super(loc, EXP.mul, __traits(classInstanceSize, MulExp), e1, e2);
6380 }
6381
accept(Visitor v)6382 override void accept(Visitor v)
6383 {
6384 v.visit(this);
6385 }
6386 }
6387
6388 /***********************************************************
6389 * The division operator, `x / y`
6390 *
6391 * https://dlang.org/spec/expression.html#mul_expressions
6392 */
6393 extern (C++) final class DivExp : BinExp
6394 {
this(const ref Loc loc,Expression e1,Expression e2)6395 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6396 {
6397 super(loc, EXP.div, __traits(classInstanceSize, DivExp), e1, e2);
6398 }
6399
accept(Visitor v)6400 override void accept(Visitor v)
6401 {
6402 v.visit(this);
6403 }
6404 }
6405
6406 /***********************************************************
6407 * The modulo operator, `x % y`
6408 *
6409 * https://dlang.org/spec/expression.html#mul_expressions
6410 */
6411 extern (C++) final class ModExp : BinExp
6412 {
this(const ref Loc loc,Expression e1,Expression e2)6413 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6414 {
6415 super(loc, EXP.mod, __traits(classInstanceSize, ModExp), e1, e2);
6416 }
6417
accept(Visitor v)6418 override void accept(Visitor v)
6419 {
6420 v.visit(this);
6421 }
6422 }
6423
6424 /***********************************************************
6425 * The 'power' operator, `x ^^ y`
6426 *
6427 * https://dlang.org/spec/expression.html#pow_expressions
6428 */
6429 extern (C++) final class PowExp : BinExp
6430 {
this(const ref Loc loc,Expression e1,Expression e2)6431 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6432 {
6433 super(loc, EXP.pow, __traits(classInstanceSize, PowExp), e1, e2);
6434 }
6435
accept(Visitor v)6436 override void accept(Visitor v)
6437 {
6438 v.visit(this);
6439 }
6440 }
6441
6442 /***********************************************************
6443 * The 'shift left' operator, `x << y`
6444 *
6445 * https://dlang.org/spec/expression.html#shift_expressions
6446 */
6447 extern (C++) final class ShlExp : BinExp
6448 {
this(const ref Loc loc,Expression e1,Expression e2)6449 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6450 {
6451 super(loc, EXP.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
6452 }
6453
accept(Visitor v)6454 override void accept(Visitor v)
6455 {
6456 v.visit(this);
6457 }
6458 }
6459
6460 /***********************************************************
6461 * The 'shift right' operator, `x >> y`
6462 *
6463 * https://dlang.org/spec/expression.html#shift_expressions
6464 */
6465 extern (C++) final class ShrExp : BinExp
6466 {
this(const ref Loc loc,Expression e1,Expression e2)6467 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6468 {
6469 super(loc, EXP.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
6470 }
6471
accept(Visitor v)6472 override void accept(Visitor v)
6473 {
6474 v.visit(this);
6475 }
6476 }
6477
6478 /***********************************************************
6479 * The 'unsigned shift right' operator, `x >>> y`
6480 *
6481 * https://dlang.org/spec/expression.html#shift_expressions
6482 */
6483 extern (C++) final class UshrExp : BinExp
6484 {
this(const ref Loc loc,Expression e1,Expression e2)6485 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6486 {
6487 super(loc, EXP.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
6488 }
6489
accept(Visitor v)6490 override void accept(Visitor v)
6491 {
6492 v.visit(this);
6493 }
6494 }
6495
6496 /***********************************************************
6497 * The bitwise 'and' operator, `x & y`
6498 *
6499 * https://dlang.org/spec/expression.html#and_expressions
6500 */
6501 extern (C++) final class AndExp : BinExp
6502 {
this(const ref Loc loc,Expression e1,Expression e2)6503 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6504 {
6505 super(loc, EXP.and, __traits(classInstanceSize, AndExp), e1, e2);
6506 }
6507
accept(Visitor v)6508 override void accept(Visitor v)
6509 {
6510 v.visit(this);
6511 }
6512 }
6513
6514 /***********************************************************
6515 * The bitwise 'or' operator, `x | y`
6516 *
6517 * https://dlang.org/spec/expression.html#or_expressions
6518 */
6519 extern (C++) final class OrExp : BinExp
6520 {
this(const ref Loc loc,Expression e1,Expression e2)6521 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6522 {
6523 super(loc, EXP.or, __traits(classInstanceSize, OrExp), e1, e2);
6524 }
6525
accept(Visitor v)6526 override void accept(Visitor v)
6527 {
6528 v.visit(this);
6529 }
6530 }
6531
6532 /***********************************************************
6533 * The bitwise 'xor' operator, `x ^ y`
6534 *
6535 * https://dlang.org/spec/expression.html#xor_expressions
6536 */
6537 extern (C++) final class XorExp : BinExp
6538 {
this(const ref Loc loc,Expression e1,Expression e2)6539 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6540 {
6541 super(loc, EXP.xor, __traits(classInstanceSize, XorExp), e1, e2);
6542 }
6543
accept(Visitor v)6544 override void accept(Visitor v)
6545 {
6546 v.visit(this);
6547 }
6548 }
6549
6550 /***********************************************************
6551 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
6552 *
6553 * https://dlang.org/spec/expression.html#andand_expressions
6554 * https://dlang.org/spec/expression.html#oror_expressions
6555 */
6556 extern (C++) final class LogicalExp : BinExp
6557 {
this(const ref Loc loc,EXP op,Expression e1,Expression e2)6558 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2)
6559 {
6560 super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
6561 assert(op == EXP.andAnd || op == EXP.orOr);
6562 }
6563
accept(Visitor v)6564 override void accept(Visitor v)
6565 {
6566 v.visit(this);
6567 }
6568 }
6569
6570 /***********************************************************
6571 * A comparison operator, `<` `<=` `>` `>=`
6572 *
6573 * `op` is one of:
6574 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
6575 *
6576 * https://dlang.org/spec/expression.html#relation_expressions
6577 */
6578 extern (C++) final class CmpExp : BinExp
6579 {
this(EXP op,const ref Loc loc,Expression e1,Expression e2)6580 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
6581 {
6582 super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
6583 assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
6584 }
6585
accept(Visitor v)6586 override void accept(Visitor v)
6587 {
6588 v.visit(this);
6589 }
6590 }
6591
6592 /***********************************************************
6593 * The `in` operator, `"a" in ["a": 1]`
6594 *
6595 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
6596 *
6597 * https://dlang.org/spec/expression.html#in_expressions
6598 */
6599 extern (C++) final class InExp : BinExp
6600 {
this(const ref Loc loc,Expression e1,Expression e2)6601 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6602 {
6603 super(loc, EXP.in_, __traits(classInstanceSize, InExp), e1, e2);
6604 }
6605
accept(Visitor v)6606 override void accept(Visitor v)
6607 {
6608 v.visit(this);
6609 }
6610 }
6611
6612 /***********************************************************
6613 * Associative array removal, `aa.remove(arg)`
6614 *
6615 * This deletes the key e1 from the associative array e2
6616 */
6617 extern (C++) final class RemoveExp : BinExp
6618 {
this(const ref Loc loc,Expression e1,Expression e2)6619 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6620 {
6621 super(loc, EXP.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
6622 type = Type.tbool;
6623 }
6624
accept(Visitor v)6625 override void accept(Visitor v)
6626 {
6627 v.visit(this);
6628 }
6629 }
6630
6631 /***********************************************************
6632 * `==` and `!=`
6633 *
6634 * EXP.equal and EXP.notEqual
6635 *
6636 * https://dlang.org/spec/expression.html#equality_expressions
6637 */
6638 extern (C++) final class EqualExp : BinExp
6639 {
this(EXP op,const ref Loc loc,Expression e1,Expression e2)6640 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
6641 {
6642 super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
6643 assert(op == EXP.equal || op == EXP.notEqual);
6644 }
6645
accept(Visitor v)6646 override void accept(Visitor v)
6647 {
6648 v.visit(this);
6649 }
6650 }
6651
6652 /***********************************************************
6653 * `is` and `!is`
6654 *
6655 * EXP.identity and EXP.notIdentity
6656 *
6657 * https://dlang.org/spec/expression.html#identity_expressions
6658 */
6659 extern (C++) final class IdentityExp : BinExp
6660 {
this(EXP op,const ref Loc loc,Expression e1,Expression e2)6661 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
6662 {
6663 super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
6664 assert(op == EXP.identity || op == EXP.notIdentity);
6665 }
6666
accept(Visitor v)6667 override void accept(Visitor v)
6668 {
6669 v.visit(this);
6670 }
6671 }
6672
6673 /***********************************************************
6674 * The ternary operator, `econd ? e1 : e2`
6675 *
6676 * https://dlang.org/spec/expression.html#conditional_expressions
6677 */
6678 extern (C++) final class CondExp : BinExp
6679 {
6680 Expression econd;
6681
this(const ref Loc loc,Expression econd,Expression e1,Expression e2)6682 extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
6683 {
6684 super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2);
6685 this.econd = econd;
6686 }
6687
syntaxCopy()6688 override CondExp syntaxCopy()
6689 {
6690 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
6691 }
6692
isLvalue()6693 override bool isLvalue()
6694 {
6695 return e1.isLvalue() && e2.isLvalue();
6696 }
6697
toLvalue(Scope * sc,Expression ex)6698 override Expression toLvalue(Scope* sc, Expression ex)
6699 {
6700 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
6701 CondExp e = cast(CondExp)copy();
6702 e.e1 = e1.toLvalue(sc, null).addressOf();
6703 e.e2 = e2.toLvalue(sc, null).addressOf();
6704 e.type = type.pointerTo();
6705 return new PtrExp(loc, e, type);
6706 }
6707
modifiableLvalue(Scope * sc,Expression e)6708 override Expression modifiableLvalue(Scope* sc, Expression e)
6709 {
6710 if (!e1.isLvalue() && !e2.isLvalue())
6711 {
6712 error("conditional expression `%s` is not a modifiable lvalue", toChars());
6713 return ErrorExp.get();
6714 }
6715 e1 = e1.modifiableLvalue(sc, e1);
6716 e2 = e2.modifiableLvalue(sc, e2);
6717 return toLvalue(sc, this);
6718 }
6719
hookDtors(Scope * sc)6720 void hookDtors(Scope* sc)
6721 {
6722 extern (C++) final class DtorVisitor : StoppableVisitor
6723 {
6724 alias visit = typeof(super).visit;
6725 public:
6726 Scope* sc;
6727 CondExp ce;
6728 VarDeclaration vcond;
6729 bool isThen;
6730
6731 extern (D) this(Scope* sc, CondExp ce)
6732 {
6733 this.sc = sc;
6734 this.ce = ce;
6735 }
6736
6737 override void visit(Expression e)
6738 {
6739 //printf("(e = %s)\n", e.toChars());
6740 }
6741
6742 override void visit(DeclarationExp e)
6743 {
6744 auto v = e.declaration.isVarDeclaration();
6745 if (v && !v.isDataseg())
6746 {
6747 if (v._init)
6748 {
6749 if (auto ei = v._init.isExpInitializer())
6750 walkPostorder(ei.exp, this);
6751 }
6752
6753 if (v.edtor)
6754 walkPostorder(v.edtor, this);
6755
6756 if (v.needsScopeDtor())
6757 {
6758 if (!vcond)
6759 {
6760 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
6761 vcond.dsymbolSemantic(sc);
6762
6763 Expression de = new DeclarationExp(ce.econd.loc, vcond);
6764 de = de.expressionSemantic(sc);
6765
6766 Expression ve = new VarExp(ce.econd.loc, vcond);
6767 ce.econd = Expression.combine(de, ve);
6768 }
6769
6770 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6771 Expression ve = new VarExp(vcond.loc, vcond);
6772 if (isThen)
6773 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
6774 else
6775 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
6776 v.edtor = v.edtor.expressionSemantic(sc);
6777 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6778 }
6779 }
6780 }
6781 }
6782
6783 scope DtorVisitor v = new DtorVisitor(sc, this);
6784 //printf("+%s\n", toChars());
6785 v.isThen = true;
6786 walkPostorder(e1, v);
6787 v.isThen = false;
6788 walkPostorder(e2, v);
6789 //printf("-%s\n", toChars());
6790 }
6791
accept(Visitor v)6792 override void accept(Visitor v)
6793 {
6794 v.visit(this);
6795 }
6796 }
6797
6798 /// Returns: if this token is the `op` for a derived `DefaultInitExp` class.
isDefaultInitOp(EXP op)6799 bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc
6800 {
6801 return op == EXP.prettyFunction || op == EXP.functionString ||
6802 op == EXP.line || op == EXP.moduleString ||
6803 op == EXP.file || op == EXP.fileFullPath ;
6804 }
6805
6806 /***********************************************************
6807 * A special keyword when used as a function's default argument
6808 *
6809 * When possible, special keywords are resolved in the parser, but when
6810 * appearing as a default argument, they result in an expression deriving
6811 * from this base class that is resolved for each function call.
6812 *
6813 * ---
6814 * const x = __LINE__; // resolved in the parser
6815 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
6816 * ---
6817 *
6818 * https://dlang.org/spec/expression.html#specialkeywords
6819 */
6820 extern (C++) class DefaultInitExp : Expression
6821 {
this(const ref Loc loc,EXP op,int size)6822 extern (D) this(const ref Loc loc, EXP op, int size)
6823 {
6824 super(loc, op, size);
6825 }
6826
accept(Visitor v)6827 override void accept(Visitor v)
6828 {
6829 v.visit(this);
6830 }
6831 }
6832
6833 /***********************************************************
6834 * The `__FILE__` token as a default argument
6835 */
6836 extern (C++) final class FileInitExp : DefaultInitExp
6837 {
this(const ref Loc loc,EXP tok)6838 extern (D) this(const ref Loc loc, EXP tok)
6839 {
6840 super(loc, tok, __traits(classInstanceSize, FileInitExp));
6841 }
6842
resolveLoc(const ref Loc loc,Scope * sc)6843 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6844 {
6845 //printf("FileInitExp::resolve() %s\n", toChars());
6846 const(char)* s;
6847 if (op == EXP.fileFullPath)
6848 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
6849 else
6850 s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
6851
6852 Expression e = new StringExp(loc, s.toDString());
6853 e = e.expressionSemantic(sc);
6854 e = e.castTo(sc, type);
6855 return e;
6856 }
6857
accept(Visitor v)6858 override void accept(Visitor v)
6859 {
6860 v.visit(this);
6861 }
6862 }
6863
6864 /***********************************************************
6865 * The `__LINE__` token as a default argument
6866 */
6867 extern (C++) final class LineInitExp : DefaultInitExp
6868 {
this(const ref Loc loc)6869 extern (D) this(const ref Loc loc)
6870 {
6871 super(loc, EXP.line, __traits(classInstanceSize, LineInitExp));
6872 }
6873
resolveLoc(const ref Loc loc,Scope * sc)6874 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6875 {
6876 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
6877 e = e.castTo(sc, type);
6878 return e;
6879 }
6880
accept(Visitor v)6881 override void accept(Visitor v)
6882 {
6883 v.visit(this);
6884 }
6885 }
6886
6887 /***********************************************************
6888 * The `__MODULE__` token as a default argument
6889 */
6890 extern (C++) final class ModuleInitExp : DefaultInitExp
6891 {
this(const ref Loc loc)6892 extern (D) this(const ref Loc loc)
6893 {
6894 super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp));
6895 }
6896
resolveLoc(const ref Loc loc,Scope * sc)6897 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6898 {
6899 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
6900 Expression e = new StringExp(loc, s);
6901 e = e.expressionSemantic(sc);
6902 e = e.castTo(sc, type);
6903 return e;
6904 }
6905
accept(Visitor v)6906 override void accept(Visitor v)
6907 {
6908 v.visit(this);
6909 }
6910 }
6911
6912 /***********************************************************
6913 * The `__FUNCTION__` token as a default argument
6914 */
6915 extern (C++) final class FuncInitExp : DefaultInitExp
6916 {
this(const ref Loc loc)6917 extern (D) this(const ref Loc loc)
6918 {
6919 super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp));
6920 }
6921
resolveLoc(const ref Loc loc,Scope * sc)6922 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6923 {
6924 const(char)* s;
6925 if (sc.callsc && sc.callsc.func)
6926 s = sc.callsc.func.Dsymbol.toPrettyChars();
6927 else if (sc.func)
6928 s = sc.func.Dsymbol.toPrettyChars();
6929 else
6930 s = "";
6931 Expression e = new StringExp(loc, s.toDString());
6932 e = e.expressionSemantic(sc);
6933 e.type = Type.tstring;
6934 return e;
6935 }
6936
accept(Visitor v)6937 override void accept(Visitor v)
6938 {
6939 v.visit(this);
6940 }
6941 }
6942
6943 /***********************************************************
6944 * The `__PRETTY_FUNCTION__` token as a default argument
6945 */
6946 extern (C++) final class PrettyFuncInitExp : DefaultInitExp
6947 {
this(const ref Loc loc)6948 extern (D) this(const ref Loc loc)
6949 {
6950 super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
6951 }
6952
resolveLoc(const ref Loc loc,Scope * sc)6953 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6954 {
6955 FuncDeclaration fd = (sc.callsc && sc.callsc.func)
6956 ? sc.callsc.func
6957 : sc.func;
6958
6959 const(char)* s;
6960 if (fd)
6961 {
6962 const funcStr = fd.Dsymbol.toPrettyChars();
6963 OutBuffer buf;
6964 functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr, fd.isStatic);
6965 s = buf.extractChars();
6966 }
6967 else
6968 {
6969 s = "";
6970 }
6971
6972 Expression e = new StringExp(loc, s.toDString());
6973 e = e.expressionSemantic(sc);
6974 e.type = Type.tstring;
6975 return e;
6976 }
6977
accept(Visitor v)6978 override void accept(Visitor v)
6979 {
6980 v.visit(this);
6981 }
6982 }
6983
6984 /**
6985 * Objective-C class reference expression.
6986 *
6987 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
6988 */
6989 extern (C++) final class ObjcClassReferenceExp : Expression
6990 {
6991 ClassDeclaration classDeclaration;
6992
this(const ref Loc loc,ClassDeclaration classDeclaration)6993 extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
6994 {
6995 super(loc, EXP.objcClassReference,
6996 __traits(classInstanceSize, ObjcClassReferenceExp));
6997 this.classDeclaration = classDeclaration;
6998 type = objc.getRuntimeMetaclass(classDeclaration).getType();
6999 }
7000
accept(Visitor v)7001 override void accept(Visitor v)
7002 {
7003 v.visit(this);
7004 }
7005 }
7006
7007 /*******************
7008 * C11 6.5.1.1 Generic Selection
7009 * For ImportC
7010 */
7011 extern (C++) final class GenericExp : Expression
7012 {
7013 Expression cntlExp; /// controlling expression of a generic selection (not evaluated)
7014 Types* types; /// type-names for generic associations (null entry for `default`)
7015 Expressions* exps; /// 1:1 mapping of typeNames to exps
7016
this(const ref Loc loc,Expression cntlExp,Types * types,Expressions * exps)7017 extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps)
7018 {
7019 super(loc, EXP._Generic, __traits(classInstanceSize, GenericExp));
7020 this.cntlExp = cntlExp;
7021 this.types = types;
7022 this.exps = exps;
7023 assert(types.length == exps.length); // must be the same and >=1
7024 }
7025
syntaxCopy()7026 override GenericExp syntaxCopy()
7027 {
7028 return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
7029 }
7030
accept(Visitor v)7031 override void accept(Visitor v)
7032 {
7033 v.visit(this);
7034 }
7035 }
7036
7037 /***************************************
7038 * Parameters:
7039 * sc: scope
7040 * flag: 1: do not issue error message for invalid modification
7041 2: the exp is a DotVarExp and a subfield of the leftmost
7042 variable is modified
7043 * Returns:
7044 * Whether the type is modifiable
7045 */
7046 extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
7047 {
7048 switch(exp.op)
7049 {
7050 case EXP.variable:
7051 auto varExp = cast(VarExp)exp;
7052
7053 //printf("VarExp::checkModifiable %s", varExp.toChars());
7054 assert(varExp.type);
7055 return varExp.var.checkModify(varExp.loc, sc, null, flag);
7056
7057 case EXP.dotVariable:
7058 auto dotVarExp = cast(DotVarExp)exp;
7059
7060 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
7061 if (dotVarExp.e1.op == EXP.this_)
7062 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
7063
7064 /* https://issues.dlang.org/show_bug.cgi?id=12764
7065 * If inside a constructor and an expression of type `this.field.var`
7066 * is encountered, where `field` is a struct declaration with
7067 * default construction disabled, we must make sure that
7068 * assigning to `var` does not imply that `field` was initialized
7069 */
7070 if (sc.func && sc.func.isCtorDeclaration())
7071 {
7072 // if inside a constructor scope and e1 of this DotVarExp
7073 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
7074 if (auto dve = dotVarExp.e1.isDotVarExp())
7075 {
7076 // Iterate the chain of DotVarExp to find `this`
7077 // Keep track whether access to fields was limited to union members
7078 // s.t. one can initialize an entire struct inside nested unions
7079 // (but not its members)
7080 bool onlyUnion = true;
7081 while (true)
7082 {
7083 auto v = dve.var.isVarDeclaration();
7084 assert(v);
7085
7086 // Accessing union member?
7087 auto t = v.type.isTypeStruct();
7088 if (!t || !t.sym.isUnionDeclaration())
7089 onlyUnion = false;
7090
7091 // Another DotVarExp left?
7092 if (!dve.e1 || dve.e1.op != EXP.dotVariable)
7093 break;
7094
7095 dve = cast(DotVarExp) dve.e1;
7096 }
7097
7098 if (dve.e1.op == EXP.this_)
7099 {
7100 scope v = dve.var.isVarDeclaration();
7101 /* if v is a struct member field with no initializer, no default construction
7102 * and v wasn't intialized before
7103 */
7104 if (v && v.isField() && !v._init && !v.ctorinit)
7105 {
7106 if (auto ts = v.type.isTypeStruct())
7107 {
7108 if (ts.sym.noDefaultCtor)
7109 {
7110 /* checkModify will consider that this is an initialization
7111 * of v while it is actually an assignment of a field of v
7112 */
7113 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
7114 if (modifyLevel == Modifiable.initialization)
7115 {
7116 // https://issues.dlang.org/show_bug.cgi?id=22118
7117 // v is a union type field that was assigned
7118 // a variable, therefore it counts as initialization
7119 if (v.ctorinit)
7120 return Modifiable.initialization;
7121
7122 return Modifiable.yes;
7123 }
7124 return modifyLevel;
7125 }
7126 }
7127 }
7128 }
7129 }
7130 }
7131
7132 //printf("\te1 = %s\n", e1.toChars());
7133 return dotVarExp.e1.checkModifiable(sc, flag);
7134
7135 case EXP.star:
7136 auto ptrExp = cast(PtrExp)exp;
7137 if (auto se = ptrExp.e1.isSymOffExp())
7138 {
7139 return se.var.checkModify(ptrExp.loc, sc, null, flag);
7140 }
7141 else if (auto ae = ptrExp.e1.isAddrExp())
7142 {
7143 return ae.e1.checkModifiable(sc, flag);
7144 }
7145 return Modifiable.yes;
7146
7147 case EXP.slice:
7148 auto sliceExp = cast(SliceExp)exp;
7149
7150 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
7151 auto e1 = sliceExp.e1;
7152 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
7153 {
7154 return e1.checkModifiable(sc, flag);
7155 }
7156 return Modifiable.yes;
7157
7158 case EXP.comma:
7159 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
7160
7161 case EXP.index:
7162 auto indexExp = cast(IndexExp)exp;
7163 auto e1 = indexExp.e1;
7164 if (e1.type.ty == Tsarray ||
7165 e1.type.ty == Taarray ||
7166 (e1.op == EXP.index && e1.type.ty != Tarray) ||
7167 e1.op == EXP.slice)
7168 {
7169 return e1.checkModifiable(sc, flag);
7170 }
7171 return Modifiable.yes;
7172
7173 case EXP.question:
7174 auto condExp = cast(CondExp)exp;
7175 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
7176 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
7177 return Modifiable.yes;
7178 return Modifiable.no;
7179
7180 default:
7181 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
7182 }
7183 }
7184
7185 /******************************
7186 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
7187 */
7188 private immutable ubyte[EXP.max + 1] exptab =
7189 () {
7190 ubyte[EXP.max + 1] tab;
with(EXPFLAGS)7191 with (EXPFLAGS)
7192 {
7193 foreach (i; Eunary) { tab[i] |= unary; }
7194 foreach (i; Ebinary) { tab[i] |= unary | binary; }
7195 foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
7196 }
7197 return tab;
7198 } ();
7199
7200 private enum EXPFLAGS : ubyte
7201 {
7202 unary = 1,
7203 binary = 2,
7204 binaryAssign = 4,
7205 }
7206
7207 private enum Eunary =
7208 [
7209 EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
7210 EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
7211 EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
7212 EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
7213 EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
7214 ];
7215
7216 private enum Ebinary =
7217 [
7218 EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
7219 EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
7220 EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
7221 EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
7222 EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
7223 EXP.question,
7224 EXP.construct, EXP.blit,
7225 ];
7226
7227 private enum EbinaryAssign =
7228 [
7229 EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
7230 EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
7231 EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
7232 EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
7233 ];
7234