public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* New -ffriend-injection behavior - is it really intended?
@ 2007-05-23 14:46 Daniel Lohmann
  2007-05-23 15:57 ` Ian Lance Taylor
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Lohmann @ 2007-05-23 14:46 UTC (permalink / raw)
  To: gcc-help

Hi,

Today I noticed the new -ffriend-injection behavior of g++ 4.1.x, which
I do not really understand:

Consider the following code and command line session:

// File t.cc
1: class C {
2: public:
3:   friend C& f (C& x) { return x; }
4: };
5: int main () {
6:   C c;
7:   f( c );	// okay, found by adnl
8:   C & (*ptr) (C&) = f; // error
9: }

***

lohmann@faui48b:~$ g++ --version
g++ (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
Copyright (C) 2006 Free Software Foundation, Inc.

lohmann@faui48b:~$ g++ -o t t.cc
t.cc: In function ‘int main()’:
t.cc:8: error: ‘f’ was not declared in this scope
lohmann@faui48b:~$ g++-3.3 -o t t.cc
lohmann@faui48b:~$ g++ -ffriend-injection -o t t.cc
lohmann@faui48b:~$


The g++ man page states:

*>>>>>
-ffriend-injection
Inject friend functions into the enclosing namespace, so that they are
visible outside the scope of the class in which they are declared.
Friend functions were documented to work this way in the old Annotated
C++ Reference Manual, and versions of G++ before 4.1 always worked that
way.  However, in ISO C++ a friend function which is not declared in an
enclosing scope can only be found using argument dependent lookup.  This
option causes friends to be injected as they were in earlier releases.
This option is for compatibility, and may be removed in a future release
of G++.
*<<<<<


1) Where can I find this in the standard? From how I understand
ISO/IEC 14882:2003 (Second Edition), sec 11.4 "Friend", sentence 5 it
should exactly work like the "old behavior". Is my 2003 edition of the
standard already outdated?

2) Is it intentional that this practically removes the ability of
passing this functions to a function pointer, as in this case I do not
have an actual argument and therefore argument-dependent-name-lookup
(adnl) does not apply? (In principle, the compiler would be able to know
from the l-value expression where to find "f".)


Thanks a lot!

Daniel

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

* Re: New -ffriend-injection behavior - is it really intended?
  2007-05-23 14:46 New -ffriend-injection behavior - is it really intended? Daniel Lohmann
@ 2007-05-23 15:57 ` Ian Lance Taylor
  2007-05-24 21:09   ` Daniel Lohmann
  0 siblings, 1 reply; 6+ messages in thread
From: Ian Lance Taylor @ 2007-05-23 15:57 UTC (permalink / raw)
  To: Daniel Lohmann; +Cc: gcc-help

Daniel Lohmann <daniel.lohmann@informatik.uni-erlangen.de> writes:

> Today I noticed the new -ffriend-injection behavior of g++ 4.1.x, which
> I do not really understand:
> 
> Consider the following code and command line session:
> 
> // File t.cc
> 1: class C {
> 2: public:
> 3:   friend C& f (C& x) { return x; }
> 4: };
> 5: int main () {
> 6:   C c;
> 7:   f( c );	// okay, found by adnl
> 8:   C & (*ptr) (C&) = f; // error
> 9: }

> The g++ man page states:
> 
> *>>>>>
> -ffriend-injection
> Inject friend functions into the enclosing namespace, so that they are
> visible outside the scope of the class in which they are declared.
> Friend functions were documented to work this way in the old Annotated
> C++ Reference Manual, and versions of G++ before 4.1 always worked that
> way.  However, in ISO C++ a friend function which is not declared in an
> enclosing scope can only be found using argument dependent lookup.  This
> option causes friends to be injected as they were in earlier releases.
> This option is for compatibility, and may be removed in a future release
> of G++.
> *<<<<<
> 
> 
> 1) Where can I find this in the standard? From how I understand
> ISO/IEC 14882:2003 (Second Edition), sec 11.4 "Friend", sentence 5 it
> should exactly work like the "old behavior". Is my 2003 edition of the
> standard already outdated?

Do you mean this?

   "A function can be defined in a friend declaration of a class if
    and only if the class is a non-local class (9.8), the function
    name is unqualified, and the function has namespace scope.  Such a
    function is implicitly inline.  A friend function defined in a
    class is in the (lexical) scope of the class in which it is
    defined.  A friend function defined outside the class is not
    (3.4.1)."

There is nothing there which makes the friend function visible to any
other use.  You need an explicit declaration outside of the class to
permit other classes to see the function.

> 2) Is it intentional that this practically removes the ability of
> passing this functions to a function pointer, as in this case I do not
> have an actual argument and therefore argument-dependent-name-lookup
> (adnl) does not apply? (In principle, the compiler would be able to know
> from the l-value expression where to find "f".)

Just add a declaration visible at the point of use.  E.g.,

class C;
C& f (C&x);
class C {
public:
  friend C& f (C& x) { return x; }
};
int main () {
  C c;
  f( c );	// okay, found by adnl
  C & (*ptr) (C&) = f; // error
}

Ian

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

* Re: New -ffriend-injection behavior - is it really intended?
  2007-05-23 15:57 ` Ian Lance Taylor
