Closed Bug 43311 Opened 24 years ago Closed 22 years ago

AIX xlC 5.0 compiler issue: friend 'prototype'

Categories

(SeaMonkey :: Build Config, defect, P3)

Other
AIX
defect

Tracking

(Not tracked)

RESOLVED FIXED
mozilla0.9.8

People

(Reporter: jdunn, Assigned: jdunn)

References

Details

Attachments

(6 files, 1 obsolete file)

The AIX xlC 5.0 compiler is having issues with having 'friend' declarations
that also double for 'prototyping'.  In this case I get the following error:

"friend.cpp", line 10.7: 1540-0040 (S) The text "function" is unexpected.  "B"
may be undeclared or ambiguous.

Since this is a compiler issue, this bug is aplace holder.
Blocks: 18688
Status: NEW → ASSIGNED
QA Contact: granrose → jdunn
Target Milestone: --- → M30
adding mike
Problem recreated and submitted to the IBM compiler team.
For tracking purposes:  IBM PMR #79946 -519-000
Changed to PMR 85012 -519-000
Not seen with gcc or IBM 3.6.6 compiler.   The problem is still being worked.


A work-around is to pre-declare B.   Is this acceptable for the time being?



--------
#include <stdio.h>

class B;   // pre-declare B

class A {
  public:
    A() { a=1; }

  private:
    friend class B;
  
    B function();
    int a;
};

class B {
  public:
    B() { b = 0; aptr = '\0'; }

  private:
    A *aptr;
    int b;
};

B A::function() {
   B *temp = new B;

   return *temp;
}
---------
Defect #160229.
Hmmm.  I can see how your compiler could legitimately complain that at
the point of

  B function();

|B| is still an incomplete type, and hence can't be used in this way.
However, for a compliant compiler, the name |B| should now be in
scope because of the earlier |friend| declaration.  Many compilers
get this wrong, and don't treat a local |friend| declaration as a
forward declaration.  This is probably your trouble.  Declaring
|class B;| above the entire class that wishes it to be a |friend|
might fix the error you're currently seeing, but would most likely
resolve to the incomplete type error I would have expected in the
first place.

Your example can easily be made to compile by re-ordering the
declarations ... so I don't know if this is a good case for your real
problem.  E.g.,

  class A;

  class B
    {
      public:
        B() : b(0), aptr(0) { }

      private:
        A* aptr; // pointer to an incomplete type is OK
        int b;
    };

  class A
    {
      public:
        A() : a(1) { }

      private:
        B function(); // B not incomplete, OK to use

        int a;
    };

  B
  A::function()
    {
      B* temp = new B;
      return *temp;
    }

