public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: C++ aliasing rules
       [not found] <200204031103.aa15838@gremlin-relay.ics.uci.edu>
@ 2002-04-23 13:59 ` Jason Merrill
  2002-04-23 19:52   ` mike stump
  0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2002-04-23 13:59 UTC (permalink / raw)
  To: Dan Nicolaescu; +Cc: libstdc++, gcc

>>>>> "Dan" == Dan Nicolaescu <dann@godzilla.ICS.UCI.EDU> writes:

> struct first  {  int i; char a;  int f1;  char f2; double d;};
> struct second {  char b;  int f2;  int f3;};

> can it be assumed that given that "first" and "second" are
> incompatible then ps1.f1 and ps2.f2 don't alias

I'm not sure.  I suppose it depends on whether you consider ps1.f1 to be an
object for the purposes of [basic.lval], which says that an object can be
referenced through an lvalue of a class type which contains a member of
that object's type.  So since ps1.f1 is an int, and struct second contains
an int, the access can alias.

If we think that [basic.lval] only means to talk about complete objects,
then the access can't alias.

I'm not sure what the intent is, but from a strict reading I tend towards
the first interpretation; according to [intro.object] sub-objects are
objects, too.

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C++ aliasing rules
  2002-04-23 13:59 ` C++ aliasing rules Jason Merrill
@ 2002-04-23 19:52   ` mike stump
  2002-04-24  6:43     ` Andreas Schwab
  2002-04-24 13:32     ` Dan Nicolaescu
  0 siblings, 2 replies; 8+ messages in thread
From: mike stump @ 2002-04-23 19:52 UTC (permalink / raw)
  To: dann, jason; +Cc: gcc, libstdc++

> To: Dan Nicolaescu <dann@godzilla.ICS.UCI.EDU>
> Cc: libstdc++@gcc.gnu.org, gcc@gcc.gnu.org
> From: Jason Merrill <jason@redhat.com>
> Date: Tue, 23 Apr 2002 10:43:27 +0100

> > struct first  {  int i; char a;  int f1;  char f2; double d;};
> > struct second {  char b;  int f2;  int f3;};

> > can it be assumed that given that "first" and "second" are
> > incompatible then ps1.f1 and ps2.f2 don't alias

