public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/35394]  New: Agressive template instantiation?
@ 2008-02-27 17:36 proy at clg dot qc dot ca
  2008-03-04  4:28 ` [Bug c++/35394] " proy at clg dot qc dot ca
  2008-03-05  2:56 ` [Bug c++/35394] Aggressive " bangerth at dealii dot org
  0 siblings, 2 replies; 3+ messages in thread
From: proy at clg dot qc dot ca @ 2008-02-27 17:36 UTC (permalink / raw)
  To: gcc-bugs

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 4151 bytes --]

I think recent versions of g++ (4.*, for example, but not 3.4.4) go too far
performing C++ template instantiation. Mind you, this is only a guess, and you
guys will know better.

Here's the problem case. The code shown below should (in my opinion) compile
properly as is but should not compile when the 2nd line of main() is not
commented out.

This «non-compilability» of the 2nd line is made on purpose, to simplify static
error checking, and relies on a technique similar to the one made by boost's
static assert on most platforms. The intent is to cause meaningful error
messages in cases where we can "see them coming", without preventing correct
programs to compile. In main(), the 1st line is expected to be legal and the
2nd (when it's not commented out) is illegal. What I see as a bug here is that
the code for generic class not_compilable seems to be considered even when the
code does not use it.

In more detail: the goal of the test cas below is to provoke a compile-time
failure that describes the error using the template parameter Reason in generic
class not_compilable, but only when the static int value used for factorial is
negative. This test code compiles (or does not compile, depending on the case)
fine using most compilers at my disposal (g++ 3.3* and 3.4* included) but most
of my students using g++ 4.* report that this code fails to compile even when
only the 1st line of main() is there. I would like to give you guys more info
but all g++ compilers around me seem to handle this correctly; only "recent
versions" (at least from 4.1* on) seem to mishandle it (at least if one
considers, as I do, the following technique to be valid C++).

The code follows...

// -------------------

//
// static_assert is provided here for clarity; remove it or
// rename it if it is provided by your compiler
//
template <bool>
   struct static_assert;
template <>
   struct static_assert<true> {};

//
// A class made not to compile, on purpose. Since it is generic, my
// expectation is that it should not be considered if it is not being
// used. It is syntactically correct and compiles fine (when not used)
// on older g++ (3.3* to 3.4* at least) and on all compilers at my
// disposal, as mentioned above
//
template <class Reason>
   class not_compilable
   {
      enum { dummy_value = sizeof (static_assert<false>) };
   };

//
// A class that does compile :)
//
struct compilable
{
};

//
// A static type selector
//
template <bool, class, class>
   struct static_if_else;
template <class IfTrue, class IfFalse>
   struct static_if_else<true, IfTrue, IfFalse>
   {
      typedef IfTrue type;
   };
template <class IfTrue, class IfFalse>
   struct static_if_else<false, IfTrue, IfFalse>
   {
      typedef IfFalse type;
   };

//
// An empty class to add meaning when factorial<N> does
// not compile using a negative value for N
//
class negative_value_not_accepted {};

//
// A class that should only compile when N>=0 and that
// should fail otherwise
//
template <int N>
   struct factorial
      : private static_if_else<
           (N<0), not_compilable<negative_value_not_accepted>, compilable
        >::type
   {
      enum { value = N * factorial<N-1>::value };
   };
template <>
   struct factorial<0>
   {
      enum { value = 1 };
   };

//
// The test program. My understanding is that it should compile
// when only the 1st line is included and that it should not
// compile when the 2nd line is included. What I see as a bug is
// that g++ 4.1*+ seems not to accept even the 1st line, considering
// not_compilable even though it is not being used by the program...
//
#include <iostream>
using std::cout;
int main ()
{
   cout << factorial<5>::value; // Cool; should compile
   //cout << factorial<-3>::value; // should not compile
}


-- 
           Summary: Agressive template instantiation?
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: proy at clg dot qc dot ca


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


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

* [Bug c++/35394] Agressive template instantiation?
  2008-02-27 17:36 [Bug c++/35394] New: Agressive template instantiation? proy at clg dot qc dot ca
@ 2008-03-04  4:28 ` proy at clg dot qc dot ca
  2008-03-05  2:56 ` [Bug c++/35394] Aggressive " bangerth at dealii dot org
  1 sibling, 0 replies; 3+ messages in thread
From: proy at clg dot qc dot ca @ 2008-03-04  4:28 UTC (permalink / raw)
  To: gcc-bugs

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 4723 bytes --]



------- Comment #1 from proy at clg dot qc dot ca  2008-03-04 04:28 -------
For those interested: it might help to know that, on all g++ compilers that I
know of and that have this bug (at least from my understanding of the
situation), one could replace

template <class Reason>
   class not_compilable
   {
      enum { dummy_value = sizeof (static_assert<false>) };
   };

with

template <class Reason>
   class not_compilable
   {
      static static_assert<false> dummy_fct ();
      enum { dummy_value = sizeof (dummy_fct ()) };
   };

and it would compile, which (somehow) makes the situation even more
suspicious...

