Bug 10437 - "using namespace" at global scope creates incorrect code
"using namespace" at global scope creates incorrect code
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: c++
3.2.2
: P3 normal
: ---
Assigned To: Not yet assigned to anyone
: rejects-valid
Depends on:
Blocks: 12944
  Show dependency treegraph
 
Reported: 2003-04-19 00:36 UTC by dean
Modified: 2014-05-13 10:58 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.8.0, 4.9.0
Known to fail:
Last reconfirmed: 2005-05-16 02:30:03


Attachments
namespace_error.cc (10.06 KB, text/x-c++ )
2003-05-21 15:17 UTC, dean
Details

Note You need to log in before you can comment on or make changes to this bug.
Description dean 2003-04-19 00:36:00 UTC
Code compiles differently if it looks like:

using namespace foo;
main()
{
  /* ... */
}

VS:

main()
{
  using namespace foo;
   /* ... */
}

My guess is that templates in the namespace foo are instantiated incorrectly.  I'm not totally possitive this is an error, but it seems like either an error in g++, or an error in the definition of how templates should be instantiated.

I cut the file down from several 1000 lines of code to under 400 lines.  I'm sorry that I haven't been able to reproduce it with fewer lines of code.  But if you look at the last 20 lines of code, I have flagged the troublesome statement.

Release:
g++ 3.2.2

Environment:
linux

How-To-Repeat:
uncomment the line marked that is near the end of the file.
Comment 1 dean 2003-04-19 00:36:00 UTC
Fix:
Not a clue!
Comment 2 Wolfgang Bangerth 2003-04-21 15:03:33 UTC
From: Wolfgang Bangerth <bangerth@ices.utexas.edu>
To: Dean Foster <foster@diskworld.wharton.upenn.edu>
Cc: dean@foster.net, <gcc-bugs@gcc.gnu.org>, <gcc-gnats@gcc.gnu.org>
Subject: Re: c++/10437: "using namespace" at global scope creates incorrect
 code
Date: Mon, 21 Apr 2003 15:03:33 -0500 (CDT)

 > I'm willing to agree that that I've have an error/ambiguity in my
 > code.  But I don't understand why bringing in a namespace that isn't
 > being called should change the ambiguity status.
 
 The point is that in order to find out which function the compiler 
 shall take, it needs to know about the possibilities. For this, the
 possible declarations must "work". Without knowing your choices, you can't 
 perform overload resolution.
 
 
 > In other words,
 > 
 > 		main()
 > 		{
 > 		  using namespace foo;
 > 		  /* ... */           // no error
 > 		}
 > doesn't generate an error. But, the following does generate an error:
 > 		  
 > 		using namespace foo;
 > 		main()
 > 		{
 > 		  /* ... */         // generates error
 > 		}
 > 
 > It seems that [they] should be the same. 
 
 I guess that should be so.
 
 I can't reproduce this with the small example I posted. Can you try to 
 come up with something short that shows this? Your original example was 
 incredibly contrived, and I don't want to go through the ordeal again of 
 reducing it, which took me well over an hour. Hint: try stripping template 
 parameters, and replacing typedefs by the types the point to, etc. Once 
 it's well below 100 lines I'll be willing to look at it again :-)
 
 W.
 
 -------------------------------------------------------------------------
 Wolfgang Bangerth              email:            bangerth@ices.utexas.edu
                                www: http://www.ices.utexas.edu/~bangerth/
 
 

