Bug 55737 - Template and the constant, short-form if-then-else condition issue
Summary: Template and the constant, short-form if-then-else condition issue
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.6.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-12-19 00:08 UTC by GS
Modified: 2013-02-27 13:05 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description GS 2012-12-19 00:08:25 UTC
Please part me if the summary isn't so informative. Can't put what's on my mind in a few words.

So my system info is:
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Linux 3.2.0-34-generic-pae #53-Ubuntu SMP Thu Nov 15 11:11:12 UTC 2012 i686 athlon i386 GNU/Linux

Consider the next code snippet:

template <int X>
struct DivByX
{
    enum
    {
        value1 = X,
        value2 = int(100.f / value1)
    };
};

enum
{
    valueA = 0,
    /// False branch in the condition should never be taken into account.
    /// And moreover, template should be constructed.
    valueB = (/* Always false >>>*/1 > 2 /*<<<*/) ? /* False branch >>>*/((1 < DivByX<0>::value2) ? 2 : 3)/*<<<*/ : 1
};


I did some template research and stumbled upon this annoying bug. It's really annoying because i need to do stuff like:

template <int X>
struct DivByX
{
    enum
    {
        real_x = X == 0 ? 1 : X,
        value1 = X,
        value2 = int(100.f / value1)
    };
};

So the problem hides in the if-then-else branch, that is discarded because of the condition, but in fact processed by the compiler. Though this happens only when in the false branch expression there is template used. The error i get:

test.cpp: In instantiation of ‘DivByX<0>’:
test.cpp:63:89:   instantiated from here
test.cpp:52:5: warning: division by zero [-Wdiv-by-zero]
test.cpp:52:5: error: ‘(1.0e+2f / 0.0f)’ is not a constant expression
test.cpp:52:5: error: enumerator value for ‘value2’ is not an integer constant

To give some comparison: clang works as intended.

Thank you for your attention.
Comment 1 Andrew Pinski 2012-12-19 00:24:09 UTC
I think GCC is correct here as for a?b:c to be an integer constant expression, all three (a, b, and c) have to be an integer constant expressions even if a is true or false.
Comment 2 GS 2012-12-19 10:31:45 UTC
Hey Andrew. You words completely logical,. But I think it can be avoided when condition can be calculated during compilation. Though it's only my opinion.


Though I still have a couple of counter arguments in my pocket :). First of all, clang++ compiles with out errors. Not an important argument, I know. The second one is code snippet:

enum
{
    valueA = 0,
    /// False branch in the condition should never be taken into account.
    /// And moreover, template should be constructed.
    valueB = (/* Always false >>>*/1 > 2 /*<<<*/) ? /* False branch >>>*/int(1.0f / 0)/*<<<*/ : 1
};

It doesn't whine about division by 0. So either former case or the later is a bug.
Comment 3 Jonathan Wakely 2012-12-19 15:54:22 UTC
(Your testcase would be a lot easier to read without all those comments inside the conditional expression, I think it's safe to assume everyone here knows which is the false branch of a conditional expression!)

A conditional expression is not a "static if" so  templates in both branches of the conditional expression are instantiated, and instantiating DivByX<0> fails.

You could work around this by preventing instantiation of the problem case, the simplest way is to specialize the template:

template <>
struct DivByX<0>
{
    enum
    {
        value1 = X,
        value2 = 0;
    };
};

Now it doesn't matter if the DivByX<0> case is instantiated because it doesn't divide by zero.
Comment 4 GS 2012-12-19 16:11:11 UTC
Always nice to read friendly replies :). Sure I could. As I said, I'm not sure I was right in the first place. Just wanted to help to make gcc better than clang. Where I need no workarounds. 

Also, what about second case from my previous comment:

enum
{
    valueA = 0,
    valueB = (/1 > 2) ? int(1.0f / 0) : 1
};

Why doesn't this generate error, or at least warning?

Thanks.
Comment 5 Jonathan Wakely 2012-12-19 16:13:08 UTC
because it doesn't instantiate a template that requires the divide-by-zero in an integer constant context
Comment 6 Paolo Carlini 2013-02-27 13:05:53 UTC
Closing.