@ 2007-05-24 21:09   ` Daniel Lohmann
  2007-05-24 21:10     ` Brian Dessent
  2007-05-25  4:21     ` Ian Lance Taylor
  0 siblings, 2 replies; 6+ messages in thread
From: Daniel Lohmann @ 2007-05-24 21:09 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-help



Ian Lance Taylor schrieb:
> Daniel Lohmann <daniel.lohmann@informatik.uni-erlangen.de> writes:
> 
>> Today I noticed the new -ffriend-injection behavior of g++ 4.1.x, which
>> I do not really understand:
>>
>> Consider the following code and command line session:
>>
>> // File t.cc
>> 1: class C {
>> 2: public:
>> 3:   friend C& f (C& x) { return x; }
>> 4: };
>> 5: int main () {
>> 6:   C c;
>> 7:   f( c );	// okay, found by adnl
>> 8:   C & (*ptr) (C&) = f; // error
>> 9: }
> 
>> The g++ man page states:
>>
>> *>>>>>
>> -ffriend-injection
>> Inject friend functions into the enclosing namespace, so that they are
>> visible outside the scope of the class in which they are declared.
>> Friend functions were documented to work this way in the old Annotated
>> C++ Reference Manual, and versions of G++ before 4.1 always worked that
>> way.  However, in ISO C++ a friend function which is not declared in an
>> enclosing scope can only be found using argument dependent lookup.  This
>> option causes friends to be injected as they were in earlier releases.
>> This option is for compatibility, and may be removed in a future release
>> of G++.
>> *<<<<<
>>
>>
>> 1) Where can I find this in the standard? From how I understand
>> ISO/IEC 14882:2003 (Second Edition), sec 11.4 "Friend", sentence 5 it
>> should exactly work like the "old behavior". Is my 2003 edition of the
>> standard already outdated?
> 
> Do you mean this?
> 
>    "A function can be defined in a friend declaration of a class if
>     and only if the class is a non-local class (9.8), the function
>     name is unqualified, and the function has namespace scope.  Such a
>     function is implicitly inline.  A friend function defined in a
>     class is in the (lexical) scope of the class in which it is
>     defined.  A friend function defined outside the class is not
>     (3.4.1)."
> 
> There is nothing there which makes the friend function visible to any
> other use.  You need an explicit declaration outside of the class to
> permit other classes to see the function.

Yes, this is exaclty the part I mean.
However, I do not understand how to come to your conclusion:

1) I guess the relevant sentence is: "A friend function defined in a class 
is in the (lexical) scope of the class in which *it* is defined." The 
question is what exactly the *it* refers to. To the class or to the 
function? What makes you sure it refers to the function?
(I should mention that I am not a native speaker, so this might be a simple 
language issue.)

2) In my standard, there is also an illustrating example:
[--example]
class C {
   friend void f() {}
};
[--end example]

The point is, that with the g++ 4.1 interpretation of the standard, f() is 
not visible in *any* scope:

lohmann@faui48a [~]>cat t.cc
class C {
   friend void f() {}

   void g() { f(); }
};

int main() {
   f();
  }

lohmann@faui48a [~]>g++ t.cc
t.cc: In member function 'void C::g()':
t.cc:4: error: 'f' was not declared in this scope
t.cc: In function 'int main()':
t.cc:8: error: 'f' was not declared in this scope
lohmann@faui48a [~]>

If g++ 4.1 interprets the standard in the way that f() is in the lexical 
scope spanned by class C it should be found by g(). If (as older versions 
did) the standard is interpreted in the way that f() is the scope in which 
C is defined, it should be found by main(). But neither scope? If this is 
really correct, it looks like a language defect to me.

3) How do you read from the standard that a friend function defined in a 
class *can* be found from the enclosing namespace (only) by argument 
dependent lookup (as stated in the -ffriend-injection documentation)?

4) And finally, do you know the *intention* behind all this? I am trying to 
imagine a good reason for the g++ 4.1 interpretation, but haven't been able 
to find one so far. I mean, it is just not a strong point for some 
interpretation if it obviously does not make sense...


Ian, please excuse me asking so many questions. Maybe I am totally wrong 
with all this, but this is kind of confusing.

Thanks!

Daniel


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

* Re: New -ffriend-injection behavior - is it really intended?
  2007-05-24 21:09   ` Daniel Lohmann
