David,

Two items I needs answered to get you the patch.

1) The get_field_at_bit_offset function is static in region.cc, so I cannot use 
it outside of the file (you want me to use it in store.cc) without updating 
that definition to extern. I am assuming you want this.

2) I am updating my direct access of the tree fields. I am using 
int_bit_position for the position of a field in a struct as you requested. What 
do I use for the size of the struct. I had been using 
->decl_common.size->int_cst[0].


Brian


Sent with ProtonMail Secure Email.

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Saturday, February 13, 2021 9:53 AM, brian.sobulefsky 
<brian.sobulef...@protonmail.com> wrote:

&gt; Hi, answers below. Note, do you want my resubmitted patch to be with
&gt; commit --amend, and therefore relative to "real" commits in the history,
&gt; or do you want me to chain it onto the last submission?
&gt;
&gt; I have already sent to assign at gnu for the form.
&gt;
&gt; I will update the commit message to call it s3 now.
&gt;
&gt; The case did not arise "in practice." After solving the xfail from the
&gt; test suite, I tried dividing the array to have more than one field and
&gt; found that this still did not work, so I tracked down why. I would
&gt; argue that the case of a struct made of only a single array as its one
&gt; field is a lot less likely to arise in practice. For what its worth,
&gt; the single field example basically works "for the wrong
&gt; reason."
&gt; When get_binding_recursive goes up the parent chain, it finds
&gt; a binding
&gt; in the parent cast region because that cast is a struct made of
&gt; only one
&gt; field, and so its binding_key is the same as that field. The
&gt; "right"
&gt; logic would check for a field covering the desired region.
&gt;
&gt; I'll fix the ChangeLog formatting parentheses. I found the formatting
&gt; script, but I did not have one of the imported python files so I just 
copied others.
&gt;
&gt; I can add the helper routine you have requested. Where would you like it,
&gt; I am thinking analyzer.h so it is visible basically everywhere?
&gt;
&gt; I can add the check for size matching, which helper routine is easiest.
&gt;
&gt; Yes, in the event of *p == 'A', *p, having a constant zerop offset
&gt; would get sent to get_cast_region, where it would become a cast region.
&gt; This defeats the new logic in maybe_fold_sub_svalue. I think in the case
&gt; where we are pointing to an array of the requested type, it is much more
&gt; correct to return the offset region with a zero offset, as arr[0] should 
not
&gt; be different than arr[1]. Sometimes the 0 tree would be of pointer_type,
&gt; and I was not sure if this would defeat it or not, so I made sure it was
&gt; of integer_type. This may just be a matter of my being new and not
&gt; knowing for sure how everything works and so erring on the side of safety.
&gt;
&gt; As of now, the routine immediately rejects any case other than where
&gt; reg is a field_region and parent is a cast_region. I will think if there
&gt; is a C like syntax for the function, really it is checking if the original
&gt; form of parent had a field covering the requested field.
&gt;
&gt; I will remove the first guard, leave the second, and try to reformat
&gt; the latters into a similar rejection style.
&gt;
&gt; Currently, get_field_at_bit_offset is not an externally visible function.
&gt; I am taking your instruction to reuse it to mean a prototype should
&gt; be added to the relevant header (it would be region.h I think, as long as
&gt; both region-model-manager.cc and store.cc include those).
&gt;
&gt; As you know, I am very new to gcc and so was happy when I could hack my
&gt; way to this working at all. I already assumed my direct access was not
&gt; correct. Most of what I did is based on "RTFS" since the manual does not
&gt; really cover the right way to do these things. I will try the routine
&gt; or otherwise macro you say.
&gt;
&gt; I will change the testfile to leave pre exisiting lines in place.
&gt;
&gt; Sent with ProtonMail Secure Email.
&gt;
&gt; ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
&gt; On Friday, February 12, 2021 4:16 PM, David Malcolm dmalc...@redhat.com 
wrote:
&gt;
&gt; &gt; On Wed, 2021-02-10 at 19:42 +0000, brian.sobulefsky wrote:
&gt; &gt; Hi Brian
&gt; &gt; Thanks for the patch.
&gt; &gt; The patch is large enough to count as legally significant; I've sent
&gt; &gt; you information on copyright assignment separately; the patch can't be
&gt; &gt; committed until that paperwork is in place.
&gt; &gt; In the meantime, I've added some review notes inline below throughout:
&gt; &gt;
&gt; &gt; &gt;     Address the bug found in test file 
gcc/testsuite/gcc.dg/analyzer/casts-1.c, as
&gt; &gt; &gt;     recorded by the XFAIL, and some simpler and more complex 
versions found during
&gt; &gt; &gt;     the investigation of it. PR analyzer/98797 was opened for 
these bugs.
&gt; &gt; &gt;
&gt; &gt; &gt;     The simplest manifestation of this bug can be replicated 
with:
&gt; &gt; &gt;
&gt; &gt; &gt;     char arr[] = {'A', 'B', 'C', 'D'};
&gt; &gt; &gt;     char *pt = ar;
&gt; &gt; &gt;     __analyzer_eval(*(pt + 0) == 'A');
&gt; &gt; &gt;     __analyzer_eval(*(pt + 1) == 'B');
&gt; &gt; &gt;     //etc
&gt; &gt; &gt;
&gt; &gt; &gt;     The result of the eval call is "UNKNOWN" because the 
analyzer is unable to
&gt; &gt; &gt;     determine the value at the pointer. Note that array access 
(such as arr[0]) is
&gt; &gt; &gt;     correctly handled. The code responsible for this is in file
&gt; &gt; &gt;     region-model-manager.cc, function 
region_model_manager::maybe_fold_sub_svalue.
&gt; &gt; &gt;     The relevant section is commented /* Handle getting 
individual chars from
&gt; &gt; &gt;     STRING_CST */. This section only had a case for an 
element_region. A case
&gt; &gt; &gt;     needed to be added for an offset_region.
&gt; &gt; &gt;
&gt; &gt; &gt;     Additionally, when the offset was 0, such as in *pt or *(pt 
+ 0), the function
&gt; &gt; &gt;     region_model_manager::get_offset_region was failing to make 
the needed offset
&gt; &gt; &gt;     region at all. This was due to the test for a constant 0 
pointer that was then
&gt; &gt; &gt;     returning get_cast_region. A special case is needed for when 
PARENT is of type
&gt; &gt; &gt;     array_type whose type matches TYPE. In this case, 
get_offset_region is allowed
&gt; &gt; &gt;     to continue to normal conclusion.
&gt; &gt; &gt;
&gt; &gt; &gt;     The original bug noted in 
gcc/testsuite/gcc.dg/analyzer/casts-1.c was for the
&gt; &gt; &gt;     case:
&gt; &gt; &gt;
&gt; &gt; &gt;     struct s1
&gt; &gt; &gt;     {
&gt; &gt; &gt;       char a;
&gt; &gt; &gt;       char b;
&gt; &gt; &gt;       char c;
&gt; &gt; &gt;       char d;
&gt; &gt; &gt;     };
&gt; &gt; &gt;
&gt; &gt; &gt;     struct s2
&gt; &gt; &gt;     {
&gt; &gt; &gt;       char arr[4];
&gt; &gt; &gt;     };
&gt; &gt; &gt;
&gt; &gt; &gt;     struct s2 x = {{'A', 'B', 'C', 'D'}};
&gt; &gt; &gt;     struct s1 *p = (struct s1 *)&amp;x;
&gt; &gt; &gt;     __analyzer_eval (p-&gt;a == 'A');
&gt; &gt; &gt;     //etc
&gt; &gt; &gt;
&gt; &gt; &gt;     This requires a case added to 
region_model_manager::maybe_fold_sub_svalue in
&gt; &gt; &gt;     the individual characters from string constant section for a 
field region.
&gt; &gt; &gt;
&gt; &gt; &gt;     Finally, the prior only works for the case where struct s2 
was a single field
&gt; &gt; &gt;     struct. The more general case is:
&gt; &gt; &gt;
&gt; &gt; &gt;     struct s2
&gt; &gt; &gt;     {
&gt; &gt; &gt;       char arr1[2];
&gt; &gt; &gt;       char arr2[2];
&gt; &gt; &gt;     };
&gt; &gt; &gt;
&gt; &gt; &gt;     struct s2 x = {{'A', 'B'}, {'C', 'D'}};
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; This is s3 in the testcase, rather than s2; looks like this commit
&gt; &gt; message should be updated accordingly to match your change to the
&gt; &gt; testcase.
&gt; &gt; BTW, did this case arise in practice? The existing cases are rather
&gt; &gt; artificial; IIRC I created them whilst experimenting with various 
casts
&gt; &gt; whilst prototypeing the code, in the hope of generating coverage, but
&gt; &gt; without any specific real-world examples in mind. (kind of "kicking
&gt; &gt; the tires", if you will). Am I right in thinking that this new one
&gt; &gt; arose in a similar way?
&gt; &gt;
&gt; &gt; &gt;     Here the array will never be found in the get_any_binding 
routines. A new
&gt; &gt; &gt;     routine is added to class binding_cluster that checks if the 
region being
&gt; &gt; &gt;     searched is a field_region of a cast_region, and if so, 
tries to find a field
&gt; &gt; &gt;     of the original region that contains the region under 
examination. This new
&gt; &gt; &gt;     function is named binding_cluster::get_parent_cast_binding. 
It is called from
&gt; &gt; &gt;     get_binding_recursive.
&gt; &gt; &gt;
&gt; &gt; &gt;     gcc/analyzer/ChangeLog:
&gt; &gt; &gt;             PR analyzer/98797
&gt; &gt; &gt;             * region-model-manager.cc 
region_model_manager::get_offset_region: Add
&gt; &gt; &gt;             check for a PARENT array whose type matches TYPE, 
and have this skip
&gt; &gt; &gt;             returning get_cast_region and rather conclude the 
function normally.
&gt; &gt; &gt;             * region-model-manager.cc 
region_model_manager::maybe_fold_sub_svalue
&gt; &gt; &gt;             Update the get character from string_cst section to 
include cases for
&gt; &gt; &gt;             an offset_region and a field_region.
&gt; &gt; &gt;             * store.cc binding_cluster::get_binding_recursive: 
Add case for call
&gt; &gt; &gt;             to new function get_parent_cast_binding.
&gt; &gt; &gt;             * store.cc binding_cluster::get_parent_cast_binding: 
New function.
&gt; &gt; &gt;             * store.h class binding_cluster: Add declaration for 
new member
&gt; &gt; &gt;             function get_parent_class_binding and macros for bit 
to byte
&gt; &gt; &gt;             conversion.
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; Formatting nit: the items in the ChangeLog within each file should be
&gt; &gt; enclosed by parentheses. We have a git commit hook that verifies the
&gt; &gt; format. In theory there's a way to run it ahead of time, but I don't
&gt; &gt; know of the top of my head where it is.
&gt; &gt;
&gt; &gt; &gt;     gcc/testsuite/ChangeLog:
&gt; &gt; &gt;             PR analyzer/98797
&gt; &gt; &gt;             * gcc.dg/analyzer/casts-1.c: Update file to no 
longer expect failures
&gt; &gt; &gt;             and add test cases for additional bugs solved.
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; diff --git a/gcc/analyzer/region-model-manager.cc 
b/gcc/analyzer/region-model-manager.cc
&gt; &gt; &gt; index dfd2413e914..1fd6b94f20a 100644
&gt; &gt; &gt; --- a/gcc/analyzer/region-model-manager.cc
&gt; &gt; &gt; +++ b/gcc/analyzer/region-model-manager.cc
&gt; &gt; &gt; @@ -602,16 +602,46 @@ 
region_model_manager::maybe_fold_sub_svalue (tree type,
&gt; &gt; &gt; /* Handle getting individual chars from a STRING_CST. */
&gt; &gt; &gt; if (tree cst = parent_svalue-&gt;maybe_get_constant ())
&gt; &gt; &gt; if (TREE_CODE (cst) == STRING_CST)
&gt; &gt; &gt;
&gt; &gt; &gt; -          if (const element_region *element_reg
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -          {
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   if (const element_region *element_reg
&gt; &gt; &gt;     = subregion-&gt;dyn_cast_element_region ())
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -   const svalue *idx_sval = element_reg-&gt;get_index ();
&gt; &gt; &gt;
&gt; &gt; &gt; -   if (tree cst_idx = idx_sval-&gt;maybe_get_constant ())
&gt; &gt; &gt;
&gt; &gt; &gt; -         if (const svalue *char_sval
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         = maybe_get_char_from_string_cst (cst, cst_idx))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           return get_or_create_cast (type, char_sval);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -         const svalue *idx_sval = element_reg-&gt;get_index ();
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         if (tree cst_idx = idx_sval-&gt;maybe_get_constant ())
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           if (const svalue *char_sval
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           = maybe_get_char_from_string_cst (cst, cst_idx))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         return get_or_create_cast (type, char_sval);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt; -   else if (const offset_region *offset_reg
&gt; &gt; &gt;
&gt; &gt; &gt; -           = subregion-&gt;dyn_cast_offset_region ())
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -         const svalue *offset_sval = 
offset_reg-&gt;get_byte_offset();
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         if (tree cst_offset = 
offset_sval-&gt;maybe_get_constant ())
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           if (const svalue *char_sval
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           = maybe_get_char_from_string_cst (cst, cst_offset))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         return get_or_create_cast (type, char_sval);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt; -   else if (const field_region *field_reg
&gt; &gt; &gt;
&gt; &gt; &gt; -           = subregion-&gt;dyn_cast_field_region ())
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -         region_offset field_offset = field_reg-&gt;get_offset 
();
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         if (!field_offset.symbolic_p ())
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           {
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         bit_offset_t field_bit_offset = 
field_offset.get_bit_offset ();
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         HOST_WIDE_INT field_offset_bits
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -             = field_bit_offset.get_val ()[0];
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         if(!(field_offset_bits &amp; BYTE_BOUNDARY_MASK))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           {
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -             tree cst_offset
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                = build_int_cst (integer_type_node,
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                                field_offset_bits &gt;&gt; 
BYTE_BIT_CONVERT);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; The patch adds logic in two places to mask a HOST_WIDE_INT against
&gt; &gt; BYTE_BOUNDARY_MASK and if zero, shift by BYTE_BIT_CONVERT, and then to
&gt; &gt; build_int_cst from the result.
&gt; &gt; The mask and shift feel like premature optimization to me.
&gt; &gt; Please can you instead introduce a helper subroutine to do this,
&gt; &gt; something like:
&gt; &gt; /* If offset_bits is a multiple of BITS_PER_UNIT, return an 
INTEGER_CST
&gt; &gt; for the offset expressed in bytes.
&gt; &gt; Otherwise, return NULL_TREE. */
&gt; &gt; tree
&gt; &gt; maybe_convert_bit_to_byte_offset (HOST_WIDE_INT offset_bits)
&gt; &gt; {
&gt; &gt; if (offset_bits % BITS_PER_UNIT)
&gt; &gt; return NULL_TREE;
&gt; &gt; return build_int_cst (offset_bits / BITS_PER_UNIT);
&gt; &gt; }
&gt; &gt;
&gt; &gt; &gt; -             if (const svalue *char_sval
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                = maybe_get_char_from_string_cst (cst, 
cst_offset))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -               return  get_or_create_cast (type, char_sval);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; Doesn't this need to also check that the size of the field is
&gt; &gt; sizeof(char)?
&gt; &gt; Consider:
&gt; &gt; void test_4 ()
&gt; &gt; {
&gt; &gt; const char s = "ABCD";
&gt; &gt; __analyzer_eval ((short *)s == 'A');}
&gt; &gt; With your patch this evaluates as TRUE, as it's erroneously slicing 
off
&gt; &gt; the 2nd byte of "AB". It ought to be FALSE (and endianness concerns
&gt; &gt; would thwart TRUE also).
&gt; &gt;
&gt; &gt; &gt; -           }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt; -          }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt;     /* SUB(INIT(r)).FIELD -&gt; INIT(r.FIELD)
&gt; &gt; &gt;     i.e.
&gt; &gt; &gt;     Subvalue(InitialValue(R1), FieldRegion(R2, F))
&gt; &gt; &gt;     @@ -867,8 +897,19 @@ region_model_manager::get_offset_region 
(const region parent,
&gt; &gt; &gt;     {
&gt; &gt; &gt;     / If BYTE_OFFSET is zero, return PARENT. */if (tree 
cst_offset = byte_offset-&gt;maybe_get_constant ())
&gt; &gt; &gt;
&gt; &gt; &gt; -   if (zerop (cst_offset))
&gt; &gt; &gt;
&gt; &gt; &gt; -          return get_cast_region (parent, type);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -          /* Special case: PARENT type is array_type whose type 
matches TYPE */
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -          if (parent-&gt;get_type ()
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         &amp;&amp;  TREE_CODE(parent-&gt;get_type ()) == 
ARRAY_TYPE
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         &amp;&amp;  TREE_TYPE(parent-&gt;get_type ()) == type)
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -   tree offset_int
&gt; &gt; &gt;
&gt; &gt; &gt; -           = build_int_cst (integer_type_node, 
cst_offset-&gt;int_cst.val[0]);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; It took me a while to get the logic here. Am I right in thinking that
&gt; &gt; this is to avoid returning
&gt; &gt; (TYPE)PARENT
&gt; &gt; for the 0 offset case when it's a matching array, since:
&gt; &gt; PARENT[0]
&gt; &gt; is better for that case?
&gt; &gt; If so, I think the comments could be updated.
&gt; &gt; I'm not quite seeing the purpose of constructing offset_int from
&gt; &gt; cst_offset here. Is it to get a value of integer_type_node, or is it
&gt; &gt; redundant?
&gt; &gt;
&gt; &gt; &gt; -   byte_offset = get_or_create_constant_svalue (offset_int);
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt; -          else if (zerop (cst_offset))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   return get_cast_region (parent, type);
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; /* Fold OFFSET_REGION(OFFSET_REGION(REG, X), Y)
&gt; &gt; &gt; to OFFSET_REGION(REG, (X + Y)). */
&gt; &gt; &gt; diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
&gt; &gt; &gt; index abdb336da91..3afba55ce90 100644
&gt; &gt; &gt; --- a/gcc/analyzer/store.cc
&gt; &gt; &gt; +++ b/gcc/analyzer/store.cc
&gt; &gt; &gt; @@ -996,14 +996,129 @@ binding_cluster::get_binding_recursive 
(store_manager *mgr,
&gt; &gt; &gt; return sval;
&gt; &gt; &gt; if (reg != m_base_region)
&gt; &gt; &gt; if (const region *parent_reg = reg-&gt;get_parent_region ())
&gt; &gt; &gt;
&gt; &gt; &gt; -          if (const svalue *parent_sval
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   = get_binding_recursive (mgr, parent_reg, kind))
&gt; &gt; &gt;
&gt; &gt; &gt; -          {
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   if (const svalue *parent_sval
&gt; &gt; &gt;
&gt; &gt; &gt; -         = get_binding_recursive (mgr, parent_reg, kind))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -         /* Extract child svalue from parent svalue.  */
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         region_model_manager *rmm_mgr = 
mgr-&gt;get_svalue_manager ();
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         return rmm_mgr-&gt;get_or_create_sub_svalue 
(reg-&gt;get_type (),
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                                              parent_sval, reg);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt; -   else if (const svalue *parent_cast_field_sval
&gt; &gt; &gt;
&gt; &gt; &gt; -         = get_parent_cast_binding (mgr, reg, kind))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -         /* PARENT_REG is a cast_region and we found a covering 
binding
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -            in the original_region */
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         return parent_cast_field_sval;
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt; &gt; -          }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   return NULL;
&gt; &gt; &gt;     +}
&gt; &gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt;
&gt; &gt; &gt; +/* Get a binding for access to a field of a cast_region.
&gt; &gt;
&gt; &gt; Is it always a cast_region? "reg" is a "const region *".
&gt; &gt; Is it possible to express in C-like syntax what this function does, in
&gt; &gt; the most general case. Is it something like:
&gt; &gt; ((TYPE)EXPR).FIELD
&gt; &gt; ?
&gt; &gt;
&gt; &gt; &gt; -   Note the original motivation for this was access of the form:
&gt; &gt; &gt; -   struct s1 x = {{'A', 'B'}; {'C', 'D'}}; struct s2 p = 
(struct s2) &amp;x;
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;a == 'A');
&gt; &gt;
&gt; &gt; I think the "s2" needs to be "s2 *" here.
&gt; &gt;
&gt; &gt; &gt; -   et al. for the other fields. get_binding_recursive fails 
because it is
&gt; &gt; &gt;
&gt; &gt; &gt; -   unidirectional (from the field_region p-&gt;a up the chain 
of parents). The
&gt; &gt; &gt;
&gt; &gt; &gt; -   routine can probably be expanded, and even further broken 
out, as other cases
&gt; &gt; &gt;
&gt; &gt; &gt; -   are discovered and understood. */
&gt; &gt; &gt;     +const svalue *
&gt; &gt; &gt;     +binding_cluster::get_parent_cast_binding (store_manager 
*mgr,
&gt; &gt; &gt;
&gt; &gt; &gt; -                                  const region *reg,
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                                  enum binding_kind kind) const
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; +{
&gt; &gt; &gt; +
&gt; &gt; &gt;
&gt; &gt; &gt; -   /* If we are sure this will never be called incorrectly, we 
can remove */
&gt; &gt; &gt; -   if (!(mgr &amp;&amp; reg))
&gt; &gt; &gt; -   return NULL;
&gt; &gt;
&gt; &gt; I'm fairly sure that mgr will always be non-NULL. I'd prefer to remove
&gt; &gt; the checks; as far as I can tell, reg is always non-NULL.
&gt; &gt;
&gt; &gt; &gt; -   const region *parent_reg = reg-&gt;get_parent_region ();
&gt; &gt; &gt; -
&gt; &gt; &gt; -   /* If it is impossible for a region's parent to be NULL, 
remove
&gt; &gt;
&gt; &gt; guard */
&gt; &gt;
&gt; &gt; &gt; -   if(!parent_reg)
&gt; &gt; &gt; -   return NULL;
&gt; &gt;
&gt; &gt; Some regions do have NULL parents e.g. symbolic regions. I'm not sure
&gt; &gt; whether or not it can be called for them, so I'd keep this defensive
&gt; &gt; check.
&gt; &gt;
&gt; &gt; &gt; -   const cast_region *parent_cast = 
parent_reg-&gt;dyn_cast_cast_region ();
&gt; &gt; &gt; -   const field_region *field_reg = 
reg-&gt;dyn_cast_field_region ();
&gt; &gt; &gt; -
&gt; &gt; &gt; -   /* The first two guards are just safety, this is the real 
condition */
&gt; &gt; &gt; -   if (!(parent_cast &amp;&amp; field_reg))
&gt; &gt; &gt; -   return NULL;
&gt; &gt; &gt; -
&gt; &gt; &gt; -   const region *original_reg = 
parent_cast-&gt;get_original_region ();
&gt; &gt; &gt; -   region_offset reg_offset = field_reg-&gt;get_offset ();
&gt; &gt; &gt; -   bit_size_t reg_bit_size;
&gt; &gt; &gt; -   tree original_tree = original_reg-&gt;get_type ();
&gt; &gt; &gt; -   tree original_field;
&gt; &gt; &gt; -
&gt; &gt; &gt; -   /* Note assignment to ORIGINAL_FIELD in compound test to
&gt; &gt; &gt; -         save some indentation space (80 comes quickly) */
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; I find it's often easiest to rewrite a series of nested conditionals:
&gt; &gt; if (foo)
&gt; &gt; if (bar)
&gt; &gt; if (baz)
&gt; &gt; {
&gt; &gt; /* etc, where did all the columns go??? /
&gt; &gt; }
&gt; &gt; into:
&gt; &gt; if (!foo)
&gt; &gt; return;
&gt; &gt; if (!bar)
&gt; &gt; return;
&gt; &gt; if (!baz)
&gt; &gt; return;
&gt; &gt; / Now we still have plenty of room. */
&gt; &gt; assuming that the suite being guarded is all of the rest of the
&gt; &gt; function.
&gt; &gt;
&gt; &gt; &gt; -   if (original_tree &amp;&amp; TREE_CODE(original_tree) == 
RECORD_TYPE
&gt; &gt; &gt;
&gt; &gt; &gt; -          &amp;&amp; (original_field = 
TYPE_FIELDS(original_tree))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -          &amp;&amp; !reg_offset.symbolic_p() &amp;&amp; 
field_reg-&gt;get_bit_size(®_bit_size))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; so the above would probably be best rewritten.
&gt; &gt; That said, for future reference, with the compound conditional, you
&gt; &gt; correctly put the "&amp;&amp;" at the start of the line, but every 
such clause
&gt; &gt; needs to be at the start of a new line, so the above should read:
&gt; &gt; if (original_tree
&gt; &gt; &amp;&amp; TREE_CODE (original_tree) == RECORD_TYPE
&gt; &gt; &amp;&amp; (original_field = TYPE_FIELDS (original_tree))
&gt; &gt; &amp;&amp; !reg_offset.symbolic_p ()
&gt; &gt; &amp;&amp; field_reg-&gt;get_bit_size (®_bit_size))
&gt; &gt; to avoid conditions hiding from a casual reader.
&gt; &gt; ...but inverting the conditions and bailing is probably better for the
&gt; &gt; column-width thing as noted above.
&gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt; -          bit_offset_t reg_bit_offset = 
reg_offset.get_bit_offset ();
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -          HOST_WIDE_INT start_offset = reg_bit_offset.get_val 
()[0];
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -          HOST_WIDE_INT end_offset = start_offset + 
reg_bit_size.get_val ()[0] - 1;
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -          tree covering_field = NULL_TREE;
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt; -          /* get_field_at_bit_offset in region.cc has a test 
for RECORD_TYPE, maybe
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   this should be here too? The test is probably moot, since we 
have to
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; It would need the test (which is to handle methods and nested types in
&gt; &gt; C++ classes), but I believe this code can simply reuse
&gt; &gt; get_field_at_bit_offset, rather than duplicating the logic.
&gt; &gt;
&gt; &gt; &gt; -   fully cover and survive the get_binding_recursive below. Also
&gt; &gt; &gt; -   consdider making the function in region.cc usable outside the
&gt; &gt;
&gt; &gt; file? */
&gt; &gt;
&gt; &gt; &gt; -          for (covering_field = original_field;
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         (original_field = TREE_CHAIN (original_field));)
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   {
&gt; &gt; &gt;
&gt; &gt; &gt; -   if 
(original_field-&gt;field_decl.bit_offset-&gt;int_cst.val[0]
&gt; &gt; &gt;
&gt; &gt; &gt; -           &lt;= start_offset)
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         covering_field = original_field;
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   else
&gt; &gt; &gt;
&gt; &gt; &gt; -         break; /* Is the list guaranteed to be in order? */
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt; -          if (covering_field &amp;&amp; end_offset
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   &lt;= 
covering_field-&gt;field_decl.bit_offset-&gt;int_cst.val[0]
&gt; &gt; &gt;
&gt; &gt; &gt; -   -   covering_field-&gt;decl_common.size-&gt;int_cst.val[0] - 
1)
&gt; &gt;
&gt; &gt; Linebreak before &amp;&amp;; probably needs parentheses, so it ought 
to be
&gt; &gt; formatted something like this:
&gt; &gt; if (covering_field
&gt; &gt; &amp;&amp; (end_offset
&gt; &gt; &lt;= (covering_field-&gt;field_decl.bit_offset-&gt;int_cst.val[0]
&gt; &gt;
&gt; &gt;                 + 
covering_field-&gt;decl_common.size-&gt;int_cst.val[0] - 1)))
&gt; &gt;
&gt; &gt;
&gt; &gt; But the direct access of tree fields seems incorrect to me. Fixing
&gt; &gt; that would mean:
&gt; &gt; if (covering_field
&gt; &gt; &amp;&amp; (end_offset
&gt; &gt; &lt;= (DECL_FIELD_BIT_OFFSET (covering_field)-&gt;int_cst.val[0]
&gt; &gt;
&gt; &gt;                 + DECL_SIZE (covering_field)-&gt;int_cst.val[0] - 1)))
&gt; &gt;
&gt; &gt;
&gt; &gt; but the usage of int_cst.val[0] seem incorrect to me (what if it's a
&gt; &gt; really large value for which the low entry is 0?); does
&gt; &gt; int_bit_position do what you need?
&gt; &gt;
&gt; &gt; &gt; {
&gt; &gt; &gt;
&gt; &gt; &gt; -   /* Extract child svalue from parent svalue. */
&gt; &gt; &gt;
&gt; &gt; &gt; -   /* We found a field that entirely covers REG. The following 
code
&gt; &gt; &gt;
&gt; &gt; &gt; -   should probably be generalized to more cases, as of now it 
will
&gt; &gt; &gt;
&gt; &gt; &gt; -   basically handle the case where a char array has been 
initialized
&gt; &gt; &gt;
&gt; &gt; &gt; -   into the original struct type. Further work might be to 
handle when
&gt; &gt; &gt;
&gt; &gt; &gt; -   a field to a struct is itself a struct, which is likely 
recursive.*/
&gt; &gt; &gt;
&gt; &gt; &gt; -   region_model_manager *rmm_mgr = mgr-&gt;get_svalue_manager 
();
&gt; &gt; &gt;
&gt; &gt; &gt; -   return rmm_mgr-&gt;get_or_create_sub_svalue 
(reg-&gt;get_type (),
&gt; &gt; &gt;
&gt; &gt; &gt; -                                            parent_sval, reg);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -   const region *covering_field_reg = rmm_mgr
&gt; &gt; &gt;
&gt; &gt; &gt; -           -&gt;get_field_region (original_reg, covering_field);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt; -   if (const svalue *parent_sval = get_binding_recursive (mgr,
&gt; &gt; &gt;
&gt; &gt; &gt; -                                        covering_field_reg, 
kind))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; Probably best to put the newline before the "=" in this; see examples
&gt; &gt; elsewhere in the analyzer sources.
&gt; &gt;
&gt; &gt; &gt; -         {
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt; -           HOST_WIDE_INT covering_field_offset = covering_field
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           -&gt;field_decl.bit_offset-&gt;int_cst.val[0];
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; I don't think the code should be accessing int_cst.val[0]. Does
&gt; &gt; int_bit_position do what you need?
&gt; &gt;
&gt; &gt; &gt; -           if (TREE_CODE(covering_field_reg-&gt;get_type()) == 
ARRAY_TYPE
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           &amp;&amp; !((start_offset - covering_field_offset)
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                &amp; BYTE_BOUNDARY_MASK))
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         {
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -           const svalue *arr_index = rmm_mgr
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -               -&gt;get_or_create_constant_svalue (
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                  build_int_cst (integer_type_node,
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                    (start_offset - covering_field_offset)
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                     &gt;&gt; BYTE_BIT_CONVERT));
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; See notes above about introducing a subroutine for part of this.
&gt; &gt;
&gt; &gt; &gt; -           const region *elmt_reg = rmm_mgr
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -               -&gt;get_element_region (covering_field_reg,
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                  TREE_TYPE (covering_field_reg-&gt;get_type 
()),
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                    arr_index);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; Probably best to have the newline before the "=" here.
&gt; &gt;
&gt; &gt; &gt; -           return rmm_mgr-&gt;get_or_create_sub_svalue (
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -               elmt_reg-&gt;get_type (), parent_sval, elmt_reg);
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -         }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt;     }
&gt; &gt; &gt;
&gt; &gt; &gt; -   }
&gt; &gt; &gt;     return NULL;
&gt; &gt; &gt;     }
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
&gt; &gt; &gt; index 2bcef6c398a..9ddc57fea01 100644
&gt; &gt; &gt; --- a/gcc/analyzer/store.h
&gt; &gt; &gt; +++ b/gcc/analyzer/store.h
&gt; &gt; &gt; @@ -416,6 +416,9 @@ public:
&gt; &gt; &gt; const svalue *get_binding_recursive (store_manager *mgr,
&gt; &gt; &gt; const region *reg,
&gt; &gt; &gt; enum binding_kind kind) const;
&gt; &gt; &gt;
&gt; &gt; &gt; -   const svalue *get_parent_cast_binding (store_manager *mgr,
&gt; &gt; &gt;
&gt; &gt; &gt; -                                  const region *reg,
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt; &gt; -                                  enum binding_kind kind)
&gt; &gt; &gt;
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; const;
&gt; &gt;
&gt; &gt; &gt; const svalue *get_any_binding (store_manager *mgr,
&gt; &gt; &gt; const region *reg) const;
&gt; &gt; &gt; const svalue *maybe_get_compound_binding (store_manager *mgr,
&gt; &gt; &gt; @@ -640,4 +643,7 @@ private:
&gt; &gt; &gt; } // namespace ana
&gt; &gt; &gt; +#define BYTE_BIT_CONVERT 3
&gt; &gt; &gt; +#define BYTE_BOUNDARY_MASK ((1 &lt;&lt; BYTE_BIT_CONVERT) - 1)
&gt; &gt;
&gt; &gt; As noted above, please lose these in favor of a subroutine.
&gt; &gt;
&gt; &gt; &gt; #endif /* GCC_ANALYZER_STORE_H */
&gt; &gt; &gt; diff --git a/gcc/testsuite/gcc.dg/analyzer/casts-1.c
&gt; &gt;
&gt; &gt; b/gcc/testsuite/gcc.dg/analyzer/casts-1.c
&gt; &gt;
&gt; &gt; &gt; index 15cd85f77cf..9340615b20f 100644
&gt; &gt; &gt; --- a/gcc/testsuite/gcc.dg/analyzer/casts-1.c
&gt; &gt; &gt; +++ b/gcc/testsuite/gcc.dg/analyzer/casts-1.c
&gt; &gt; &gt; @@ -13,6 +13,21 @@ struct s2
&gt; &gt; &gt; char arr[4];
&gt; &gt; &gt; };
&gt; &gt; &gt; +struct s3
&gt; &gt; &gt; +{
&gt; &gt; &gt;
&gt; &gt; &gt; -   char arr1[2];
&gt; &gt; &gt;
&gt; &gt; &gt; -   char arr2[2];
&gt; &gt; &gt;     +};
&gt; &gt; &gt;
&gt; &gt; &gt; -
&gt; &gt; &gt;
&gt; &gt; &gt; +void test_0 ()
&gt; &gt; &gt; +{
&gt; &gt; &gt;
&gt; &gt; &gt; -   char ar[] = {'A', 'B', 'C', 'D'};
&gt; &gt; &gt; -   char *pt = ar;
&gt; &gt; &gt; -   __analyzer_eval ((pt + 0) == 'A'); / { dg-warning "TRUE" } */
&gt; &gt; &gt; -   __analyzer_eval ((pt + 1) == 'B'); / { dg-warning "TRUE" } */
&gt; &gt; &gt; -   __analyzer_eval ((pt + 2) == 'C'); / { dg-warning "TRUE" } */
&gt; &gt; &gt; -   __analyzer_eval ((pt + 3) == 'D'); / { dg-warning "TRUE" } */
&gt; &gt; &gt;     +}
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; Probably best to append new tests, rather than to insert them, to 
avoid
&gt; &gt; changing the line numbers of existing tests (which can help when
&gt; &gt; comparing DejaGnu results).
&gt; &gt;
&gt; &gt; &gt; void test_1 ()
&gt; &gt; &gt; {
&gt; &gt; &gt; struct s1 x = {'A', 'B', 'C', 'D'};
&gt; &gt; &gt; @@ -38,12 +53,22 @@ void test_2 ()
&gt; &gt; &gt; __analyzer_eval (x.arr[2] == 'C'); /* { dg-warning "TRUE" } /
&gt; &gt; &gt; __analyzer_eval (x.arr[3] == 'D'); / { dg-warning "TRUE" } 
*/struct s1 *p = (struct s1 *)&amp;x;
&gt; &gt; &gt;
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;a == 'A'); /* { dg-warning "TRUE" 
"true" {
&gt; &gt;
&gt; &gt; xfail --* } } */
&gt; &gt;
&gt; &gt; &gt; -   /* { dg-bogus "UNKNOWN" "unknown" { xfail --* } .-1 } */
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;b == 'B'); /* { dg-warning "TRUE" 
"true" {
&gt; &gt;
&gt; &gt; xfail --* } } */
&gt; &gt;
&gt; &gt; &gt; -   /* { dg-bogus "UNKNOWN" "unknown" { xfail --* } .-1 } */
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;c == 'C'); /* { dg-warning "TRUE" 
"true" {
&gt; &gt;
&gt; &gt; xfail --* } } */
&gt; &gt;
&gt; &gt; &gt; -   /* { dg-bogus "UNKNOWN" "unknown" { xfail --* } .-1 } */
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;d == 'D'); /* { dg-warning "TRUE" 
"true" {
&gt; &gt;
&gt; &gt; xfail --* } } */
&gt; &gt;
&gt; &gt; &gt; -   /* { dg-bogus "UNKNOWN" "unknown" { xfail --* } .-1 } */
&gt; &gt; &gt;
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;a == 'A'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt;
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;b == 'B'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt;
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;c == 'C'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt;
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;d == 'D'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt;     +}
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; It's great to see xfails become passes.
&gt; &gt;
&gt; &gt; &gt; +void test_3 ()
&gt; &gt; &gt; +{
&gt; &gt; &gt;
&gt; &gt; &gt; -   struct s3 x = {{'A', 'B'}, {'C', 'D'}};
&gt; &gt; &gt; -   __analyzer_eval (x.arr1[0] == 'A'); /* { dg-warning "TRUE" } 
*/
&gt; &gt; &gt; -   __analyzer_eval (x.arr1[1] == 'B'); /* { dg-warning "TRUE" } 
*/
&gt; &gt; &gt; -   __analyzer_eval (x.arr2[0] == 'C'); /* { dg-warning "TRUE" } 
*/
&gt; &gt; &gt; -   __analyzer_eval (x.arr2[1] == 'D'); /* { dg-warning "TRUE" } 
*/
&gt; &gt; &gt; -   struct s1 *p = (struct s1 *)&amp;x;
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;a == 'A'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;b == 'B'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;c == 'C'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt; -   __analyzer_eval (p-&gt;d == 'D'); /* { dg-warning "TRUE" 
"true" } */
&gt; &gt; &gt;     }
&gt; &gt; &gt;
&gt; &gt;
&gt; &gt; Thanks again for the patch; hope the above makes sense and is
&gt; &gt; constructive.
&gt; &gt; Dave

</brian.sobulef...@protonmail.com>

Reply via email to