dmd.clone

Define the implicit opEquals, opAssign, post blit, copy constructor and destructor for structs.

Authors

Walter Bright

Source: clone.d

  • Declaration

    pure StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f);

    Merge function attributes pure, nothrow, @safe, @nogc, and @disable from f into s1.

    Parameters

    StorageClass s1

    storage class to merge into

    FuncDeclaration f

    function

    Return Value

    merged storage class

  • Declaration

    FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc);

    Check given aggregate actually has an identity opAssign or not.

    Parameters

    AggregateDeclaration ad

    struct or class

    Scope* sc

    current scope

    Return Value

    if found, returns FuncDeclaration of opAssign, otherwise null

  • Declaration

    FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc);

    Build opAssign for a struct.

    Discussion

    The generated opAssign function has the following signature:

    1. ref S opAssign(S s) // S is the name of the `struct`


    The opAssign function will be built for a struct S if the following constraints are met:
    1. S does not have an identity opAssign defined.
    2. S has at least one of the following members: a postblit (user-defined or)
    3. generated for fields that have a defined postblit
    , a destructor (user-defined or generated for fields that have a defined destructor) or at least one field that has a defined opAssign.
    1. S does not have any non-mutable fields.
    If S has a disabled destructor or at least one field that has a disabled opAssign, S.opAssign is going to be generated, but marked with @disable

    If S defines a destructor, the generated code for opAssign is:

    1. S __swap = void; __swap = this; // bit copy this = s; // bit copy __swap.dtor();


    Otherwise, if S defines a postblit, the generated code for opAssign is:

    1. this = s;


    Note that the parameter to the generated opAssign is passed by value, which means that the postblit is going to be called (if it is defined) in both of the above situations before entering the body of opAssign. The assignments in the above generated function bodies are blit expressions, so they can be regarded as memcpys (opAssign is not called as this will result in an infinite recursion; the postblit is not called because it has already been called when the parameter was passed by value).

    If S does not have a postblit or a destructor, but contains at least one field that defines an opAssign function (which is not disabled), then the body will make member-wise assignments:

    1. this.field1 = s.field1; this.field2 = s.field2; ...;


    In this situation, the assignemnts are actual assign expressions (opAssign is used if defined).

    Parameters

    StructDeclaration sd

    struct to generate opAssign for

    Scope* sc

    context

    Return Value

    generated opAssign function

  • Declaration

    bool needOpEquals(StructDeclaration sd);

    We need an opEquals for the struct if any fields has an opEquals. Generate one if a user-specified one does not exist.

  • Declaration

    FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc);

    Build opEquals for struct. const bool opEquals(const S s) { ... }

    Discussion

    By fixing https://issues.dlang.org/show_bug.cgi?id=3789 opEquals is changed to be never implicitly generated. Now, struct objects comparison s1 == s2 is translated to: s1.tupleof == s2.tupleof to calculate structural equality. See EqualExp.op_overload.

  • Declaration

    FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc);

    Build __xopEquals for TypeInfo_Struct static bool __xopEquals(ref const S p, ref const S q) { return p == q; }

    Discussion

    This is called by TypeInfo.equals(p1, p2). If the struct does not support const objects comparison, it will throw "not implemented" Error in runtime.

  • Declaration

    FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc);

    Build __xopCmp for TypeInfo_Struct static bool __xopCmp(ref const S p, ref const S q) { return p.opCmp(q); }

    Discussion

    This is called by TypeInfo.compare(p1, p2). If the struct does not support const objects comparison, it will throw "not implemented" Error in runtime.

  • Declaration

    FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc);

    Build _xtoHash for non-bitwise hashing static hash_t xtoHash(ref const S p) nothrow @trusted;

  • Declaration

    DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc);

    Create inclusive destructor for struct/class by aggregating all the destructors in dtors[] with the destructors for all the members.

    Parameters

    AggregateDeclaration ad

    struct or class to build destructor for

    Scope* sc

    context

    Return Value

    generated function, null if none needed

    Note: Close similarity with StructDeclaration::buildPostBlit(), and the ordering changes (runs backward instead of forwards).

  • Declaration

    DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc);

    build a shim function around the compound dtor that translates a C++ destructor to a destructor with extern(D) calling convention

    Parameters

    AggregateDeclaration ad

    the aggregate that contains the destructor to wrap

    Scope* sc

    the scope in which to analyze the new function

    Return Value

    the shim destructor, semantically analyzed and added to the class as a member

  • Declaration

    FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc);

    Create inclusive invariant for struct/class by aggregating all the invariants in invs[].

    1. void __invariant() const [pure nothrow @trusted] { invs[0](), invs[1](), ...; }