Bug 11814 - Code with missing "template" keyword wrongly accepted
Summary: Code with missing "template" keyword wrongly accepted
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid, monitored, rejects-valid
: 20516 37596 41973 57312 (view as bug list)
Depends on:
Blocks: c++-lookup, c++-name-lookup 6023 20308
  Show dependency treegraph
 
Reported: 2003-08-05 23:09 UTC by Volker Reichelt
Modified: 2017-01-11 20:02 UTC (History)
12 users (show)

See Also:
Host:
Target:
Build:
Known to work: 7.0
Known to fail: 3.3, 4.5.3, 4.8.3, 4.9.3, 5.3.0, 6.3.0
Last reconfirmed: 2006-09-03 21:39:18


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Volker Reichelt 2003-08-05 23:09:39 UTC
Here's a spin-off from PR 6023:
The following code snippet is wrongly accepted by gcc:

-------------------------------------------
template <typename> struct A
{
    template <typename> void foo();
};

template <typename T> struct B
{
    template <int> void foo()
    {
        A<T>* p;
        p->foo<int>(); // wrong: should be "p->template foo<int>();"
    }
};
-------------------------------------------

Since "p" is dependent on the outer template parameter, we need a "template"
here. The parser wrongly accepts it because it finds "foo" in the current
scope which happens to be a template (although it's actually the wrong "foo"
that is considered for parsing). (This was pointed out by Nathan.)

To see this effect, just remove the "template <int>" from the second "foo"
and the compiler gioves an error message.

This bug affects all versions since gcc 2.95.x.
Comment 1 Andrew Pinski 2003-08-05 23:34:17 UTC
I can confirm this on the mainline (20030805).
Here is a more interesting example where the two template function foo take two different 
template arguments:
template <typename> struct A
{
    template <int> void foo();
};
template <typename T> struct B
{
    template <int> void foo()
    {
        A<T>* p;
        p->foo<1>(); // wrong: should be "p->template foo<1>();"  
    }
};
Comment 2 Andrew Pinski 2003-08-06 00:38:44 UTC
My comment in 1 is wrong, the example I gave is where they have the same type 
template agruments not different.
Comment 3 Volker Reichelt 2003-08-08 00:07:50 UTC
Maybe related to PR 10200.
Comment 4 Kriang Lerdsuwanakij 2003-11-23 11:36:32 UTC
Probably problem deciding if a name is dependent.
Comment 5 Andrew Pinski 2004-05-25 14:16:37 UTC
Hmm, ICC 6.0 accepts the code also (even in strict mode).
Comment 6 Andrew Pinski 2005-03-17 13:58:50 UTC
*** Bug 20516 has been marked as a duplicate of this bug. ***
Comment 7 Jonathan Wakely 2005-03-25 20:38:26 UTC
This can be simplified to:

template <class T> void f()
{
  T t;
  t.f<>(0); //should be t.template f<>(0);
}

If either 'f' is renamed g++ correctly reports an error.

Comeau's online compiler behaves the same.
Comment 8 Andrew Pinski 2006-01-04 01:11:41 UTC
This is also related to PR 20308 (I think they are more than related, I think they are the same bug but reproducing in a different way).
Comment 9 David Fang 2007-05-08 20:48:10 UTC
Still accepts-invalid with 4.2-20070430 (RC2).
Comment 10 Andrew Pinski 2008-12-27 06:34:19 UTC
*** Bug 37596 has been marked as a duplicate of this bug. ***
Comment 11 Andrew Pinski 2009-11-06 19:05:20 UTC
*** Bug 41973 has been marked as a duplicate of this bug. ***
Comment 12 Wolfgang Bangerth 2011-10-09 13:52:05 UTC
Still happens with gcc4.5.1.
Comment 13 Jonathan Wakely 2011-10-09 14:01:26 UTC
and 4.7.0
Comment 14 Paolo Carlini 2013-05-17 10:42:34 UTC
*** Bug 57312 has been marked as a duplicate of this bug. ***
Comment 15 Andrew Pinski 2015-01-15 18:02:25 UTC
*** Bug 64611 has been marked as a duplicate of this bug. ***
Comment 16 Martin Sebor 2017-01-11 20:02:28 UTC
With the current trunk of GCC 7.0 the test cases are rejected as expected (GCC 6 still accepts it).  Closing as fixed.

$ cat t.C && gcc -O2 -S -Wall -Wextra t.C
template <typename> struct A
{
    template <typename> void foo();
};

template <typename T> struct B
{
    template <int> void foo()
    {
        A<T>* p;
        p->foo<int>(); // wrong: should be "p->template foo<int>();"
    }
};
t.C: In member function ‘void B<T>::foo()’:
t.C:11:16: error: expected primary-expression before ‘int’
         p->foo<int>(); // wrong: should be "p->template foo<int>();"
                ^~~
t.C:11:16: error: expected ‘;’ before ‘int’