(In reply to comment #0)
> I think recent versions of g++ (4.*, for example, but not 3.4.4) go too far
> performing C++ template instantiation. Mind you, this is only a guess, and you
> guys will know better.
> 
> Here's the problem case. The code shown below should (in my opinion) compile
> properly as is but should not compile when the 2nd line of main() is not
> commented out.
> 
> This «non-compilability» of the 2nd line is made on purpose, to simplify static
> error checking, and relies on a technique similar to the one made by boost's
> static assert on most platforms. The intent is to cause meaningful error
> messages in cases where we can "see them coming", without preventing correct
> programs to compile. In main(), the 1st line is expected to be legal and the
> 2nd (when it's not commented out) is illegal. What I see as a bug here is that
> the code for generic class not_compilable seems to be considered even when the
> code does not use it.
> 
> In more detail: the goal of the test cas below is to provoke a compile-time
> failure that describes the error using the template parameter Reason in generic
> class not_compilable, but only when the static int value used for factorial is
> negative. This test code compiles (or does not compile, depending on the case)
> fine using most compilers at my disposal (g++ 3.3* and 3.4* included) but most
> of my students using g++ 4.* report that this code fails to compile even when
> only the 1st line of main() is there. I would like to give you guys more info
> but all g++ compilers around me seem to handle this correctly; only "recent
> versions" (at least from 4.1* on) seem to mishandle it (at least if one
> considers, as I do, the following technique to be valid C++).
> 
> The code follows...
> 
> // -------------------
> 
> //
> // static_assert is provided here for clarity; remove it or
> // rename it if it is provided by your compiler
> //
> template <bool>
>    struct static_assert;
> template <>
>    struct static_assert<true> {};
> 
> //
> // A class made not to compile, on purpose. Since it is generic, my
> // expectation is that it should not be considered if it is not being
> // used. It is syntactically correct and compiles fine (when not used)
> // on older g++ (3.3* to 3.4* at least) and on all compilers at my
> // disposal, as mentioned above
> //
> template <class Reason>
>    class not_compilable
>    {
>       enum { dummy_value = sizeof (static_assert<false>) };
>    };
> 
> //
> // A class that does compile :)
> //
> struct compilable
> {
> };
> 
> //
> // A static type selector
> //
> template <bool, class, class>
>    struct static_if_else;
> template <class IfTrue, class IfFalse>
>    struct static_if_else<true, IfTrue, IfFalse>
>    {
>       typedef IfTrue type;
>    };
> template <class IfTrue, class IfFalse>
>    struct static_if_else<false, IfTrue, IfFalse>
>    {
>       typedef IfFalse type;
>    };
> 
> //
> // An empty class to add meaning when factorial<N> does
> // not compile using a negative value for N
> //
> class negative_value_not_accepted {};
> 
> //
> // A class that should only compile when N>=0 and that
> // should fail otherwise
> //
> template <int N>
>    struct factorial
>       : private static_if_else<
>            (N<0), not_compilable<negative_value_not_accepted>, compilable
>         >::type
>    {
>       enum { value = N * factorial<N-1>::value };
>    };
> template <>
>    struct factorial<0>
>    {
>       enum { value = 1 };
>    };
> 
> //
> // The test program. My understanding is that it should compile
> // when only the 1st line is included and that it should not
> // compile when the 2nd line is included. What I see as a bug is
> // that g++ 4.1*+ seems not to accept even the 1st line, considering
> // not_compilable even though it is not being used by the program...
> //
> #include <iostream>
> using std::cout;
> int main ()
> {
>    cout << factorial<5>::value; // Cool; should compile
>    //cout << factorial<-3>::value; // should not compile
> }
> 


-- 


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


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

* [Bug c++/35394] Aggressive template instantiation?
  2008-02-27 17:36 [Bug c++/35394] New: Agressive template instantiation? proy at clg dot qc dot ca
  2008-03-04  4:28 ` [Bug c++/35394] " proy at clg dot qc dot ca
@ 2008-03-05  2:56 ` bangerth at dealii dot org
  1 sibling, 0 replies; 3+ messages in thread
From: bangerth at dealii dot org @ 2008-03-05  2:56 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #2 from bangerth at dealii dot org  2008-03-05 02:55 -------

This is called two-stage name lookup: when parsing a template all occurrences
of "things" that do not depend on the template parameter are bound to their
global definitions. Thus, here...

> template <class Reason>
>    class not_compilable
>    {
>       enum { dummy_value = sizeof (static_assert<false>) };
>    };

...even though we're in a template the compiler sees that static_assert<false>
is a classname that does not depend on the (currently) unknown template
parameter 'Reason' and so is supposed to be replaced for sizeof. This fails,
a behavior mandated by the C++ standard.

On the other hand, here...

> template <class Reason>
>    class not_compilable
>    {
>       static static_assert<false> dummy_fct ();
>       enum { dummy_value = sizeof (dummy_fct ()) };
>    };

...you ask the compiler to evaluate sizeof
(not_compilable<Reason>::dummy_fct())
which depends on the template parameter 'Reason' and so its evaluation is
deferred till we know the template type 'Reason', i.e. till instantiation
time. If you never instantiate it, there's no error.

W.


-- 

bangerth at dealii dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bangerth at dealii dot org
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|                            |INVALID


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


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

end of thread, other threads:[~2008-03-05  2:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-27 17:36 [Bug c++/35394] New: Agressive template instantiation? proy at clg dot qc dot ca
2008-03-04  4:28 ` [Bug c++/35394] " proy at clg dot qc dot ca
2008-03-05  2:56 ` [Bug c++/35394] Aggressive " bangerth at dealii dot org

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