COMPLEX 2-D ARRAYS The original temporary-generation scheme is incorrect for arrays. It converts multi-dimensional array references into pointers to pointers to pointers... instead of pointers to N-1 dimensional arrays. Although incorrect, this scheme works for one-dimensional arrays. It also works for two-dimensional arrays, so long as temporaries are not generated for the actual array. That is, a[i][j] will work, but foo.a[i][j] will not. Generating correct temporaries is not difficult. For reference, GCC stores the number of elements in an array rather indirectly - calculate it with TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type))) - TREE_INT_CST_LOW(TYPE_MIN_VALUE(TYPE_DOMAIN(type))) + 1 However, the use of array temporaries must be special-cased, some compilers issue spurious warnings for the correct assignments, and the changes would be scattered around several files. Instead, the fix is to stop instrumenting at the right point in the descent of the parse tree. This approach is justified as follows: PART 1: EXPRESSIONS THAT YIELD SCALAR TYPES. 1. In what follows, we are concerned only with true arrays, not the use of array notation with pointer structures. (Arrays of pointers to 1D arrays work fine. Only true two-dimensional arrays are handled incorrectly.) 2. We wish to avoid generating temporaries for two-or-more dimensional arrays. 3. When descending the parse tree, the "dimensionality" of the object being evaluated can increase only at an array-reference node or a dereference node. Examples: In the expression [b][c], the subtree [b] has as its value a single-dimensional array, so a temporary is allowed. has as its value a 2D array, so a temporary would be incorrect. In the expression ([b]+1)[c], the subtree [b]+1 is a single-dimensional array. So is [b]. Since the dimensionality cannot change at the PLUS node, we needn't worry about it until we reach the array-reference node. 4. Temporaries are generated at the parent node, before a particular subtree is instrumented. A subtree in general cannot control whether its parent later uses the temporary. Consequently, we cannot decide not to instrument when we reach the first 2D-array node -- that's too late. We must decide before we reach the node. That is, when we see a 1D array node, we must decide whether to go any further. 5. At an array-reference or pointer-dereference node, we descend only if no temporary will be generated for the underlying array (the child of this node). (Essentially, we descend only for identifiers.) 6. It might seem that we can descend if the type of the underlying object is anything but array. However, consider ([1]+1)[]. Because of type conversions, the type of [1]+1 is pointer, not array. If we descend into it, the temporary generated for [1] will be incorrect (pointer to pointer, instead of pointer to 2D array). Thus, we should either not descend any temporary-needing subtree OR we need to place checks for many node types, not just array reference and pointer dereference. To minimize the scope of changes, the first is chosen. In sum: in array dereference and pointer dereference, add a check like this: if ( ARRAY_TYPE==TREE_CODE(self->gcc_type) && TEMPORARY_NEEDED(GCT_ARRAY_ARRAY(self))) If true, don't instrument. PART 2: EXPRESSIONS THAT YIELD ARRAYS Expressions that yield arrays actually yield pointers-to-arrays, according to C's type-conversion rules. There are two cases of interest: 1. Operand constancy checks. Whenever constancy checks are turned on, temporaries *are* generated for identifiers even if NO_TEMPORARY_NEEDED. Because operand constancy is a waste of time and easy to turn off and probably unused by anyone, I ignore this. 2. Taking the address of subarrays. An example: int array[3][3][3][3]; int (*p)[3][3] = array[3]; Array[3] will have a temporary generated for it, as it is a complex expression. It is also ARRAY_TYPE, so the temporary-generation can be made to fail because of an error check in temporary_id. Avoiding this problem would require changes to many instrumentation routines (any one that could have a child of this form). The necessary check would be just like the one described in part 1. I doubt that such expressions are common, so I haven't made the fix. As a patch, GCT will in these circumstances generate a temporary that's a FLOAT. If the temporary is actually used (typically only when operand coverage is turned on, not branch and the like), the file will fail to compile. ADDENDUM: In a related change, we avoid the confused issue of what to do when the address of a function or array is taken by immediately stopping instrumentation.