@@ -566,6 +566,271 @@ $(GNAME Postblit):
566
566
}
567
567
---
568
568
569
+ $(P Depending on the struct layout, the compiler may generate the following
570
+ internal postblit functions:)
571
+
572
+ $(OL
573
+ $(LI `void __postblit()`. The compiler assigns this name to the explicitly
574
+ defined postblit `this(this)` so that it can be treated exactly as
575
+ a normal function. Note that if a struct defines a postblit, it cannot
576
+ define a function named `__postblit` - no matter the signature -
577
+ as this would result in a compilation error due to the name conflict.)
578
+ $(LI `void __fieldPostblit()`. If a struct `X` has at least one `struct`
579
+ member that in turn defines (explicitly or implicitly) a postblit, then a field
580
+ postblit is generated for `X` that calls all the underlying postblits
581
+ of the struct fields in declaration order.)
582
+ $(LI `void __aggrPostblit()`. If a struct has an explicitly defined postblit
583
+ and at least 1 struct member that has a postblit (explicit or implicit)
584
+ an aggregated postblit is generated which calls `__fieldPostblit` first
585
+ and then `__postblit`.)
586
+ $(LI `void __xpostblit()`. The field and aggregated postblits, although
587
+ generated for a struct, are not actual struct members. In order to be able
588
+ to call them, the compiler internally creates an alias, called `__xpostblit`
589
+ which is a member of the struct and which points to the generated postblit that
590
+ is the most inclusive.)
591
+ )
592
+
593
+ $(SPEC_RUNNABLE_EXAMPLE_COMPILE
594
+ ---
595
+ // struct with alias __xpostblit = __postblit
596
+ struct X
597
+ {
598
+ this(this) {}
599
+ }
600
+
601
+ // struct with alias __xpostblit = __fieldPostblit
602
+ // which contains a call to X.__xpostblit
603
+ struct Y
604
+ {
605
+ X a;
606
+ }
607
+
608
+ // struct with alias __xpostblit = __aggrPostblit which contains
609
+ // a call to Y.__xpostblit and a call to Z.__postblit
610
+ struct Z
611
+ {
612
+ Y a;
613
+ this(this) {}
614
+ }
615
+
616
+ void main()
617
+ {
618
+ // X has __postblit and __xpostblit (pointing to __postblit)
619
+ static assert(__traits(hasMember, X, "__postblit"));
620
+ static assert(__traits(hasMember, X, "__xpostblit"));
621
+
622
+ // Y does not have __postblit, but has __xpostblit (pointing to __fieldPostblit)
623
+ static assert(!__traits(hasMember, Y, "__postblit"));
624
+ static assert(__traits(hasMember, Y, "__xpostblit"));
625
+ // __fieldPostblit is not a member of the struct
626
+ static assert(!__traits(hasMember, Y, "__fieldPostblit"));
627
+
628
+ // Z has __postblit and __xpostblit (pointing to __aggrPostblit)
629
+ static assert(__traits(hasMember, Z, "__postblit"));
630
+ static assert(__traits(hasMember, Z, "__xpostblit"));
631
+ // __aggrPostblit is not a member of the struct
632
+ static assert(!__traits(hasMember, Z, "__aggrPostblit"));
633
+ }
634
+ ---
635
+ )
636
+
637
+ $(P Neither of the above postblits is defined for structs that don't
638
+ define `this(this)` and don't have fields that transitively define it.
639
+ If a struct does not define a postblit (implicit or explicit) but
640
+ defines functions that use the same name/signature as the internally
641
+ generated postblits, the compiler is able to identify that the functions
642
+ are not actual postblits and does not insert calls to them when the
643
+ struct is copied. Example:)
644
+
645
+ $(SPEC_RUNNABLE_EXAMPLE_COMPILE
646
+ ---
647
+ struct X
648
+ {}
649
+
650
+ int a;
651
+
652
+ struct Y
653
+ {
654
+ int a;
655
+ X b;
656
+ void __fieldPostPostblit()
657
+ {
658
+ a = 42;
659
+ }
660
+ }
661
+
662
+ void main()
663
+ {
664
+ static assert(!__traits(hasMember, X, "__postblit"));
665
+ static assert(!__traits(hasMember, X, "__xpostblit"));
666
+
667
+ static assert(!__traits(hasMember, Y, "__postblit"));
668
+ static assert(!__traits(hasMember, Y, "__xpostblit"));
669
+
670
+ Y y;
671
+ auto y2 = y;
672
+ assert(a == 0); // __fieldPostBlit does not get called
673
+ }
674
+ ---
675
+ )
676
+
677
+ $(P Postblits cannot be overloaded. If two or more postblits are defined,
678
+ even if the signatures differ, the compiler assigns the
679
+ `__postblit` name to both and later issues a conflicting function
680
+ name error:)
681
+
682
+ ---
683
+ struct X
684
+ {
685
+ this(this) {}
686
+ this(this) const {} // error: function X.__postblit conflicts with function X.__postblit
687
+ }
688
+ ---
689
+
690
+ $(P The following describes the behavior of the
691
+ qualified postblit definitions:)
692
+
693
+ $(OL
694
+ $(LI `const`. When a postblit is qualified with `const` as in
695
+ $(D this(this) const;) or $(D const this(this);) then the postblit
696
+ is succesfully called on mutable (unqualified), `const`,
697
+ and `immutable` objects, but the postblit cannot modify the object
698
+ because it regards it as `const`; hence `const` postblits are of
699
+ limited usefulness. Example:)
700
+
701
+ $(SPEC_RUNNABLE_EXAMPLE_COMPILE
702
+ ---
703
+ struct S
704
+ {
705
+ int n;
706
+ this(this) const
707
+ {
708
+ import std.stdio : writeln;
709
+ writeln("postblit called");
710
+ //++n; // error: cannot modify this.n in `const` function
711
+ }
712
+ }
713
+
714
+ void main()
715
+ {
716
+ S s1;
717
+ auto s2 = s1;
718
+ const S s3;
719
+ auto s4 = s3;
720
+ immutable S s5;
721
+ auto s6 = s5;
722
+ }
723
+ ---
724
+ )
725
+ $(LI `immutable`. When a postblit is qualified with `immutable`
726
+ as in $(D this(this) immutable) or $(D immutable this(this))
727
+ the code is ill-formed. The `immutable` postblit passes the
728
+ compilation phase but cannot be invoked. Example:)
729
+
730
+ ---
731
+ struct Y
732
+ {
733
+ // not invoked anywhere, no error is issued
734
+ this(this) immutable
735
+ { }
736
+ }
737
+
738
+ struct S
739
+ {
740
+ this(this) immutable
741
+ { }
742
+ }
743
+
744
+ void main()
745
+ {
746
+ S s1;
747
+ auto s2 = s1; // error: immutable method `__postblit` is not callable using a mutable object
748
+ const S s3;
749
+ auto s4 = s3; // error: immutable method `__postblit` is not callable using a mutable object
750
+ immutable S s5;
751
+ auto s6 = s5; // error: immutable method `__postblit` is not callable using a mutable object
752
+ }
753
+ ---
754
+
755
+ $(LI `shared`. When a postblit is qualified with `shared` as in
756
+ $(D this(this) shared) or $(D shared this(this)) solely `shared`
757
+ objects may invoke the postblit; attempts of postbliting unshared
758
+ objects will result in compile time errors:)
759
+
760
+ ---
761
+ struct S
762
+ {
763
+ this(this) shared
764
+ { }
765
+ }
766
+
767
+ void main()
768
+ {
769
+ S s1;
770
+ auto s2 = s1; // error: shared method `__postblit` is not callable using a non-shared object
771
+ const S s3;
772
+ auto s4 = s3; // error: shared method `__postblit` is not callable using a non-shared object
773
+ immutable S s5;
774
+ auto s6 = s5; // error: shared method `__postblit` is not callable using a non-shared object
775
+
776
+ // calling the shared postblit on a shared object is accepted
777
+ shared S s7;
778
+ auto s8 = s7;
779
+ }
780
+ ---
781
+ )
782
+
783
+ $(P An unqualified postblit will get called even if the
784
+ struct is instantiated as `immutable` or `const`, but
785
+ the compiler issues an error if the struct is instantiated
786
+ as shared:)
787
+
788
+ $(SPEC_RUNNABLE_EXAMPLE_COMPILE
789
+ ---
790
+ struct S
791
+ {
792
+ int n;
793
+ this(this) { ++n; }
794
+ }
795
+
796
+ void main()
797
+ {
798
+ immutable S a; // shared S a; => error : non-shared method is not callable using a shared object
799
+ auto a2 = a;
800
+ import std.stdio: writeln;
801
+ writeln(a2.n); // prints 1
802
+ }
803
+ ---
804
+ )
805
+
806
+ $(P From a postblit perspective, qualifiying the struct definition
807
+ yields the same result as explicitly qualifying the postblit.)
808
+
809
+ $(P The following table lists all the possibilities of grouping
810
+ qualifiers for a postblit associated with the type of object that
811
+ needs to be used in order to succesfully invoke the postblit:)
812
+
813
+ $(TABLE_10 $(ARGS Qualifier Groups),
814
+ $(VERTROW object type to be invoked on, $(D const), $(D immutable), $(D shared)),
815
+ $(TROW any object type, $(YES), $(NO), $(NO) )
816
+ $(TROW uncallable, $(NO), $(YES), $(NO) )
817
+ $(TROW shared object, $(NO), $(NO), $(YES))
818
+ $(TROW uncallable, $(YES), $(YES), $(NO) )
819
+ $(TROW shared object, $(YES), $(NO), $(YES))
820
+ $(TROW uncallable, $(NO), $(YES), $(YES))
821
+ $(TROW uncallable, $(YES), $(YES), $(YES))
822
+ )
823
+
824
+ $(P Note that when `const` and `immutable` are used to explicitly
825
+ qualify a postblit as in `this(this) const immutable;` or
826
+ `const immutable this(this);` - the order in which the qualifiers
827
+ are declared does not matter - the compiler generates a `conflicting
828
+ attribute error`, however declaring the struct as `const`/`immutable`
829
+ and the postblit as `immutable`/`const` achieves the effect of applying
830
+ both qualifiers to the postblit. In both cases the postblit is
831
+ qualified with the more restrictive qualifier, which is `immutable`.
832
+ )
833
+
569
834
$(P Unions may not have fields that have postblits.)
570
835
571
836
$(H2 $(LEGACY_LNAME2 StructDestructor, struct-destructor, Struct Destructors))
0 commit comments