This would be an excellent question for comp.std.c.  C++ mostly just
followed C on this.  We fixed a few things (made memcpy so that it can
be portably written within the rules of the language), but it should
mostly be the same.  You would need complete code, and might need to
`fix up' the example so that you can have them answer the question you
wanted.

Consider:

struct { char buf[sizeof (double)]; short i; } secondo, *second = &secondo;
struct { double other; short i; } firsto, *not_really_first = &secondo;

and the question of whether or not first->i can ever alias second->i.

I suspect the closest we can come would be to

  memcpy (&secondo, &firsto, sizeof (secondo));

and then play with not_really_first->i and second->i.

I think the answer is no, as no matter what you do, you need to
violate the notion of which struct type the object really was and you
cannot get at the short without going though the struct first, and in
the end, you cannot get through both struct types simultaneously.

No, before you implement this, you need to be aware that some
prefixing is probably ok:

       6.3.2.3  Structure and union members

       Constraints

       [#1] The first operand  of  the  .  operator  shall  have  a
       qualified  or  unqualified  structure or union type, and the
       second operand shall name a member of that type.

       [#2] The first operand of the -> operator  shall  have  type
       ``pointer   to   qualified  or  unqualified  structure''  or
       ``pointer to  qualified  or  unqualified  union,''  and  the
       second operand shall name a member of the type pointed to.

       Semantics

       [#3] A postfix expression followed by the . operator and  an
       identifier  designates  a  member  of  a  structure or union
       object.  The value is that of the named member,  and  is  an
       lvalue  if  the first expression is an lvalue.  If the first
       expression has  qualified  type,  the  result  has  the  so-
       qualified version of the type of the designated member.

       [#4] A postfix expression followed by the -> operator and an
       identifier  designates  a  member  of  a  structure or union
       object.  The value is that of the named member of the object
       to which the first expression points, and is  an  lvalue.66
       If  the  first  expression is a pointer to a qualified type,
       the result has the so-qualified version of the type  of  the
       designated member.

       [#5] With one exception, if the value of a member of a union
       object  is used when the most recent store to the object was
       to a  different  member,  the  behavior  is  implementation-
       defined.67  One  special  guarantee  is  made  in  order  to


       __________

       66. If  &E  is  a  valid  pointer expression (where & is the
           ``address-of'' operator, which generates  a  pointer  to
           its  operand),  the  expression (&E)->MOS is the same as
           E.MOS.

       67. The  ``byte  orders''  for scalar types are invisible to
           isolated programs that do not indulge  in  type  punning
           (for  example, by assigning to one member of a union and
           inspecting the storage by accessing another member  that


       Language                                                  85









       Working Draft, 1997-11-21, WG14/<a href="n794.htm">N794</a> J11/97-158


       simplify the use of unions:  If  a  union  contains  several
       structures that share a common initial sequence (see below),
       and if the union object  currently  contains  one  of  these
       structures,  it  is  permitted to inspect the common initial
       part of any of them  anywhere  that  a  declaration  of  the
       completed  type  of  the  union  is visible.  Two structures
       share a common initial  sequence  if  corresponding  members
       have compatible types (and, for bit-fields, the same widths)
       for a sequence of one or more initial members.

       Examples

       [#6]

         1.  If f is a function returning a structure or union, and
             x  is  a member of that structure or union, f().x is a
             valid postfix expression but is not an lvalue.

         2.  The following is a valid fragment:

                     union {
                             struct {
                                     int     alltypes;
                             } n;
                             struct {
                                     int     type;
                                     int     intnode;
                             } ni;
                             struct {
                                     int     type;
                                     double  doublenode;
                             } nf;
                     } u;
                     u.nf.type = 1;
                     u.nf.doublenode = 3.14;
                     /* ... */
                     if (u.n.alltypes == 1)
                             if (sin(u.nf.doublenode) == 0.0)
                                     /* ... */






       ____________________________________________________________

           is  an appropriately sized array of character type), but
           must be accounted  for  when  conforming  to  externally
           imposed storage layouts.



       86                                                  Language









                    Working Draft, 1997-11-21, WG14/<a href="n794.htm">N794</a> J11/97-158


         3.  The following is not a  valid  fragment  (because  the
             union type is not visible within function f):

                     struct t1 { int m; };
                     struct t2 { int m; };
                     int f(struct t1 * p1, struct t2 * p2)
                     {
                             if (p1->m &lt; 0)
                                     p2->m = -p2->m;
                             return p1->m;
                     }
                     int g()
                     {
                             union {
                                     struct t1 s1;
                                     struct t2 s2;
                             } u;
                             /* ... */
                             return f(&u.s1, &u.s2);
                     }

       Forward  references:   address  and  indirection   operators
       (6.3.3.2), structure and union specifiers (6.5.2.1).

And from the C++ world:

  - a type that is a (possibly cv-qualified)  base  class  type  of  the
    dynamic type of the object,

and:

14Two POD-struct (9) types are layout-compatible if they have  the  same
  number  of  members, and corresponding members (in order) have layout-
  compatible types (3.9).

15Two POD-union (9) types are layout-compatible if they  have  the  same
  number  of  members,  and  corresponding  members  (in any order) have
  layout-compatible types (3.9).

  +-------                     BEGIN BOX 2                      -------+
  Shouldn't this be the same set of types?
  +-------                      END BOX 2                       -------+


16If a POD-union contains two or more POD-structs that  share  a  common
  initial  sequence,  and if the POD-union object currently contains one
  of these POD-structs, it is permitted to inspect  the  common  initial
  part  of any of them.  Two POD-structs share a common initial sequence
  if corresponding members have layout-compatible types (and,  for  bit-
  fields,  the  same  widths)  for  a  sequence  of  one or more initial
  members.

17A pointer to a POD-struct object, suitably converted,  points  to  its
  initial  member (or if that member is a bit-field, then to the unit in
  which it resides) and vice versa.  [Note:  There  might  therefore  be
  unnamed  padding within a POD-struct object, but not at its beginning,
  as necessary to achieve appropriate alignment.  ]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C++ aliasing rules
  2002-04-23 19:52   ` mike stump
@ 2002-04-24  6:43     ` Andreas Schwab
  2002-04-24 13:32     ` Dan Nicolaescu
  1 sibling, 0 replies; 8+ messages in thread
