Opened 4 years 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