| | 54 | |
| | 55 | By contrast, initializing a const field via the autogenerated member-wise constructor works: |
| | 56 | |
| | 57 | [B, success corner] |
| | 58 | {{{ |
| | 59 | struct thing { |
| | 60 | const int foo; |
| | 61 | }; |
| | 62 | int main() { |
| | 63 | thing t{ 1234 }; |
| | 64 | printf("%d\n", t.foo); |
| | 65 | } |
| | 66 | }}} |
| | 67 | |
| | 68 | B, actual and expected: compiles, runs, and prints 1234 |
| | 69 | |
| | 70 | We found a workaround that uses both field assignment (in place of field constructor call) and a const-cast: |
| | 71 | |
| | 72 | [C, workaround] |
| | 73 | {{{ |
| | 74 | struct thing { |
| | 75 | const int foo; |
| | 76 | }; |
| | 77 | void ?{}( thing & this ) { |
| | 78 | * ( int * ) & ( this.foo ) = 5; |
| | 79 | } |
| | 80 | int main() { |
| | 81 | thing t; |
| | 82 | printf("%d\n", t.foo); |
| | 83 | } |
| | 84 | }}} |
| | 85 | |
| | 86 | C, actual and expected: compiles, runs, and prints 5 |
| | 87 | |
| | 88 | Further variations of the basic pattern have been tried, with mixed success: |
| | 89 | [D, mix-n-match] |
| | 90 | {{{ |
| | 91 | #ifndef VAR_noqual |
| | 92 | // default: include qualifiers |
| | 93 | #define MAYBE_QUAL(...) __VA_ARGS__ |
| | 94 | #else |
| | 95 | // variation: suppress qualifiers |
| | 96 | #define MAYBE_QUAL(...) |
| | 97 | #endif |
| | 98 | |
| | 99 | #ifndef VAR_assign |
| | 100 | // default: user's ctor calls field's ctor |
| | 101 | #define INITIALIZE( THISFIELD, VAL ) ( THISFIELD ) { VAL } |
| | 102 | #else |
| | 103 | // variation: user's ctor calls field's assignment operator |
| | 104 | #define INITIALIZE( THISFIELD, VAL ) ( THISFIELD ) = ( VAL ) |
| | 105 | #endif |
| | 106 | |
| | 107 | #if ! defined VAR_concast1 && ! defined VAR_concast2 |
| | 108 | // default: user's field access is otherwise passthrough |
| | 109 | #define MAYBE_CONCAST( TY, THISFIELD ) THISFIELD |
| | 110 | #elif defined VAR_concast1 && ! defined VAR_concast2 |
| | 111 | // variation, sub 1: user's field access is via a CFA const cast |
| | 112 | #define MAYBE_CONCAST( TY, THISFIELD ) ( TY & )( THISFIELD ) |
| | 113 | #elif ! defined VAR_concast1 && defined VAR_concast2 |
| | 114 | // variation, sub 1: user's field access is via a C const cast |
| | 115 | #define MAYBE_CONCAST( TY, THISFIELD ) * ( TY * )( & ( THISFIELD ) ) |
| | 116 | #else |
| | 117 | #error Bad 'concast' combination |
| | 118 | #endif |
| | 119 | |
| | 120 | #ifndef VAR_derefref |
| | 121 | // default: passthrough |
| | 122 | #define MAYBE_DEREFREF( THISFIELD ) THISFIELD |
| | 123 | #else |
| | 124 | // variation: take the address, then dereference it |
| | 125 | // (has helped some cases of emitting "lvalue required" code) |
| | 126 | #define MAYBE_DEREFREF( THISFIELD ) *&(THISFIELD) |
| | 127 | #endif |
| | 128 | |
| | 129 | #ifndef VAR_ctorparm |
| | 130 | // default: user's ctor is parameterless; ctor's body hardcodes the value |
| | 131 | #define MAYBE_CTORPARM( ... ) |
| | 132 | #define SWITCH_CTORPARM( CASE_NORMAL, CASE_VAR ) CASE_NORMAL |
| | 133 | #else |
| | 134 | // variation: user's ctor takes a `foo_val` param; program main hardcodes the value |
| | 135 | #define MAYBE_CTORPARM( ... ) __VA_ARGS__ |
| | 136 | #define SWITCH_CTORPARM( CASE_NORMAL, CASE_VAR ) CASE_VAR |
| | 137 | #endif |
| | 138 | |
| | 139 | #ifndef VAR_with |
| | 140 | // default: ctor body accesses the field via this-dot |
| | 141 | #define SWITCH_WITH( CASE_NORMAL, CASE_VAR ) CASE_NORMAL |
| | 142 | #else |
| | 143 | // variation: ctor body accesses the field via `with` |
| | 144 | #define SWITCH_WITH( CASE_NORMAL, CASE_VAR ) CASE_VAR |
| | 145 | #endif |
| | 146 | |
| | 147 | struct thing { |
| | 148 | MAYBE_QUAL( const ) int foo; |
| | 149 | }; |
| | 150 | void ?{}( thing & this MAYBE_CTORPARM(, int foo_val ) ) SWITCH_WITH( , with( this ) ) { |
| | 151 | INITIALIZE( MAYBE_DEREFREF( MAYBE_CONCAST( int, SWITCH_WITH( this., ) foo ) ), SWITCH_CTORPARM( 42, foo_val ) ); |
| | 152 | } |
| | 153 | int main() { |
| | 154 | thing t{ MAYBE_CTORPARM( 999 ) }; |
| | 155 | printf("%d\n", t.foo); |
| | 156 | } |
| | 157 | }}} |
| | 158 | |
| | 159 | D, all variation combinations, ideal: success, printing 5 or 999, as appropriate |
| | 160 | |
| | 161 | D, expectation tolerance: as can be accepted case-by-case, rejection of some "ideal-valid" variation combinations may occur due to cfacc having to resort to conservative detection of "this appears to be a field initialization." |
| | 162 | |
| | 163 | D, across variation combinations, actual: incomplete list follows |
| | 164 | |
| | 165 | Some of the earlier tests are variation combinations from this general test, specifically: |
| | 166 | - A is D with A's HIDE_ERROR being the same as D's VAR_noqual, and with the other VAR_* not defined [actual, VAR_noqual, pass; actual, none defined, fail] |
| | 167 | - C is D with VAR_assign and VAR_concast2 defined, and the other VAR_* not defined [actual: pass] |
| | 168 | |
| | 169 | However, in spite of the element of similarity, B is not D with VAR_ctorparm defined and the other VAR_* not defined. B (pass) uses an autogenerated constructor, while D with VAR_ctorparm defined (fail) uses a user-written constructor that tries to emulate B. |
| | 170 | |
| | 171 | Every VAR_* option is believed to be at least a benign independent contribution, i.e. not inherently invalid. This is directly observable in all cases VAR_xxx, except VAR_concast2, defining both VAR_noqual (pass on its own) and VAR_xxx leaves a working program (VAR_noqual + VAR_xxx: pass). For VAR_concast2, its validity along with VAR_assign (as in test C) shows that it can be okay. |
| | 172 | |
| | 173 | Even so, VAR_concast2 all alone is failing, with the same symptom as in A. No hypothesis generalizing this phenomenon is yet conceived. |
| | 174 | |
| | 175 | VAR_assign alone: different error, from CFA resolver (before chance to generate bad code): ambiguous `?{}` call, between regular and volatile; not remotely understood; have been unable to fix, with any (non)volatile combinations (these not shown) |
| | 176 | |
| | 177 | VAR_assign + VAR_concast1: fixed, as for VAR_concast2 already discussed |
| | 178 | |
| | 179 | VAR_derefref: different error still, also at resolver: ctor call is an invalid application |
| | 180 | |
| | 181 | Except for VAR_noqual, each other VAR_*, on its own has some error. Except as just identified (VAR_assign and VAR_derefref), the symptom is "fails to fix the original symptom." |
| | 182 | |
| | 183 | The switches VAR_ctorparm and VAR_with have never been seen to have an effect, i.e. these factors are independent. |
| | 184 | |
| | 185 | Note that the `-E` and `-CFA -XCFA,-p` outputs from program D are quite readable. Looking at a `-E` can be easier than mentally expanding macros. |