@ 2007-05-24 21:10     ` Brian Dessent
  2007-05-25  4:21     ` Ian Lance Taylor
  1 sibling, 0 replies; 6+ messages in thread
From: Brian Dessent @ 2007-05-24 21:10 UTC (permalink / raw)
  To: gcc-help

Daniel Lohmann wrote:

> 3) How do you read from the standard that a friend function defined in a
> class *can* be found from the enclosing namespace (only) by argument
> dependent lookup (as stated in the -ffriend-injection documentation)?
> 
> 4) And finally, do you know the *intention* behind all this? I am trying to
> imagine a good reason for the g++ 4.1 interpretation, but haven't been able
> to find one so far. I mean, it is just not a strong point for some
> interpretation if it obviously does not make sense...

I think you can find some language-lawyering on the topic here:
<http://www.open-std.org/JTC1/sc22/wg21/docs/cwg_closed.html#95>.  As
far as I understand it, the original early C++ standard (Annotated C++
Reference/ARM) called for name injection, but this was changed during
the drafting of the formal ISO C++ spec, which is but one of a number of
incompatibilities between the two standards.  I'm not sure of the
rationale but if you dig around on the wg21 site you should be able to
find more.

The gcc bug report tracking the change:
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=7874>.  Note that it was
actually a regression in gcc 3.x against 2.95 that was never reconciled
until 4.1.  So this really is nothing new at all, it's just that
removing functionality in a compiler requires a deprecation period and a
lot of waiting.

Brian

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

* Re: New -ffriend-injection behavior - is it really intended?
  2007-05-24 21:09   ` Daniel Lohmann
  2007-05-24 21:10     ` Brian Dessent
@ 2007-05-25  4:21     ` Ian Lance Taylor
  2007-05-25  9:13       ` David Fang
  1 sibling, 1 reply; 6+ messages in thread
From: Ian Lance Taylor @ 2007-05-25  4:21 UTC (permalink / raw)
  To: Daniel Lohmann; +Cc: gcc-help

Daniel Lohmann <daniel.lohmann@informatik.uni-erlangen.de> writes:

> Ian Lance Taylor schrieb:
> >    "A function can be defined in a friend declaration of a class if
> >     and only if the class is a non-local class (9.8), the function
> >     name is unqualified, and the function has namespace scope.  Such a
> >     function is implicitly inline.  A friend function defined in a
> >     class is in the (lexical) scope of the class in which it is
> >     defined.  A friend function defined outside the class is not
> >     (3.4.1)."
> > There is nothing there which makes the friend function visible to any
> > other use.  You need an explicit declaration outside of the class to
> > permit other classes to see the function.
> 
> Yes, this is exaclty the part I mean.
> However, I do not understand how to come to your conclusion:
> 
> 1) I guess the relevant sentence is: "A friend function defined in a
> class is in the (lexical) scope of the class in which *it* is
> defined." The question is what exactly the *it* refers to. To the
> class or to the function? What makes you sure it refers to the
> function?
> (I should mention that I am not a native speaker, so this might be a
> simple language issue.)

"it" refers to the function.  I agree this is ambiguous, but it would
be contorted English for "it" to refer to the class.  And it would not
make sense if the class were not itself defined in some other class.


