Bug 16635 - g++ instantiates templates at the wrong place
Summary: g++ instantiates templates at the wrong place
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.0.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid, wrong-code
: 35799 37225 38762 42292 (view as bug list)
Depends on:
Blocks: 23885 41995
  Show dependency treegraph
 
Reported: 2004-07-19 19:45 UTC by Geoff Keating
Modified: 2011-12-16 18:30 UTC (History)
11 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 3.3, 4.0.0, 4.3.1, 4.4.0
Last reconfirmed: 2004-10-30 17:51:00


Attachments
smime.p7s (1.63 KB, application/pkcs7-signature)
2004-07-31 01:07 UTC, Geoff Keating
Details
smime.p7s (1.64 KB, application/pkcs7-signature)
2005-06-23 19:32 UTC, Geoff Keating
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Geoff Keating 2004-07-19 19:45:21 UTC
Consider the following:

template <class T> T * foo (T * x)
{ 
  return x++;
}

struct aclass;

aclass *
addone (aclass * x)
{ 
  return foo<aclass>(x);
}

struct aclass
{ 
  int x;
};

At the point where foo<aclass> is instantiated, 'aclass' is incomplete, and 'x++' requires it to be 
complete, so this program is not well-formed, and a diagnostic is required.
Comment 1 Wolfgang Bangerth 2004-07-19 20:23:18 UTC
Confirmed. I'm sure Giovanni has something to say about this. 
 
W. 
Comment 2 Giovanni Bajo 2004-07-31 00:25:53 UTC
I am not 100% sure about this. Geoff, why do you think GCC is wrong? FWIW EDG 
does exactly the same. Do you have a specific quote from the standard?
Comment 3 Geoff Keating 2004-07-31 01:07:14 UTC
Subject: Re:  g++ doesn't diagnose instantiation of template that uses incomplete type


On 30/07/2004, at 5:25 PM, giovannibajo at libero dot it wrote:

>
> ------- Additional Comments From giovannibajo at libero dot it  
> 2004-07-31 00:25 -------
> I am not 100% sure about this. Geoff, why do you think GCC is wrong? 
> FWIW EDG
> does exactly the same. Do you have a specific quote from the standard?

Um, why do you think GCC is right?

[expr.add] says in paragraph 1, "one operand shall be a pointer to a 
completely defined object type".

[temp.inst], paragraph 2, says "the function template specialization is 
implicitly instantiated when the specialization is referenced in a 
context that requires a function definition to exist", which is at the 
point of the call to foo<aclass> in the original example.  [temp.res] 
says in paragraph 8 "The lookup of names dependent on the template 
parameters is postponed until the actual template argument is known 
(14.6.2)" and 'until' in the standard is precise, it means lookup 
happens at that point, which here is also the point of the call.

[temp.res] also says in paragraph 7 "if a template is instantiated, 
errors will be diagnosed according to the other rules in this 
Standard", although I think it's just trying to be helpful by 
clarifying the rest of the paragraph, which is mostly about how you 
don't have to have any diagnostics when a template isn't instantiated, 
and which makes it valid to write 'some_class<incomplete_type> *' even 
if some_class<incomplete_type> has 'incomplete_type' as a member.

So at the point of the call, name lookup is complete, and errors are 
diagnosed according to the rest of the standard, including the rule in 
[expr.add].
Comment 4 Geoff Keating 2004-07-31 01:07:15 UTC
Created attachment 6859 [details]
smime.p7s
Comment 5 Geoff Keating 2005-04-26 06:53:58 UTC
Here's the same thing with overloaded functions, causing a wrong-code error.  If the last definition of 
'bar' is commented out, the testcase passes, but otherwise not.

template <class T> int func(T & x)
{
  return bar (x);
}

int bar(const int & x)
{
  return x;
}

extern "C" void abort ();

int main (void)
{
  int x = 3;
  if (func<int>(x) != 3)
    abort ();
}