From: Andreas Schwab @ 2002-04-24  6:43 UTC (permalink / raw)
  To: mike stump; +Cc: dann, jason, gcc, libstdc++

mike stump <mrs@windriver.com> writes:

|> No, before you implement this, you need to be aware that some
|> prefixing is probably ok:
|> 
|>        6.3.2.3  Structure and union members

FYI, this is how the section reads in the final standard.  Especially
[#5] is different and there is one more example.

    6.5.2.3 Structure and union members

    Constraints

    [#1] The first operand of the . operator shall have a qualified or
    unqualified structure or union type, and the second operand shall name a
    member of that type.

    [#2] The first operand of the -> operator shall have type pointer to
    qualified or unqualified structure or pointer to qualified or unqualified
    union, and the second operand shall name a member of the type pointed to.

    Semantics

    [#3] A postfix expression followed by the . operator and an identifier
    designates a member of a structure or union object. The value is that of
    the named member, and is an lvalue if the first expression is an
    lvalue. If the first expression has qualified type, the result has the
    so-qualified version of the type of the designated member.

    [#4] A postfix expression followed by the -> operator and an identifier
    designates a member of a structure or union object. The value is that of
    the named member of the object to which the first expression points, and
    is an lvalue.79) If the first expression is a pointer to a qualified
    type, the result has the so-qualified version of the type of the
    designated member.

    [#5] One special guarantee is made in order to simplify the use of
    unions: if a union contains several structures that share a common
    initial sequence (see below), and if the union object currently contains
    one of these structures, it is permitted to inspect the common initial
    part of any of them anywhere that a declaration of the complete type of
    the union is visible. Two structures share a common initial sequence if
    corresponding members have compatible types (and, for bit-fields, the
    same widths) for a sequence of one or more initial members.

    [#6] EXAMPLE 1 If f is a function returning a structure or union, and x
    is a member of that structure or union, f().x is a valid postfix
    expression but is not an lvalue.

    [#7] EXAMPLE 2 In:

             struct s { int i; const int ci; };
             struct s s;
             const struct s cs;
             volatile struct s vs;

         the various members have the types:

             s.i 	  int
             s.ci 	  const int
             cs.i 	  const int
             cs.ci   const int
             vs.i 	  volatile int
             vs.ci   volatile const int

    [#8] EXAMPLE 3 The following is a valid fragment:

             union {
                   struct {
                          int alltypes;
                   } n;
                   struct {
                          int type;
                          int intnode;
                   } ni;
                   struct {
                          int type;
                          double doublenode;
                   } nf;
             } u;
             u.nf.type = 1;
             u.nf.doublenode = 3.14;
             /* ... */
             if (u.n.alltypes == 1)
                   if (sin(u.nf.doublenode) == 0.0)
                         /* ... */

         The following is not a valid fragment (because the union type is not
         visible within function f):

             struct t1 { int m; };
             struct t2 { int m; };
             int f(struct t1 * p1, struct t2 * p2)
             {
                   if (p1->m < 0)
                         p2->m = -p2->m;
                   return p1->m;
             }
             int g()
             {
                   union {
                         struct t1 s1;
                         struct t2 s2;
                   } u;
                   /* ... */
                   return f(&u.s1, &u.s2);
             }

    Forward references: address and indirection operators (6.5.3.2),
    structure and union specifiers (6.7.2.1).

   --------------------
    79) If &E is a valid pointer expression (where & is the address-of
        operator, which generates a pointer to its operand), the expression
        (&E)->MOS is the same as E.MOS.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE GmbH, Deutschherrnstr. 15-19, D-90429 Nürnberg
Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C++ aliasing rules
  2002-04-23 19:52   ` mike stump
  2002-04-24  6:43     ` Andreas Schwab
@ 2002-04-24 13:32     ` Dan Nicolaescu
  2002-04-25  1:11       ` Nathan Sidwell
  2002-04-25 10:57       ` Jason Merrill
  1 sibling, 2 replies; 8+ messages in thread
From: Dan Nicolaescu @ 2002-04-24 13:32 UTC (permalink / raw)
  To: mike stump; +Cc: jason, gcc, libstdc++

mike stump <mrs@windriver.com> writes:

  > > To: Dan Nicolaescu <dann@godzilla.ICS.UCI.EDU>
  > > Cc: libstdc++@gcc.gnu.org, gcc@gcc.gnu.org
  > > From: Jason Merrill <jason@redhat.com>
  > > Date: Tue, 23 Apr 2002 10:43:27 +0100
  > 
  > > > struct first  {  int i; char a;  int f1;  char f2; double d;};
  > > > struct second {  char b;  int f2;  int f3;};
  > 
  > > > can it be assumed that given that "first" and "second" are
  > > > incompatible then ps1.f1 and ps2.f2 don't alias
  > 
  > This would be an excellent question for comp.std.c.  C++ mostly just
  > followed C on this. 

As a matter of fact I asked this question on comp.std.c sometime in
March. And the answer was that the C standard is a bit unclear in this
area...  

  >  We fixed a few things (made memcpy so that it can
  > be portably written within the rules of the language), but it should
  > mostly be the same.  You would need complete code, and might need to
  > `fix up' the example so that you can have them answer the question you
  > wanted.

A bit too much of my original post was snipped in the message you
replied to, that's why the code is incomplete, see:

http://gcc.gnu.org/ml/libstdc++/2002-04/msg00049.html


  > Consider:
  > 
  > struct { char buf[sizeof (double)]; short i; } secondo, *second = &secondo;
  > struct { double other; short i; } firsto, *not_really_first = &secondo;
  > 
  > and the question of whether or not first->i can ever alias second->i.
  > 
  > I suspect the closest we can come would be to
  > 
  >   memcpy (&secondo, &firsto, sizeof (secondo));
  > 
  > and then play with not_really_first->i and second->i.
  > 
  > I think the answer is no, as no matter what you do, you need to
  > violate the notion of which struct type the object really was and you
  > cannot get at the short without going though the struct first, and in
  > the end, you cannot get through both struct types simultaneously.

I like this answer. :-) 

Does anybody disagree with Mike's statement above (wrt C++) ? Jason? 


  > No, before you implement this, you need to be aware that some
  > prefixing is probably ok:

I've already implemented it. 
I have an unsubmited patch that takes care of the prefixing thing
too. I'll reopen the discussion on the patches after 3.1 is released,
if we have an agreement that it's OK from the C++ standard point of
view. 

BTW, there's a defect report for C99 that says that allowing prefixing
is not such a great idea...

Thanks.
                --dan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C++ aliasing rules
  2002-04-24 13:32     ` Dan Nicolaescu
@ 2002-04-25  1:11       ` Nathan Sidwell
  2002-04-25 10:57       ` Jason Merrill
  1 sibling, 0 replies; 8+ messages in thread
From: Nathan Sidwell @ 2002-04-25  1:11 UTC (permalink / raw)
  To: Dan Nicolaescu; +Cc: mike stump, jason, gcc, libstdc++

Dan Nicolaescu wrote:

>   > I think the answer is no, as no matter what you do, you need to
>   > violate the notion of which struct type the object really was and you
>   > cannot get at the short without going though the struct first, and in
>   > the end, you cannot get through both struct types simultaneously.

> 
> Does anybody disagree with Mike's statement above (wrt C++) ? Jason?
I agree with Mike's analysis.

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
           The voices in my head told me to say this
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C++ aliasing rules
  2002-04-24 13:32     ` Dan Nicolaescu
  2002-04-25  1:11       ` Nathan Sidwell
@ 2002-04-25 10:57       ` Jason Merrill
  2002-04-25 17:44         ` mike stump
  1 sibling, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2002-04-25 10:57 UTC (permalink / raw)
  To: Dan Nicolaescu; +Cc: mike stump, gcc, libstdc++

>>>>> "Dan" == Dan Nicolaescu <dann@godzilla.ICS.UCI.EDU> writes:

> mike stump <mrs@windriver.com> writes:

>> Consider:
>> 
>> struct { char buf[sizeof (double)]; short i; } secondo, *second = &secondo;
>> struct { double other; short i; } firsto, *not_really_first = &secondo;
>> 
>> and the question of whether or not first->i can ever alias second->i.
>> 
>> I suspect the closest we can come would be to
>> 
>> memcpy (&secondo, &firsto, sizeof (secondo));
>> 
>> and then play with not_really_first->i and second->i.
>> 
>> I think the answer is no, as no matter what you do, you need to
>> violate the notion of which struct type the object really was and you
>> cannot get at the short without going though the struct first, and in
>> the end, you cannot get through both struct types simultaneously.

> I like this answer. :-) 

> Does anybody disagree with Mike's statement above (wrt C++) ? Jason? 

I don't see how Mike's statement answers my question.  Given

 struct A { char buf[sizeof (double)]; short i; };
 struct B { double other; short i; };

 A a;
 A* ap = &a;
 B* bp = reinterpret_cast<B*>(ap);

referring to bp->i is accessing a.i through an lvalue of a class type (B)
which contains a member of a.i's type (short).  The standard seems to say
that's OK.

Again, if instead we consider a.i to be an indivisible part of 'a' for
purposes of [basic.lval], then the access would be undefined.  I would
probably support writing that into the standard.  But I don't think that's
what it says now.

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C++ aliasing rules
  2002-04-25 10:57       ` Jason Merrill
@ 2002-04-25 17:44         ` mike stump
  2002-05-17 13:09           ` Dan Nicolaescu
  0 siblings, 1 reply; 8+ messages in thread
From: mike stump @ 2002-04-25 17:44 UTC (permalink / raw)
  To: dann, jason; +Cc: gcc, libstdc++

> To: Dan Nicolaescu <dann@godzilla.ICS.UCI.EDU>
> Cc: mike stump <mrs@windriver.com>, gcc@gcc.gnu.org, libstdc++@gcc.gnu.org
> From: Jason Merrill <jason@redhat.com>
> Date: Thu, 25 Apr 2002 18:44:05 +0100

> I don't see how Mike's statement answers my question.

Yes, I agree, I don't think it does.

> I would probably support writing that into the standard.  But I
> don't think that's what it says now.

A hard line would be we should be conservative, and get it written
into the standard first.  I think it would be reasonable for the
standard to say they don't alias.

If we want to lead the standard, I think we can.  Because the standard
isn't perfectly clear, it would be good to document what we did.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: C++ aliasing rules
  2002-04-25 17:44         ` mike stump
@ 2002-05-17 13:09           ` Dan Nicolaescu
  0 siblings, 0 replies; 8+ messages in thread
From: Dan Nicolaescu @ 2002-05-17 13:09 UTC (permalink / raw)
  To: mike stump; +Cc: jason, gcc, libstdc++

Now that 3.1 is out of the way we can reopen this discussion... 
For reference the start of this thread is at: 
http://gcc.gnu.org/ml/libstdc++/2002-04/msg00049.html


mike stump <mrs@windriver.com> writes:

  > > To: Dan Nicolaescu <dann@godzilla.ICS.UCI.EDU>
  > > Cc: mike stump <mrs@windriver.com>, gcc@gcc.gnu.org, libstdc++@gcc.gnu.org
  > > From: Jason Merrill <jason@redhat.com>
  > > Date: Thu, 25 Apr 2002 18:44:05 +0100
  > 
  > > I don't see how Mike's statement answers my question.
  > 
  > Yes, I agree, I don't think it does.
  > 
  > > I would probably support writing that into the standard.  But I
  > > don't think that's what it says now.
  > 
  > A hard line would be we should be conservative, and get it written
  > into the standard first.  I think it would be reasonable for the
  > standard to say they don't alias.
  > 
  > If we want to lead the standard, I think we can.  Because the standard
  > isn't perfectly clear, it would be good to document what we did.

If we decide to lead the standard, I volunteer the write the patch and
the associated GCC documentation. 
Somebody else will have to take care about the standardization
process... 

Who can make a decision about this? 


        --dan

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2002-05-17 19:01 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <200204031103.aa15838@gremlin-relay.ics.uci.edu>
2002-04-23 13:59 ` C++ aliasing rules Jason Merrill
2002-04-23 19:52   ` mike stump
2002-04-24  6:43     ` Andreas Schwab
2002-04-24 13:32     ` Dan Nicolaescu
2002-04-25  1:11       ` Nathan Sidwell
2002-04-25 10:57       ` Jason Merrill
2002-04-25 17:44         ` mike stump
2002-05-17 13:09           ` Dan Nicolaescu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).