> 2) In my standard, there is also an illustrating example:
> [--example]
> class C {
>    friend void f() {}
> };
> [--end example]
> 
> The point is, that with the g++ 4.1 interpretation of the standard,
> f() is not visible in *any* scope:
> 
> lohmann@faui48a [~]>cat t.cc
> class C {
>    friend void f() {}
> 
>    void g() { f(); }
> };
> 
> int main() {
>    f();
>   }
> 
> lohmann@faui48a [~]>g++ t.cc
> t.cc: In member function 'void C::g()':
> t.cc:4: error: 'f' was not declared in this scope
> t.cc: In function 'int main()':
> t.cc:8: error: 'f' was not declared in this scope
> lohmann@faui48a [~]>
> 
> If g++ 4.1 interprets the standard in the way that f() is in the
> lexical scope spanned by class C it should be found by g(). If (as
> older versions did) the standard is interpreted in the way that f() is
> the scope in which C is defined, it should be found by main(). But
> neither scope? If this is really correct, it looks like a language
> defect to me.

Hmmm.  That does look strange.  I would have expected that f would be
found in C::g, but I agree that gcc does not work that way at present.
This may be a gcc bug.

I'm confident that it's not a gcc bug that f is not found in main.


> 3) How do you read from the standard that a friend function defined in
> a class *can* be found from the enclosing namespace (only) by argument
> dependent lookup (as stated in the -ffriend-injection documentation)?
> 
> 4) And finally, do you know the *intention* behind all this? I am
> trying to imagine a good reason for the g++ 4.1 interpretation, but
> haven't been able to find one so far. I mean, it is just not a strong
> point for some interpretation if it obviously does not make sense...

I don't know.

I recommend asking on a C++ language mailing list.

Ian

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

* Re: New -ffriend-injection behavior - is it really intended?
  2007-05-25  4:21     ` Ian Lance Taylor
@ 2007-05-25  9:13       ` David Fang
  0 siblings, 0 replies; 6+ messages in thread
From: David Fang @ 2007-05-25  9:13 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Daniel Lohmann, gcc-help

> > The point is, that with the g++ 4.1 interpretation of the standard,
> > f() is not visible in *any* scope:
> >
> > lohmann@faui48a [~]>cat t.cc
> > class C {
> >    friend void f() {}
> >
> >    void g() { f(); }
> > };
> >
> > int main() {
> >    f();
> >   }

> > If g++ 4.1 interprets the standard in the way that f() is in the
> > lexical scope spanned by class C it should be found by g(). If (as
> > older versions did) the standard is interpreted in the way that f() is
> > the scope in which C is defined, it should be found by main(). But
> > neither scope? If this is really correct, it looks like a language
> > defect to me.
>
> Hmmm.  That does look strange.  I would have expected that f would be
> found in C::g, but I agree that gcc does not work that way at present.
> This may be a gcc bug.
>
> I'm confident that it's not a gcc bug that f is not found in main.

The change was documented here:
http://gcc.gnu.org/gcc-4.1/changes.html

Related bug reports contain some discussions: 1016, 16995 [meta]
(ton of invalid dupes too)

> > 4) And finally, do you know the *intention* behind all this? I am
> > trying to imagine a good reason for the g++ 4.1 interpretation, but
> > haven't been able to find one so far. I mean, it is just not a strong
> > point for some interpretation if it obviously does not make sense...
>
> I don't know.
>
> I recommend asking on a C++ language mailing list.

<opinion>
Name injection was always hideous and created really confusing situations
where a friend declaration was deep inside a nested class.  Unless you
*like* having to look things up in the standard, some answers just weren't
obvious (to me at least).  Consider:
	class A {
	class B {
	friend class C; // where does this go? A::C or ::C?
	};
	};
It also implied that parsing a class had *side-effects* (evil) to the
enclosing namespace.  (Such non-modularity could've impeded pre-compiled
class headers, or other syntax tree shortcuts.)  This also meant you
couldn't necessarily speed read over a class definition without looking at
its friends.

The best policy is to always forward declare the prototype/class that you
would normally expect to inject.

I'm all for comprehensibility and less ambiguity.
Good riddance to friend-injection!
(but thank goodness for backwards compatibility switches)
</opinion>


Fang

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

end of thread, other threads:[~2007-05-25  4:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-05-23 14:46 New -ffriend-injection behavior - is it really intended? Daniel Lohmann
2007-05-23 15:57 ` Ian Lance Taylor
2007-05-24 21:09   ` Daniel Lohmann
2007-05-24 21:10     ` Brian Dessent
2007-05-25  4:21     ` Ian Lance Taylor
2007-05-25  9:13       ` David Fang

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).