Mercurial > projects > ddmd
comparison dmd/VarDeclaration.d @ 179:cd48cb899aee
Updated to dmd2.040
author | korDen |
---|---|
date | Sun, 17 Oct 2010 20:56:07 +0400 |
parents | e3afd1303184 |
children | b0d41ff5e0df |
comparison
equal
deleted
inserted
replaced
178:e3afd1303184 | 179:cd48cb899aee |
---|---|
462 TOK op = TOK.TOKconstruct; | 462 TOK op = TOK.TOKconstruct; |
463 if (!init && !sc.inunion && !isStatic() && fd && | 463 if (!init && !sc.inunion && !isStatic() && fd && |
464 (!(storage_class & (STC.STCfield | STC.STCin | STC.STCforeach | STC.STCparameter)) || (storage_class & STC.STCout)) && | 464 (!(storage_class & (STC.STCfield | STC.STCin | STC.STCforeach | STC.STCparameter)) || (storage_class & STC.STCout)) && |
465 type.size() != 0) | 465 type.size() != 0) |
466 { | 466 { |
467 // Provide a default initializer | 467 // Provide a default initializer |
468 //printf("Providing default initializer for '%s'\n", toChars()); | 468 //printf("Providing default initializer for '%s'\n", toChars()); |
469 if (type.ty == TY.Tstruct && | 469 if (type.ty == TY.Tstruct && |
470 (cast(TypeStruct)type).sym.zeroInit) | 470 (cast(TypeStruct)type).sym.zeroInit) |
471 { /* If a struct is all zeros, as a special case | 471 { /* If a struct is all zeros, as a special case |
472 * set it's initializer to the integer 0. | 472 * set it's initializer to the integer 0. |
473 * In AssignExp.toElem(), we check for this and issue | 473 * In AssignExp.toElem(), we check for this and issue |
474 * a memset() to initialize the struct. | 474 * a memset() to initialize the struct. |
475 * Must do same check in interpreter. | 475 * Must do same check in interpreter. |
476 */ | 476 */ |
477 Expression e = new IntegerExp(loc, 0, Type.tint32); | 477 Expression e = new IntegerExp(loc, 0, Type.tint32); |
478 Expression e1; | 478 Expression e1; |
479 e1 = new VarExp(loc, this); | 479 e1 = new VarExp(loc, this); |
480 e = new AssignExp(loc, e1, e); | 480 e = new AssignExp(loc, e1, e); |
481 e.op = TOK.TOKconstruct; | 481 e.op = TOK.TOKconstruct; |
482 e.type = e1.type; // don't type check this, it would fail | 482 e.type = e1.type; // don't type check this, it would fail |
483 init = new ExpInitializer(loc, e); | 483 init = new ExpInitializer(loc, e); |
484 return; | 484 return; |
485 } | 485 } |
486 else if (type.ty == TY.Ttypedef) | 486 else if (type.ty == TY.Ttypedef) |
487 { TypeTypedef td = cast(TypeTypedef)type; | 487 { |
488 if (td.sym.init) | 488 TypeTypedef td = cast(TypeTypedef)type; |
489 { init = td.sym.init; | 489 if (td.sym.init) |
490 ExpInitializer ie = init.isExpInitializer(); | 490 { |
491 if (ie) | 491 init = td.sym.init; |
492 // Make copy so we can modify it | 492 ExpInitializer ie = init.isExpInitializer(); |
493 init = new ExpInitializer(ie.loc, ie.exp); | 493 if (ie) |
494 // Make copy so we can modify it | |
495 init = new ExpInitializer(ie.loc, ie.exp); | |
496 } | |
497 else | |
498 init = getExpInitializer(); | |
494 } | 499 } |
495 else | 500 else |
496 init = getExpInitializer(); | 501 { |
497 } | 502 init = getExpInitializer(); |
498 else | 503 } |
499 { | 504 // Default initializer is always a blit |
500 init = getExpInitializer(); | 505 op = TOK.TOKblit; |
501 } | |
502 // Default initializer is always a blit | |
503 op = TOK.TOKblit; | |
504 } | 506 } |
505 | 507 |
506 if (init) | 508 if (init) |
507 { | 509 { |
508 sc = sc.push(); | 510 sc = sc.push(); |
509 sc.stc &= ~(STC.STC_TYPECTOR | STC.STCpure | STC.STCnothrow | STC.STCref); | 511 sc.stc &= ~(STC.STC_TYPECTOR | STC.STCpure | STC.STCnothrow | STC.STCref | STCdisable); |
510 | 512 |
511 ArrayInitializer ai = init.isArrayInitializer(); | 513 ArrayInitializer ai = init.isArrayInitializer(); |
512 if (ai && tb.ty == TY.Taarray) | 514 if (ai && tb.ty == TY.Taarray) |
513 { | 515 { |
514 Expression e = ai.toAssocArrayLiteral(); | 516 Expression e = ai.toAssocArrayLiteral(); |
515 init = new ExpInitializer(e.loc, e); | 517 init = new ExpInitializer(e.loc, e); |
516 } | 518 } |
517 | 519 |
518 StructInitializer si = init.isStructInitializer(); | 520 StructInitializer si = init.isStructInitializer(); |
519 ExpInitializer ei = init.isExpInitializer(); | 521 ExpInitializer ei = init.isExpInitializer(); |
520 | 522 |
521 // See if initializer is a NewExp that can be allocated on the stack | 523 // See if initializer is a NewExp that can be allocated on the stack |
522 if (ei && isScope() && ei.exp.op == TOK.TOKnew) | 524 if (ei && isScope() && ei.exp.op == TOK.TOKnew) |
523 { NewExp ne = cast(NewExp)ei.exp; | 525 { NewExp ne = cast(NewExp)ei.exp; |
524 if (!(ne.newargs && ne.newargs.dim)) | 526 if (!(ne.newargs && ne.newargs.dim)) |
525 { ne.onstack = 1; | 527 { ne.onstack = 1; |
526 onstack = 1; | 528 onstack = 1; |
527 if (type.isBaseOf(ne.newtype.semantic(loc, sc), null)) | 529 if (type.isBaseOf(ne.newtype.semantic(loc, sc), null)) |
528 onstack = 2; | 530 onstack = 2; |
529 } | 531 } |
530 } | 532 } |
531 | 533 |
532 // If inside function, there is no semantic3() call | 534 // If inside function, there is no semantic3() call |
533 if (sc.func) | 535 if (sc.func) |
534 { | 536 { |
535 // If local variable, use AssignExp to handle all the various | 537 // If local variable, use AssignExp to handle all the various |
536 // possibilities. | 538 // possibilities. |
537 if (fd && | 539 if (fd && |
538 !(storage_class & (STC.STCmanifest | STC.STCstatic | STC.STCtls | STC.STCgshared | STC.STCextern)) && | 540 !(storage_class & (STC.STCmanifest | STC.STCstatic | STC.STCtls | STC.STCgshared | STC.STCextern)) && |
539 !init.isVoidInitializer()) | 541 !init.isVoidInitializer()) |
540 { | 542 { |
541 //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars()); | 543 //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars()); |
542 if (!ei) | 544 if (!ei) |
543 { | 545 { |
544 Expression e = init.toExpression(); | 546 Expression e = init.toExpression(); |
545 if (!e) | 547 if (!e) |
548 { | |
549 init = init.semantic(sc, type); | |
550 e = init.toExpression(); | |
551 if (!e) | |
552 { error("is not a static and cannot have static initializer"); | |
553 return; | |
554 } | |
555 } | |
556 ei = new ExpInitializer(init.loc, e); | |
557 init = ei; | |
558 } | |
559 | |
560 Expression e1 = new VarExp(loc, this); | |
561 | |
562 Type t = type.toBasetype(); | |
563 if (t.ty == TY.Tsarray && !(storage_class & (STC.STCref | STC.STCout))) | |
564 { | |
565 ei.exp = ei.exp.semantic(sc); | |
566 if (!ei.exp.implicitConvTo(type)) | |
567 { | |
568 int dim = cast(int)(cast(TypeSArray)t).dim.toInteger(); /// | |
569 // If multidimensional static array, treat as one large array | |
570 while (1) | |
571 { | |
572 t = t.nextOf().toBasetype(); | |
573 if (t.ty != TY.Tsarray) | |
574 break; | |
575 dim *= (cast(TypeSArray)t).dim.toInteger(); | |
576 e1.type = new TypeSArray(t.nextOf(), new IntegerExp(Loc(0), dim, Type.tindex)); | |
577 } | |
578 } | |
579 e1 = new SliceExp(loc, e1, null, null); | |
580 } | |
581 else if (t.ty == TY.Tstruct) | |
582 { | |
583 ei.exp = ei.exp.semantic(sc); | |
584 ei.exp = resolveProperties(sc, ei.exp); | |
585 StructDeclaration sd = (cast(TypeStruct)t).sym; | |
586 version (DMDV2) | |
587 { | |
588 /* Look to see if initializer is a call to the constructor | |
589 */ | |
590 if (sd.ctor && // there are constructors | |
591 ei.exp.type.ty == TY.Tstruct && // rvalue is the same struct | |
592 (cast(TypeStruct)ei.exp.type).sym == sd && | |
593 ei.exp.op == TOK.TOKstar) | |
594 { | |
595 /* Look for form of constructor call which is: | |
596 * *__ctmp.ctor(arguments...) | |
597 */ | |
598 PtrExp pe = cast(PtrExp)ei.exp; | |
599 if (pe.e1.op == TOK.TOKcall) | |
600 { CallExp ce = cast(CallExp)pe.e1; | |
601 if (ce.e1.op == TOK.TOKdotvar) | |
602 { DotVarExp dve = cast(DotVarExp)ce.e1; | |
603 if (dve.var.isCtorDeclaration()) | |
604 { /* It's a constructor call, currently constructing | |
605 * a temporary __ctmp. | |
606 */ | |
607 /* Before calling the constructor, initialize | |
608 * variable with a bit copy of the default | |
609 * initializer | |
610 */ | |
611 Expression e = new AssignExp(loc, new VarExp(loc, this), t.defaultInit(loc)); | |
612 e.op = TOK.TOKblit; | |
613 e.type = t; | |
614 ei.exp = new CommaExp(loc, e, ei.exp); | |
615 | |
616 /* Replace __ctmp being constructed with e1 | |
617 */ | |
618 dve.e1 = e1; | |
619 return; | |
620 } | |
621 } | |
622 } | |
623 } | |
624 } | |
625 if (!ei.exp.implicitConvTo(type)) | |
626 { | |
627 Type ti = ei.exp.type.toBasetype(); | |
628 // Look for constructor first | |
629 if (sd.ctor && | |
630 /* Initializing with the same type is done differently | |
631 */ | |
632 !(ti.ty == Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) | |
633 { | |
634 // Rewrite as e1.ctor(arguments) | |
635 Expression ector = new DotIdExp(loc, e1, Id.ctor); | |
636 ei.exp = new CallExp(loc, ector, ei.exp); | |
637 } | |
638 else | |
639 /* Look for opCall | |
640 * See bugzilla 2702 for more discussion | |
641 */ | |
642 | |
643 // Don't cast away invariant or mutability in initializer | |
644 if (search_function(sd, Id.call) && | |
645 /* Initializing with the same type is done differently | |
646 */ | |
647 !(ti.ty == Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) | |
648 { // Rewrite as e1.call(arguments) | |
649 Expression eCall = new DotIdExp(loc, e1, Id.call); | |
650 ei.exp = new CallExp(loc, eCall, ei.exp); | |
651 } | |
652 } | |
653 } | |
654 ei.exp = new AssignExp(loc, e1, ei.exp); | |
655 ei.exp.op = op; | |
656 canassign++; | |
657 ei.exp = ei.exp.semantic(sc); | |
658 canassign--; | |
659 ei.exp.optimize(WANT.WANTvalue); | |
660 } | |
661 else | |
546 { | 662 { |
547 init = init.semantic(sc, type); | 663 init = init.semantic(sc, type); |
548 e = init.toExpression(); | 664 } |
549 if (!e) | 665 } |
550 { error("is not a static and cannot have static initializer"); | 666 else if (storage_class & (STC.STCconst | STC.STCimmutable | STC.STCmanifest) || |
551 return; | 667 type.isConst() || type.isImmutable() || |
552 } | 668 parent.isAggregateDeclaration()) |
553 } | 669 { |
554 ei = new ExpInitializer(init.loc, e); | 670 /* Because we may need the results of a const declaration in a |
555 init = ei; | 671 * subsequent type, such as an array dimension, before semantic2() |
556 } | 672 * gets ordinarily run, try to run semantic2() now. |
557 | 673 * Ignore failure. |
558 Expression e1 = new VarExp(loc, this); | 674 */ |
559 | 675 |
560 Type t = type.toBasetype(); | 676 if (!global.errors && !inferred) |
561 if (t.ty == TY.Tsarray && !(storage_class & (STC.STCref | STC.STCout))) | |
562 { | |
563 ei.exp = ei.exp.semantic(sc); | |
564 if (!ei.exp.implicitConvTo(type)) | |
565 { | 677 { |
566 int dim = cast(int)(cast(TypeSArray)t).dim.toInteger(); /// | 678 uint errors = global.errors; |
567 // If multidimensional static array, treat as one large array | 679 global.gag++; |
568 while (1) | 680 //printf("+gag\n"); |
569 { | 681 Expression e; |
570 t = t.nextOf().toBasetype(); | 682 Initializer i2 = init; |
571 if (t.ty != TY.Tsarray) | 683 inuse++; |
572 break; | 684 if (ei) |
573 dim *= (cast(TypeSArray)t).dim.toInteger(); | 685 { |
574 e1.type = new TypeSArray(t.nextOf(), new IntegerExp(Loc(0), dim, Type.tindex)); | 686 e = ei.exp.syntaxCopy(); |
575 } | 687 e = e.semantic(sc); |
576 } | 688 e = resolveProperties(sc, e); |
577 e1 = new SliceExp(loc, e1, null, null); | 689 version (DMDV2) { |
578 } | 690 /* The problem is the following code: |
579 else if (t.ty == TY.Tstruct) | 691 * struct CopyTest { |
580 { | 692 * double x; |
581 ei.exp = ei.exp.semantic(sc); | 693 * this(double a) { x = a * 10.0;} |
582 ei.exp = resolveProperties(sc, ei.exp); | 694 * this(this) { x += 2.0; } |
583 StructDeclaration sd = (cast(TypeStruct)t).sym; | 695 * } |
584 version (DMDV2) | 696 * const CopyTest z = CopyTest(5.3); // ok |
585 { | 697 * const CopyTest w = z; // not ok, postblit not run |
586 /* Look to see if initializer is a call to the constructor | 698 * static assert(w.x == 55.0); |
587 */ | 699 * because the postblit doesn't get run on the initialization of w. |
588 if (sd.ctor && // there are constructors | 700 */ |
589 ei.exp.type.ty == TY.Tstruct && // rvalue is the same struct | 701 |
590 (cast(TypeStruct)ei.exp.type).sym == sd && | 702 Type tb_ = e.type.toBasetype(); |
591 ei.exp.op == TOK.TOKstar) | 703 if (tb_.ty == Tstruct) |
592 { | 704 { |
593 /* Look for form of constructor call which is: | 705 StructDeclaration sd = (cast(TypeStruct)tb_).sym; |
594 * *__ctmp.ctor(arguments...) | 706 Type typeb = type.toBasetype(); |
595 */ | 707 /* Look to see if initializer involves a copy constructor |
596 PtrExp pe = cast(PtrExp)ei.exp; | 708 * (which implies a postblit) |
597 if (pe.e1.op == TOK.TOKcall) | |
598 { CallExp ce = cast(CallExp)pe.e1; | |
599 if (ce.e1.op == TOK.TOKdotvar) | |
600 { DotVarExp dve = cast(DotVarExp)ce.e1; | |
601 if (dve.var.isCtorDeclaration()) | |
602 { /* It's a constructor call, currently constructing | |
603 * a temporary __ctmp. | |
604 */ | 709 */ |
605 /* Before calling the constructor, initialize | 710 if (sd.cpctor && // there is a copy constructor |
606 * variable with a bit copy of the default | 711 typeb.equals(tb_)) // rvalue is the same struct |
607 * initializer | 712 { |
713 // The only allowable initializer is a (non-copy) constructor | |
714 if (e.op == TOKcall) | |
715 { | |
716 CallExp ce = cast(CallExp)e; | |
717 if (ce.e1.op == TOKdotvar) | |
718 { | |
719 DotVarExp dve = cast(DotVarExp)ce.e1; | |
720 if (dve.var.isCtorDeclaration()) | |
721 goto LNoCopyConstruction; | |
722 } | |
723 } | |
724 global.gag--; | |
725 error("of type struct %s uses this(this), which is not allowed in static initialization", typeb.toChars()); | |
726 global.gag++; | |
727 | |
728 LNoCopyConstruction: | |
729 ; | |
730 } | |
731 } | |
732 } | |
733 e = e.implicitCastTo(sc, type); | |
734 } | |
735 else if (si || ai) | |
736 { | |
737 i2 = init.syntaxCopy(); | |
738 i2 = i2.semantic(sc, type); | |
739 } | |
740 inuse--; | |
741 global.gag--; | |
742 //printf("-gag\n"); | |
743 if (errors != global.errors) // if errors happened | |
744 { | |
745 if (global.gag == 0) | |
746 global.errors = errors; // act as if nothing happened | |
747 version (DMDV2) { | |
748 /* Save scope for later use, to try again | |
608 */ | 749 */ |
609 Expression e = new AssignExp(loc, new VarExp(loc, this), t.defaultInit(loc)); | 750 scope_ = sc.clone(); |
610 e.op = TOK.TOKblit; | 751 scope_.setNoFree(); |
611 e.type = t; | 752 } |
612 ei.exp = new CommaExp(loc, e, ei.exp); | 753 } |
613 | 754 else if (ei) |
614 /* Replace __ctmp being constructed with e1 | |
615 */ | |
616 dve.e1 = e1; | |
617 return; | |
618 } | |
619 } | |
620 } | |
621 } | |
622 } | |
623 if (!ei.exp.implicitConvTo(type)) | |
624 { | |
625 Type ti = ei.exp.type.toBasetype(); | |
626 // Look for constructor first | |
627 if (sd.ctor && | |
628 /* Initializing with the same type is done differently | |
629 */ | |
630 !(ti.ty == Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) | |
631 { | 755 { |
632 // Rewrite as e1.ctor(arguments) | 756 if (isDataseg()) |
633 Expression ector = new DotIdExp(loc, e1, Id.ctor); | 757 /* static const/invariant does CTFE |
634 ei.exp = new CallExp(loc, ector, ei.exp); | 758 */ |
635 } | 759 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); |
760 else | |
761 e = e.optimize(WANT.WANTvalue); | |
762 if (e.op == TOK.TOKint64 || e.op == TOK.TOKstring || e.op == TOK.TOKfloat64) | |
763 { | |
764 ei.exp = e; // no errors, keep result | |
765 } | |
766 ///version (DMDV2) { | |
767 else | |
768 { | |
769 /* Save scope for later use, to try again | |
770 */ | |
771 scope_ = sc.clone(); | |
772 scope_.setNoFree(); | |
773 } | |
774 ///} | |
775 } | |
636 else | 776 else |
637 /* Look for opCall | 777 init = i2; // no errors, keep result |
638 * See bugzilla 2702 for more discussion | 778 } |
639 */ | 779 } |
640 | 780 sc = sc.pop(); |
641 // Don't cast away invariant or mutability in initializer | |
642 if (search_function(sd, Id.call) && | |
643 /* Initializing with the same type is done differently | |
644 */ | |
645 !(ti.ty == Tstruct && t.toDsymbol(sc) == ti.toDsymbol(sc))) | |
646 { // Rewrite as e1.call(arguments) | |
647 Expression eCall = new DotIdExp(loc, e1, Id.call); | |
648 ei.exp = new CallExp(loc, eCall, ei.exp); | |
649 } | |
650 } | |
651 } | |
652 ei.exp = new AssignExp(loc, e1, ei.exp); | |
653 ei.exp.op = op; | |
654 canassign++; | |
655 ei.exp = ei.exp.semantic(sc); | |
656 canassign--; | |
657 ei.exp.optimize(WANT.WANTvalue); | |
658 } | |
659 else | |
660 { | |
661 init = init.semantic(sc, type); | |
662 } | |
663 } | |
664 else if (storage_class & (STC.STCconst | STC.STCimmutable | STC.STCmanifest) || | |
665 type.isConst() || type.isImmutable() || | |
666 parent.isAggregateDeclaration()) | |
667 { | |
668 /* Because we may need the results of a const declaration in a | |
669 * subsequent type, such as an array dimension, before semantic2() | |
670 * gets ordinarily run, try to run semantic2() now. | |
671 * Ignore failure. | |
672 */ | |
673 | |
674 if (!global.errors && !inferred) | |
675 { | |
676 uint errors = global.errors; | |
677 global.gag++; | |
678 //printf("+gag\n"); | |
679 Expression e; | |
680 Initializer i2 = init; | |
681 inuse++; | |
682 if (ei) | |
683 { | |
684 e = ei.exp.syntaxCopy(); | |
685 e = e.semantic(sc); | |
686 e = e.implicitCastTo(sc, type); | |
687 } | |
688 else if (si || ai) | |
689 { i2 = init.syntaxCopy(); | |
690 i2 = i2.semantic(sc, type); | |
691 } | |
692 inuse--; | |
693 global.gag--; | |
694 //printf("-gag\n"); | |
695 if (errors != global.errors) // if errors happened | |
696 { | |
697 if (global.gag == 0) | |
698 global.errors = errors; // act as if nothing happened | |
699 version (DMDV2) { | |
700 /* Save scope for later use, to try again | |
701 */ | |
702 scope_ = sc.clone(); | |
703 scope_.setNoFree(); | |
704 } | |
705 } | |
706 else if (ei) | |
707 { | |
708 if (isDataseg()) | |
709 /* static const/invariant does CTFE | |
710 */ | |
711 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
712 else | |
713 e = e.optimize(WANT.WANTvalue); | |
714 if (e.op == TOK.TOKint64 || e.op == TOK.TOKstring || e.op == TOK.TOKfloat64) | |
715 { | |
716 ei.exp = e; // no errors, keep result | |
717 } | |
718 ///version (DMDV2) { | |
719 else | |
720 { | |
721 /* Save scope for later use, to try again | |
722 */ | |
723 scope_ = sc.clone(); | |
724 scope_.setNoFree(); | |
725 } | |
726 ///} | |
727 } | |
728 else | |
729 init = i2; // no errors, keep result | |
730 } | |
731 } | |
732 sc = sc.pop(); | |
733 } | 781 } |
734 } | 782 } |
735 | 783 |
736 override void semantic2(Scope sc) | 784 override void semantic2(Scope sc) |
737 { | 785 { |