Opened 12 months ago

#186 new defect

Cannot add extra assertion on a constructor

Reported by: mlbrooks Owned by:
Priority: major Component: cfa-cc
Version: 1.0 Keywords:
Cc:

Description

Conflicts or confusion happen when trying to declare a custom constructor, which intends to replace an autogen constructor, if the custom constructor is adding assertions beyond those of the struct declaration (which is the set of assertions that applies to visible autogen constructors). The replacement happens only partially; two examples are detailed below.

A simple example has neither constructor being callable.

struct S {};

forall( | {void sayHi();} )
void ?{}( S & this ) {
    sayHi();
}

void sayHi() {
    printf("hi\n");
}

int main() {
    S s;
}

Expected, simple: compile success with output

hi

Actual, simple: compiler error

Unique best alternative includes deleted identifier in Generated Cast of:
  Application of
    Deleted Expression
      Variable Expression: ?{}: static inline function
      ... with parameters
        _dst: reference to instance of struct S with body 1
      ... returning nothing

      ... deleted by: ?{}: forall
        __anonymous0: data type
        ... with assertions
          sayHi: pointer to function
            accepting unspecified arguments
          ... returning nothing

Note that the error says the custom constructor is responsible for deleting the autogen constructor (which is correct), yet the call site is preferring the autogen constructor (which is incorrect).

A consequence of this first example is, when there is no generic type parameter on the structure, all constructors must use the same set of assertions. This represents a limitation of the resource-management/traits system, in that a specialized resource acquisition strategy cannot be applied for a scenario indicated by the presence of a certain API.

A more elaborate example has the autogen constructor being called in spite of the same-signature custom constructor, which is confusing and hard to troubleshoot.

forall( dtype T ) {
    struct S {
        T * t;
    };

    forall( | {void sayHi();} )
    void ?{}( S(T) & this, T * t ) {
        sayHi();
        this.t = 0p;
    }
}

void sayHi() {
    printf("hi\n");
}

int main() {
    int x = 7;
    S(int) s = { & x };
    printf("%s\n", (s.t == 0p) ? "null" : "not null");
}

Expected, elaborate: compiler success with output

hi
null

Actual, elaborate: compiler success with output

not null

The actual-elaborate output is suggesting that the autogen 1-param constructor is being called. Manual inspection of -CFA output corroborates.

In this revision of the elaborate case, the behaviour is reversed. This does provide a workaround (for cases when the struct has generic parameters). But note the extreme similarity of the two elaborate code listings: all our instincts about forall distribution are screaming that the two should be the same.

forall( dtype T ) {
    struct S {
        T * t;
    };
}

forall( dtype T | {void sayHi();} ) {
    void ?{}( S(T) & this, T * t ) {
        sayHi();
        this.t = 0p;
    }
}

void sayHi() {
    printf("hi\n");
}

int main() {
    int x = 7;
    S(int) s = { & x };
    printf("%s\n", (s.t == 0p) ? "null" : "not null");
}

Actual, elaborate revised: as expected elaborate

Change History (0)

Note: See TracTickets for help on using tickets.