Comment 3 Wolfgang Bangerth 2003-04-21 15:06:06 UTC
State-Changed-From-To: open->closed
State-Changed-Why: I don't think this is a bug. After quite some reducing,
    your code looks like this:
    ---------------------------
    struct X {
        int operator-(const X& it);
    };
    
    template <class T>
    struct Y {
        typedef typename T::SOME_TYPE SOME_TYPE;
        typedef int type;
    };
    
    #ifdef BUG
    template <class T> typename Y<T>::type operator-(T,T);
    #endif
    
    int x = X() - X();
    -----------------------------
    (I replaced your using directive by the conditional
    statement -- both just bring into visibility the
    operator-.)
    
    What happens is that in the minus statement (which was
    inside a std:: function in your example), both possible
    operator- are considered, i.e. the member function and
    the global one. The global one requires instantiation
    of Y, at which point we realize that X::SOME_TYPE does
    not exist:
    g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ -c x.cc -DBUG
    x.cc: In instantiation of `Y<X>':
    x.cc:15:   instantiated from here
    x.cc:7: error: no type named `SOME_TYPE' in `struct X'
    
    Tracing back where this happens in your code is a little
    more complicated, but I guess this is what happens -- you
    try to use __gnu_cxx::normal_iterator::const_iterator
    when bringing into scope the function in the namespace,
    but this const_iterator doesn't exist.
    
    Wolfgang
Comment 4 foster 2003-04-21 19:18:52 UTC
From: Dean Foster <foster@diskworld.wharton.upenn.edu>
To: bangerth@dealii.org, dean@foster.net, gcc-bugs@gcc.gnu.org,
  gcc-prs@gcc.gnu.org, nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
Cc:  
Subject: Re: c++/10437: "using namespace" at global scope creates incorrect code
Date: 21 Apr 2003 19:18:52 -0000

 Sorry about forcing you to do more of the reduction.  I did at least
 remove several 1000 lines of code!  But, every time I tried reducing
 it further, I ended up removing the problem.  Thanks.
 
 I'm willing to agree that that I've have an error/ambiguity in my
 code.  But I don't understand why bringing in a namespace that isn't
 being called should change the ambiguity status.  In other
 words,
 
 		main()
 		{
 		  using namespace foo;
 		  /* ... */           // no error
 		}
 doesn't generate an error.  Neither does:
 
 		main()
 		{
 		  /* ... */          // no error
 		}
 
 But, the following does generate an error:
 		  
 		using namespace foo;
 		main()
 		{
 		  /* ... */         // generates error
 		}
 
 It seems that the first and the 3rd should be the same.  So maybe the
 problem is that the third one is correct and that the first two should
 catch the ambigity?  Or is my understanding of namespaces incorrect?
 
 
 later,
 
 dean
 
 
 =============================================================================
 Dean Foster                                                   dean@foster.net
 Statistics, Wharton, U. Penn                                     215 898 8233
 Philadelphia PA 19104-6340                 http://diskworld.wharton.upenn.edu
 
 
 > Date: 21 Apr 2003 15:06:07 -0000
 > From: bangerth@dealii.org
 > Reply-To: bangerth@dealii.org, dean@foster.net, gcc-bugs@gcc.gnu.org,
 >   gcc-prs@gcc.gnu.org, nobody@gcc.gnu.org, gcc-gnats@gcc.gnu.org
 > X-SBRule: Spammy To: Header
 > X-SBRule: Other Spammy Headers
 > 
 > Synopsis: "using namespace" at global scope creates incorrect code
 > 
 > State-Changed-From-To: open->closed
 > State-Changed-By: bangerth
 > State-Changed-When: Mon Apr 21 15:06:06 2003
 > State-Changed-Why:
 >     I don't think this is a bug. After quite some reducing,
 >     your code looks like this:
 >     ---------------------------
 >     struct X {
 >         int operator-(const X& it);
 >     };
 >     
 >     template <class T>
 >     struct Y {
 >         typedef typename T::SOME_TYPE SOME_TYPE;
 >         typedef int type;
 >     };
 >     
 >     #ifdef BUG
 >     template <class T> typename Y<T>::type operator-(T,T);
 >     #endif
 >     
 >     int x = X() - X();
 >     -----------------------------
 >     (I replaced your using directive by the conditional
 >     statement -- both just bring into visibility the
 >     operator-.)
 >     
 >     What happens is that in the minus statement (which was
 >     inside a std:: function in your example), both possible
 >     operator- are considered, i.e. the member function and
 >     the global one. The global one requires instantiation
 >     of Y, at which point we realize that X::SOME_TYPE does
 >     not exist:
 >     g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ -c x.cc -DBUG
 >     x.cc: In instantiation of `Y<X>':
 >     x.cc:15:   instantiated from here
 >     x.cc:7: error: no type named `SOME_TYPE' in `struct X'
 >     
 >     Tracing back where this happens in your code is a little
 >     more complicated, but I guess this is what happens -- you
 >     try to use __gnu_cxx::normal_iterator::const_iterator
 >     when bringing into scope the function in the namespace,
 >     but this const_iterator doesn't exist.
 >     
 >     Wolfgang
 > 
 > http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=10437
 > 

Comment 5 Wolfgang Bangerth 2003-04-25 14:15:09 UTC
From: Wolfgang Bangerth <bangerth@ices.utexas.edu>
To: gcc-gnats@gcc.gnu.org
Cc:  
Subject: Re: c++/10437: "using namespace" at global scope creates incorrect
 code (fwd)
Date: Fri, 25 Apr 2003 14:15:09 -0500 (CDT)

 ---------- Forwarded message ----------
 Date: 22 Apr 2003 11:59:01 -0000
 From: Dean Foster <foster@diskworld.wharton.upenn.edu>
 To: bangerth@ices.utexas.edu
 Subject: Re: c++/10437: "using namespace" at global scope creates incorrect
     code
 
 
 I've shortened it down to about 50 lines.  (Took several 100 compiles.
 First to generate the error then move the one line, and confirm the
 error goes away!)  It is cut-and-pasted at the end of this email.
 
 There are several lines that turned out to be needed in order for the
 error to be generated.  The line ** 1 ** actually generates the error.
 The line ** 2 ** calls the error_generator.  Line ** 3 ** is where the
 error is.  It shouldn't ever try the apl::operator-() code, but it
 does if the "using namespace" is outside of the main().
 
 Move line ** 4 ** around to see the most obvious way that this is an
 error. 
 
 Thanks for your willingness to be patient.  Of course putting "using
 namespace"'s at global scope is pure evil!  We only had it in our test
 code.  
 
 later,
 
 dean
 
 
 =============================================================================
 Dean Foster                                                   dean@foster.net
 Statistics, Wharton, U. Penn                                     215 898 8233
 Philadelphia PA 19104-6340                 http://diskworld.wharton.upenn.edu
 =============================================================================
 
 // $Id: namespace_error.cc,v 4.29 2003/04/22 11:45:10 foster Exp $  
 
 #include <utility>
 
 class Iterator
 {
 public:
   void operator-(Iterator){};
 };
  
 template < class T>
 class flag_error 
 {
 public:
   typedef typename T::type_doesnt_exist unused_type;                   // ** 1 **
   typedef std::pair<T,T> pair;
 };
 
 namespace apl
 {  
   template <class T>
   typename flag_error<T>::pair                                          // ** 2 **
   operator-(const T& ,  const T& )
   {
   }
 } 
 
 std::pair<Iterator,Iterator>
 pair_iterator_constructor()
 {
 };
 
 template<class T>
 void
 foo(T t)
 {
   t.first - t.second;                                                   // ** 3 **
 }
 
 //  moving ** 4 ** from inside to outside of the main() changes from "legal" to "errors"
 
 using namespace apl;                                                    // ** 4 **
 int main()
 { 
   foo(pair_iterator_constructor());
 }
 
 
 
 
Comment 6 Wolfgang Bangerth 2003-04-25 14:37:44 UTC
From: Wolfgang Bangerth <bangerth@ices.utexas.edu>
To: Dean Foster <foster@diskworld.wharton.upenn.edu>
Cc: gcc-gnats@gcc.gnu.org, <gcc@gcc.gnu.org>
Subject: Re: c++/10437: "using namespace" at global scope creates incorrect
 code
Date: Fri, 25 Apr 2003 14:37:44 -0500 (CDT)

 > I've shortened it down to about 50 lines.  (Took several 100 compiles.
 
 OK, I tested this and I now see two issues here. Number one:
 -----------------------
 namespace NS {
   template <class T> void foo (const T&);
 }
 
 template<class T> void bar() {
   foo (T());
 }
 
 using namespace NS;
 
 int main() {
  bar<int>();
 }
 -----------------------
 This compiles. Should it? At the point of declaration of bar(), NS::foo is 
 not visible, but the call is template dependent (i.e. two-stage name 
 lookup kicks in), so we also have to take into account everything that is 
 visible at the point of instantiation, where NS::foo _is_ visible, due to 
 the global scope using directive. I wasn't aware of the fact, though, that 
 using directives work retroactively for two-stage name lookup as well. 
 (icc tends to agree with me here, it rejects the code.)
 
 However, the code stops to compile if the "using" is moved inside main(). 
 I think that for visibility of foo inside bar, only symbols declared in the 
 scope of main, not inside it should be relevant, which would explain this. 
 Can someone confirm this?
 
 
 Point 2: Given the above -- this doesn't compile:
 ----------------------
 template <class T> struct X {
     typedef typename T::type_doesnt_exist type;
 };
 
 void foo(int);
 
 template <class T>
 typename X<T>::inexistent  foo (const T&);
 
 template<class T> void bar() {  foo(T());  }
 
 
 int main() { bar<int>(); }
 -----------------------
 
 The compiler says:
 g/x> ~/bin/gcc-3.4-pre/bin/c++ -c x.cc
 x.cc: In instantiation of `X<int>':
 x.cc:12:   instantiated from `void bar() [with T = int]'
 x.cc:16:   instantiated from here
 x.cc:4: error: `int' is not a class, struct, or union type
 
 Why isn't this just a SFINAE failure, which would lead to the silent 
 rejection of the foo template? (icc rejects this code as well, so I think 
 gcc should be right, but I don't understand why.)
 
 W.
 
 -------------------------------------------------------------------------
 Wolfgang Bangerth              email:            bangerth@ices.utexas.edu
                                www: http://www.ices.utexas.edu/~bangerth/
Comment 7 Wolfgang Bangerth 2003-04-25 19:38:54 UTC
State-Changed-From-To: closed->analyzed
State-Changed-Why: I just send an extended analysis. Needs a language lawyer, though.
Comment 8 Dara Hazeghi 2003-12-18 18:07:33 UTC
Nathan, would you mind commenting on the validity of this code? Thanks.
Comment 9 Nathan Sidwell 2003-12-22 16:36:29 UTC
Ok, First point1. Do using declarations work retroactively in this regard.
For a dependent name, the answer is yes, sort of. [14.6.4] lists the places you
look to resolve a dependent name, and they are
1) declarations that are visible at the point of definition of the template
2) declarations from namespaces associated with the type of the function arguments
both from the instantiation context and from the definition context.

That 2nd part is an amalgamated koenig lookup. In this case the type is int, so
has no associated namespaces, and hence adds nothing to the overload set.

Thus, I believe instantiation of bar will give an unresolved call for foo.

Now the second point. This a case of SFINAE failure, no diagnostic should
be issued. The call of foo in bar must resolve to ::foo(int), as the other
posibility ::foo<int>(const int &) gives a substitution failure.

The EDG compiler accepts this code.
Comment 10 Wolfgang Bangerth 2004-08-16 19:02:29 UTC
Still happens. To my great surprise, icc also barfs at the 
example listed as "point 2", with the same error message as gcc. 
 
W. 
Comment 11 Richard Smith 2014-05-12 23:52:29 UTC
(In reply to Nathan Sidwell from comment #9)
> Now the second point. This a case of SFINAE failure, no diagnostic should
> be issued.

I disagree. The failure is not in the immediate context of the substitution, so this is a hard error. GCC seems to be doing the right thing in all cases here.
Comment 12 Jonathan Wakely 2014-05-13 08:28:45 UTC
(In reply to Richard Smith from comment #11)
> I disagree. The failure is not in the immediate context of the substitution,
> so this is a hard error. GCC seems to be doing the right thing in all cases
> here.

Agreed. I think GCC has been fixed in both respects since this was active and this can be closed (maybe after adding the examples to the test suite, but I think we have equivalents already).
Comment 13 Paolo Carlini 2014-05-13 10:58:54 UTC
Let's close this, then.