int bar (int &x)
{
  return x + 3;
}
Comment 6 Andrew Pinski 2005-06-23 01:19:55 UTC
(In reply to comment #5)
> Here's the same thing with overloaded functions, causing a wrong-code error.  If the last definition of 
> 'bar' is commented out, the testcase passes, but otherwise not.
That code is acutally invalid and really should have been rejected see PR 2922 for that.
Comment 7 Andrew Pinski 2005-06-23 01:27:59 UTC
(In reply to comment #6)
> (In reply to comment #5)
> > Here's the same thing with overloaded functions, causing a wrong-code error.  If the last definition 
of 
> > 'bar' is commented out, the testcase passes, but otherwise not.
> That code is acutally invalid and really should have been rejected see PR 2922 for that.

Also if we move the template func after bar and main after the second bar, we get back to basicially PR 
2922.  So the first testcase is the only one which the problem for this bug.
Comment 8 Geoff Keating 2005-06-23 19:32:15 UTC
Subject: Re:  g++ instantiates templates at the wrong place


On 22/06/2005, at 9:19 PM, pinskia at gcc dot gnu dot org wrote:

>
> ------- Additional Comments From pinskia at gcc dot gnu dot org   
> 2005-06-23 01:19 -------
> (In reply to comment #5)
>
>> Here's the same thing with overloaded functions, causing a wrong- 
>> code error.  If the last definition of
>> 'bar' is commented out, the testcase passes, but otherwise not.
>>
> That code is acutally invalid and really should have been rejected  
> see PR 2922 for that.

Yes, apparently it should, following the discussion in DR 197.

The following example, similar to the corrected one from DR 197, is a  
wrong-code:

void f(char);

template <class T> void g(T t)
{
   f(T(1));     // dependent
   f(t);        // dependent
}

enum E { e };

void h()
{
   g(e);  // calls f(char) twice
}

void f(E);  // should make no difference

because it calls f(E) twice rather than f(char).
Comment 9 Geoff Keating 2005-06-23 19:32:18 UTC
Created attachment 9137 [details]
smime.p7s
Comment 10 Andrew Stubbs 2007-05-31 10:57:41 UTC
Here's another issue in this area. Is it the same, or a separate bug? This code is adapted from the example in DR197.

#include <stdio.h>

struct C1 {};
struct C2 : C1 {
};

C1 c1;
C2 c2;

    void f(C1);

    template <class T> void g(T t)
    {
        f(c2);  // f(C1) should be the nearest match
        f(t);   // dependent
    }

    void f(C2);

    int main()
    {
        g(c2);       // will cause one call of f(C1) followed
                     // by one calls of f(C2)
        g(c1);      // will cause two calls of f(C1)
    }

void f(C1) { printf ("C1\n");}
void f(C2) { printf ("C2\n");}

What actually happens (with the 4.1.1 I have anyway) is three calls to f(C2) followed by one call to f(C1). This shows that the *non-dependent* call is being resolved in the wrong scope also - it should not be able to see f(C2).

If the prototype for f(C2) is removed, then the previously described problem is apparent also, and the (incorrect) behaviour of the program is unchanged.
Comment 11 Andrew Pinski 2008-04-03 02:51:55 UTC
*** Bug 35799 has been marked as a duplicate of this bug. ***
Comment 12 Andrew Pinski 2008-08-29 03:47:15 UTC
*** Bug 37225 has been marked as a duplicate of this bug. ***
Comment 13 Andrew Pinski 2009-01-09 20:27:39 UTC
*** Bug 38762 has been marked as a duplicate of this bug. ***
Comment 14 Andrew Pinski 2009-12-05 00:10:19 UTC
*** Bug 42292 has been marked as a duplicate of this bug. ***
Comment 15 Jason Merrill 2010-01-06 19:40:50 UTC
I believe http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#993 will be resolved to allow the G++ behavior.  Suspending.
Comment 16 Jonathan Wakely 2011-12-16 11:08:03 UTC
(In reply to comment #15)
> I believe http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#993 will
> be resolved to allow the G++ behavior.  Suspending.

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#993 so this is INVALID?
Comment 17 Jason Merrill 2011-12-16 18:30:54 UTC
Yep.