[Bug c++/23885] incorrect template two-stage name-lookup

martin dot audet at imi dot cnrc-nrc dot gc dot ca gcc-bugzilla@gcc.gnu.org
Wed May 30 21:03:00 GMT 2007



------- Comment #6 from martin dot audet at imi dot cnrc-nrc dot gc dot ca  2007-05-30 21:02 -------
I'm the original submiter of this bug and I'am not sure now if it's a bug in
g++ template instantiation mechanism (e.g. problem with the two phase name
lookup) or if the code example itself is standard compliant.

We need a couple of C++ experts to look at this "problem" carefully to decide
if the two phases template name binding process is incorrect as I reported or
if the code sample is incorrect (if that's the case maybe g++ needs to emit a
warning at least) or if g++ current behavior is correct.

I'm now expressing doubts since I submited a similar issue with Intel C/C++
compiler using the following code sample (similar but slightly longer):

#include <iostream>

// "f" in g<T>(T) should bind to this function even if "f"
//  is overloaded later with a more "natural" version.
void f(double) { std::cout << "Function f(double)" << std::endl; }

template<class T> void g(T a) {
  f(123);      // "f" is not a dependent name. Binding occurs at definition
(e.g. here). 
  h(a);        // "h" is a dependent name. Binding will occurs at instantiation
point.
}

// "f" in g<T>(T) should not bind to this function even if it is more
"natural".
void f(int)    { std::cout << "Function f(int)"    << std::endl; }

// "h" in g<int>() should be bound to this function even
//  if "h" is overloded later with a more "natural" version.
void h(double) { std::cout << "Function h(double)" << std::endl; }

// Instantiation point for g<int>().

void i(void) {
  extern void h(int);    // Should not influence the choice of the "h"
function.
                         //  because it is out of scope at instantiation point. 
                         // Note: the problem with h instantiation occur even
                         //  if this declaration is commented out.
  g(234);                // g<int>(234) is called.
}

// "h" in g<int>() should be not be bound to this version of
//  "h" function even if it is more "natural". This is because
//  its declaration occurs after instatiation point.
void h(int) { std::cout << "Function h(int)" << std::endl; }

int main(void)
{
   // Should print:
   //                 "Function f(double)".
   //                 "Function h(double)".
   i();

   return 0;
}


This code was taken from an example in a IBM Developer Works article where the
author explained that the two phases template name binding process (the
comments are added by me). The article stated that the correct result was to
print:

   Function f(double)
   Function h(double)

I remember at that time trying it on one AIX machine witch xlC C++ compiler and
it effectively printed that result. I also tried it on a few other
compilers/systems and I remember having the four possible outcomes
(f(double)/f(int), h(double)/h(int)).

Recent g++ and icpc (Intel C++ compiler v9.1) versions now prints:

  Function f(double)
  Function h(int)

Since I was convinced that this was a bad result I submited this bug report for
g++ and a bug report for Intel compiler.

The answer I finally got from Intel compiler team (before closing the case)
suggest that this code sample isn't standard compliant and therefore there
wasn't a template instantiation problem. Here is the answer I got:

Intel answer BEGIN

Hi Martin,

The development team has had another look at this and have determined that the
test case is not standard conforming.

"""
The compiler is right to issue the error.

There are two rules for the Dependent name resolution in C++ strandard.

14.6.4 Dependent name resolution [temp.dep.res]
1 In resolving dependent names, names from the following sources are
considered:
- Declarations that are visible at the point of definition of the
template.
- Declarations from namespaces associated with the types of the function
arguments both from the instantiation context (14.6.4.1) and from the
definition context.

The first rule, said we need to have a declaration of "h" before definition of
the template. But in this test case we don't have.

For the second rule, the namespaces for type "int" is empty according 3.4.2 as
following. So this test case does not match this rule too. The test case is
not standard conforming. The compiler is right on it.

3.4.2.
For each argument type T in the function call, there is a set of zero or more
associated namespaces and a set of zero or more associated classes to be
considered. The sets of namespaces and classes is determined entirely by the
types of the function arguments (and the namespace of any template template
argument). Typedef names and usingdeclarations used to specify the types do
not contribute to this set. The sets of namespaces and classes are determined
in the following way:

- If T is a fundamental type, its associated sets of namespaces and
classes are both empty.
"""

Thank you.
-- 

Intel answer END

So with this answer I don't know what to think, is the sample program standard
compliant ? Is there a warning missing ? Is the current name binding process
for template standard compliant ?

We need C++ experts to look at this problem.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23885



More information about the Gcc-bugs mailing list