I know your example was just quick and dirty, but I don't understand
why you would initialize a pointer to be the conversion of a
character.  How does your example differ from the real case that would
prevent you from avoiding the trouble entirely by re-ordering the
declarations?
oops, I left out the |friend| decl; which I don't think is actually needed in
your example anyway (even though it's the point of your example).
The work around suggested has been used to get around this.
However, it is annoying and since I had opened other VA5.0
(xlC) bugs, I figured I would open this one too.

The example is down and dirty that mimics what I have seen
in mozilla code.  The example itself is silly and is not meant
to do anything other than show the compiler bug.

The key point to this and the other VA5.0 bugs is too show that
the compiler is not currently up to task to build mozilla and
I wanted to list all of the issues I found.  I have had problems
in the past getting permission to go in and re-order statements
just to fix a 'AIX' issue.  It would be much easier to have a
compiler that didn't exhibit these problems.
scc wasn't cced on this so he didn't see jdunn's latest comment.

scc - apparently, this problem exists in some Mozilla files, so if you believe 
the code is incorrect, then mozilla does need to be fixed.

jdunn, can you give specific examples of mozilla files with this problem?
Not without doing a 5.0 build and right now I am not setup to
do it...

One key is that we can workaround this.
The other key is that my original attachment, shows the problem
so that the compiler people can fix this.
So if we ever decide to move to the new compiler (there are lots
of other bigger issues then just this... we can deal with the
workarounds...
I have engaged the compiler people on this issue as well as the two other
AIX VisualAge 5 C++ issues, bugs 43315 and 43306.

A compiler defect (160229) was opened for this problem and was subsequently
closed by the compiler team as "user error", since the friend declaration
does not implicitly declare the class.

I am following up on this, because my understanding was that, in Bjarne
Stroustrup's words, "A friend class must be previously declared in an
enclosing scope or defined in the non-class scope immediately enclosing
the class that is declaring it a friend." (Quote taken from the 2000
edition of "The C++ Programming Language".) This implies that the code in
the testcase should work, since the friend class is defined within "the
non-class scope immediately enclosing the class that is declaring it a
friend".

It is possible that the standard varies slightly from this or that there
is some subtlety which has eluded me, but I am asking for a clarification
from the compiler team, which I will copy into the text of this bug.
Thanks!  If the compiler team still say no, they are
right, then please ask them to cite where in the standard
that they are quoting from.

With the quote, I can go to engineers and say, HERE, your
code is wrong, here is the solution, let me check it in.
Without a quote from the standard... I can't do squat.
I am currently discussing this with our compiler team, who have pointed to
the relevant reference in the standard, section 7.3.1.2, paragraph 3:

"If a friend declaration in a non-local class first declares a class or
function the friend class or function is a member of the innermost
enclosing namespace.  The name of the friend is not found by simple name
lookup until a matching declaration is provided in that namespace scope
(either before or after the class declaration granting friendship)."

This compile error occurs when the compile of xpcom/base/nsWeakReference.cpp
is attempted. The error message is:

  "nsWeakReference.h", line 53.22: 1540-0040 (S) The text "*" is unexpected.
  "nsWeakReference" may be undeclared or ambiguous.
It seems that the VisualAge 5 C++ compiler is behaving correctly here
according to the standard. We should definitely resolve this with a code
change in Mozilla.

I was a little fuzzy on exactly how the construct in question violated the
standard, so the VisualAge C++ compiler team provided me with the following
more precise explanation of why this usage is incorrect in terms of the
standard:

The particular example being discussed is included below.  The error
given is that function is unexpected.  I will try to explain the history
behind this and why this is an error.

#include <stdio.h>

class A {
  public:
    A() { a=1; }

  private:
    friend class B;

    B function();
    int a;
};

class B {
  public:
    B() { b = 0; aptr = '\0'; }

  private:
    A *aptr;
    int b;
};

B A::function() {
   B *temp = new B;

   return *temp;
}

First, the history.  In the working drafts of the standard, it used to be that
a friend declaration of a class also implicitly declared a class in global
scope if it did not already exist in global scope.  Version 3.6.6 of IBM's
compilers worked this way, as do many current versions of C++ compilers offered
by other vendors.  When a friend declaration was encountered, the name of the
class being nominated for friendship was looked up and matched if it existed.
If it did not, it would be declared in the global scope.  Thus, the name would
be found in the next declaration because the lookup for B would find the name
in global scope.

This was changed in the final standard.  The reference in the standard is
7.3.1.2, paragraph 3.

"If a friend declaration in a non-local class first declares a class or
function the friend class or function is a member of the innermost enclosing
namespace.  The name of the friend is not found by simple name lookup until a
matching declaration is provided in that namespace scope (either before or
after the class declaration granting friendship)."

What this means is that when a class is nominated for friendship, the name of
the class is looked up in the current scope.  If it is not found, it is looked
up in the enclosing scopes, until it is found or the global namespace is
reached.  Essentially, normal name lookup is performed.  If it is not found (as
is the case here), the rules in the quotation given apply.  The name is
declared in the innermost enclosing namespace.  The name is not visible until a
matching declaration is provided.  Thus, the name B is not found, resulting in
the error.  Note that the error even suggests that B may be undeclared.
The class |nsWeakReference| needs to be forward declared before the class
|nsSupportsWeakReference|, that's all.  The compiler is right to refuse this
code.  Most compilers get this wrong, and find |nsWeakReference| in spite of the
standard, as this was the draft standard defined behavior, as pointed out above.
This patch will fix all the friend issues.
Declaring something friend doesn't mean that it has been
declared or prototyped.  The new xlC compiler is just
very strict in this case, so in order for something to be
used it needs to be "declared/prototyped" in addition to
being made a "friend".

Additionally, if it is "declared/prototyped" the default args
need to be set in the prototype and NOT in the friend accessor
updating bug, adding a bunch of people on the CC list.

I am looking for a r= and hopefully a sr= (but since this
is a "build" issue and shouldn't change any code... I don't
think it is needed, but I cc'd a bunch of people to get there
thoughts)
Target Milestone: --- → mozilla0.9.8
Cc'ing dbaron, who is a C++ language guru (in my book, anyway).  David, could
you look at the latest patch and jdunn's comments this year, and bless or curse?
 Thanks,

/be
Comment on attachment 64132 [details] [diff] [review]
New patch to fix all the offending "friend" issues

IIRC (all the online copies of the C++ standard have disappeared) this compiler
is wrong, but the workaround won't really hurt anything, so I don't object
(although people will probably re-break this a bit).

I think the example used in comment #6 led scc to think this was a different
problem from what it really is.

r=dbaron
Attachment #64132 - Flags: review+
From "The C++ Programming Language, Third Edition", section 11.5.1:
<quote>
11.5.1 Finding Friends

  Like a member declaration, a friend declaration does not introduce a name into
an enclosing scope. For example:

  class Matrix {
    friend class Xform;
    friend Matrix invert(const Matrix&);
    //..
  }

  Xform x;                              // error: no Xform in scope
  Matrix (*p)(const Matrix&) = &invert; // error: no invert() in scope

  For large programs and large classes, it is nice that a class doesn't
``quietly'' add names to its enclosing scope. For a template class that can be
instantiated in many different contexts (Chapter 13), this is very important.
  A friend class must be previously declared in an enclosing scope or defined in
the non-class scope immediately enclosing the class that is declaring it a
friend. For example:

  class X { /* ... */ };         // Y's friend
  namespace N {
    class Y {
      friend class X;
      friend class Z;
      friend class AE;
    };
    class Z { /* ... */ };       // Y's friend
  }

  class AE { /* ... */ };        // not a friend of Y
</quote>

This seems to suggest that the following is also the case, since B is declared
in the non-class scope immediately enclosing A:

  class A {
    friend class B;
  };

  class B { /* ... */ };   // friend of A
*** Bug 72190 has been marked as a duplicate of this bug. ***
fix checked in
Status: ASSIGNED → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
Fixes for several files have been checked in, but the problem has reoccurred in 
other files. Therefore, the standard question should really be settled to make 
it easier to handle new similar problems.

In an earlier note in comment #18, the standard was quoted that explains why the 
 behavior of the new AIX compiler is standard conform. Scott Collins agreed in 
comment #19. David Baron states in comment #23 that the compiler is wrong.

David, if you think the compiler is wrong, could you please explain why the 
quoted standard does not apply, and why the example in comment #6 does not 
address the real problem.

I would like to get the opinion of the compiler group that develops the 
compiler, but to do this I need more specifics.

Thank you very much.
To quote from comment 18:

"If a friend declaration in a non-local class first declares a class or
function the friend class or function is a member of the innermost enclosing
namespace.  The name of the friend is not found by simple name lookup until a
matching declaration is provided in that namespace scope (either before or
after the class declaration granting friendship)."

// innermost enclosing namespace is the global scope

class A // non-local class
{
  friend class B; // friend declaration in a non-local class, first declaration
}

class B // matching declaration for friend class B, provided in "that namespace"
{
}

So the way I see it, the compiler is wrong and this code is fine, but perhaps
I'm misinterpreting something (for I am not a c++ language lawyer).
I am attaching a very simple testcase that shows the
current set of problems.

---- friend.cpp : xlC -c friend.cpp ----
class A {
  public:
    A(void);

  private:
    friend int NS_SomeFunc(int a);
};

A::A(void) {
  int rc = NS_SomeFunc(10);
  return;
}

int NS_SomeFunc(int a) {
    return 1;
}
----
Error message
"friend.cpp", line 11.12: 1540-0274 (S) The name lookup for "NS_SomeFunc" did 
not find a declaration.
"friend.cpp", line 15.5: 1540-1298 (I) "int NS_SomeFunc(int)" needs to be 
declared in the containing scope to be found by name lookup.
I can't clearly find a normative passage in the C++ spec that states this
behavior is wrong (or states the contrary), but there are *examples* in the C++
spec that I don't think would compile on this compiler, and I think the examples
at least make the intentions of the spec authors clear.  Does the compiler
compile this example from 11.4?

          class X {
              int a;
              friend void friend_set(X*, int);
          public:
              void member_set(int);
          };
          void friend_set(X* p, int i) { p->a = i; }
          void X::member_set(int i) { a = i; }

          void f()
          {
              X obj;
              friend_set(&obj,10);
              obj.member_set(10);
          }
Your example does compile... 

class A {
  public:
    A(void);

  private:
    friend int NS_SomeFunc(int a);
};

int NS_SomeFunc(int a) {
    return 1;
}

A::A(void) {
  int rc = NS_SomeFunc(10);
  return;
}

How about the above? (So your code, but the actual call and the definition
switched).
Your latest test does compile... since you are
declaring " int NS_SomeFunc(int a) " before it
is being used.
Ah, so the issue is that |friend class foopy;| doesn't declare |foopy| as a class.

Time to re-read all comments here with that in mind.

So, it does seem that the new compiler is correct.
Section 11.4, clause 9 of the C++ standard says this would be the correct
behavior for *local* classes, but the fact that it restricts that statement to
local classes suggests that it's not correct for other ones.  However, I can't
find any explicit statement to the contrary.

attachment 64132 [details] [diff] [review] shows that there are problems with both friend functions and
friend classes.
From my #29 comment:

I put my "friend.cpp" into Comeau's online compiler
http://www.comeaucomputing.com/tryitout/  after it was
suggested to me from someone else.  

-----------------------------------------------------------------
Comeau C/C++ 4.2.45.2 (Apr 12 2001 10:06:52) for ONLINE_EVALUATION
Copyright 1988-2001 Comeau Computing.  All rights reserved.
MODE:strict errors C++

"14100.c", line 10: error: identifier "NS_SomeFunc" is undefined
    int rc = NS_SomeFunc(10);
             ^
Waldemar, can you shed any light here? Thanks,

/be
I looked over all of the comments above and looked at the relevant
sections of the standard.  It's clear to me that the compiler is
correct, given the quote mentioned in comment 15 and comment 18.  I
couldn't say it better than as stated in comment 18.

The one remaining dissenting opinion mentions a clause that does not
apply here and covers a different issue:

Comment 35 mentions section 11.4, clause 9.  This clause is not
relevant here because it deals only with what happens when you declare
a class *inside a function*.  This is a really bizarre thing to do --
it's a holdover from old C -- and C++ restricts what you can do there.
In particular, 11.4:9 states that when looking for functions or
classes to be made into friends, you *cannot* look outside the
enclosing function into the namespace or global scope.  See the
example in 11.4:9.

Outside a local class (i.e. a class defined inside a function), the
friend declaration *can* look into global and namespace scopes and
either find or declare things there.  As stated in 7.3.1.2, paragraph
3, these declarations are not visible until they are declared outside
a friend clause.
There are two more places in the code where the friend function needs to be
declared (as of Mozilla 0.9.8). Here is a patch fixing the last two remaining
problems.
Here is the most recent fix that cleans up all the remaining friend issues with
the AIX v5 compiler.
Attachment #68206 - Attachment is obsolete: true
Comment on attachment 72806 [details] [diff] [review]
Friend fixes for latest trunk build

sr=jag
Attachment #72806 - Flags: superreview+
Comment on attachment 72806 [details] [diff] [review]
Friend fixes for latest trunk build

a=asa (on behalf of drivers) for checkin to the 1.0 trunk
Attachment #72806 - Flags: approval+
Fix checked in
One more fix needed after the checkin for Bug 127097.
reopening to fix latest issue (see #44)
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Jag mentioned that no one should include nsString2.h instead
they should include nsString.h.  Switching this fixes the
compile issue.
Comment on attachment 75600 [details] [diff] [review]
alternative patch to 73249

with jag's r= you have a=asa for checkin to the 1.0 trunk. scc says this is a
good thing so I'm 'pre-approving'.
Attachment #75600 - Flags: approval+
Comment on attachment 75600 [details] [diff] [review]
alternative patch to 73249

r=/sr=jag
Attachment #75600 - Flags: superreview+
dbaron checked in the fix...
marking fixed (may this bug never be re-opened again...)
Status: REOPENED → RESOLVED
Closed: 23 years ago22 years ago
Resolution: --- → FIXED
Product: Browser → Seamonkey
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: