Topic: a defect in FCD? (constexpr functions)


Author: restor <akrzemi1@gmail.com>
Date: Mon, 28 Jun 2010 14:01:58 CST
Raw View
Hi,
Could someone tell me if the following is a bug in the FCD or in my
reasoning?

My reading of 5.19/6 (i.e. my translation to human language) is: an
Expression can be called a Potential Constant Expression only if for
all possible combinations of parameter values it will render a
Constant Expression.

Now, 5.19/2, bullet 5 requires that the result must be mathematically
defined and in the range of representable values for its type.

This makes the following constexpr functions invalid:

 constexpr int add( int x, int y ) {
   return x + y;
 }

Invalid because there exists an arbitrary substitution of parameters
with values
 x = std::numeric_limits<int>::max()
 y = std::numeric_limits<int>::max()
that makes the result not in the range of representable values for its
type.

 constexpr int square( int x ) {
   return x * x;
 }

(Example from FCD) invalid because of the following possible arbitrary
substitution
 x = std::numeric_limits<int>::max()

 constexpr int abs( int x ) {
   return x < 0 ? -x : x;
 }

(Example from FCD) invalid because of the following possible arbitrary
substitution
 x = (-std::numeric_limits<int>::max() -1), i.e. the lowest possible
value doesn't have
a positive equivalent in Two's complement representation.

 constexpr int division( int x, int y ) {
   return x / y;
 }

Invalid ... , and so on...

This could be solved by appending 5.19/6 with something like "Except
that if an expression
fails to render constant expression as a result of the above
substitution due to the result being not in the range of representable
values for its type, the expression is still a potential constant
expression; in such a case, however evaluating the expression with
values that make the result not in the range of representable values
for its type in the constant expression context makes the program ill-
formed, and evaluating  the expression with values that make the
result not in the range of representable values for its type in non-
constant expression context is an undefined behavior."

Or this could be solved by defining constant expression in terms of
potential constant expression, rather than doing the inverse.

Regards,
&rzej

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: CornedBee <wasti.redl@gmx.net>
Date: Tue, 29 Jun 2010 17:51:57 CST
Raw View
On Jun 28, 10:01 pm, restor <akrze...@gmail.com> wrote:
> Hi,
> Could someone tell me if the following is a bug in the FCD or in my
> reasoning?
>
> My reading of 5.19/6 (i.e. my translation to human language) is: an
> Expression can be called a Potential Constant Expression only if for
> all possible combinations of parameter values it will render a
> Constant Expression.

The text isn't very clear, but I believe the intent of "arbitrary" is
"choose one that fits". That is, a constant expression is a potential
constant expression if there is *any* combination of arguments that
yield a valid constant expression. This is consistent with:
1) The examples in the standard. They are now valid.
2) The name Potential Constant Expression. A PCE has the potential to
be a CE if the right arguments are stuffed in.
3) Usefulness.

For example, this is not a PCE (although I daresay that many compilers
won't diagnose it unless you actually try to use it, if then):

int overflow(int i) {
 return ((i + std::numeric_traits<int>::max()) +
std::numeric_traits<int>::max()) + std::numeric_traits<int>::max();
}

because there is no possible value for i that yields a valid CE here,
due to every possible value overflowing.

Sebastian


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: restor <akrzemi1@gmail.com>
Date: Thu, 1 Jul 2010 00:53:19 CST
Raw View
> > My reading of 5.19/6 (i.e. my translation to human language) is: an
> > Expression can be called a Potential Constant Expression only if for
> > all possible combinations of parameter values it will render a
> > Constant Expression.
>
> The text isn't very clear, but I believe the intent of "arbitrary" is
> "choose one that fits". That is, a constant expression is a potential
> constant expression if there is *any* combination of arguments that
> yield a valid constant expression. This is consistent with:
> 1) The examples in the standard. They are now valid.
> 2) The name Potential Constant Expression. A PCE has the potential to
> be a CE if the right arguments are stuffed in.
> 3) Usefulness.

Hi,
First, considring the normative text rather than the intent, I believe
that the word "arbitrary" is closer to saying "someone might pick a
nasty value for your function" rather than "if you can find one, it is
ok". (I admit, I am not sure, not being an English speaker.) So, even
if the intent is different, and the normative text has a bug, but we
all know what it should say, this is a defect in FCD that needs
fixing.

Second, considering an intent rather than the normative text, I am not
sure if the intent was "choose one that fits". This would allow
writing functions like:

 constexpr int VerifyPositiveNumber( int i ) {
   return i > 0 ? i : throw Exception();
 }

A throw in constexpr function? Yes, because there exists an arbitrary
value of i (e.g. 1) that renders a constant expression: unevaluated
operands of conditional operator can do anything (according to 5.19/2)
- this makes sense (for constant expressions) since they are not
evaluated anyway.

While the example above would be useful (I imagine
VerifyPositiveNumber(1) would return 1, and VerifyPositiveNumber(0)
would fail to compile), I met interpretations of the Standard in this
group that say it is not allowed.

Regards,
&rzej

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Fri, 2 Jul 2010 16:01:07 CST
Raw View
On 30 Jun., 01:51, CornedBee <wasti.r...@gmx.net> wrote:
> On Jun 28, 10:01 pm, restor <akrze...@gmail.com> wrote:
>
> > Could someone tell me if the following is a bug in the FCD or in my
> > reasoning?
>
> > My reading of 5.19/6 (i.e. my translation to human language) is: an
> > Expression can be called a Potential Constant Expression only if for
> > all possible combinations of parameter values it will render a
> > Constant Expression.
>
> The text isn't very clear, but I believe the intent of "arbitrary" is
> "choose one that fits". That is, a constant expression is a potential
> constant expression if there is *any* combination of arguments that
> yield a valid constant expression. This is consistent with:
> 1) The examples in the standard. They are now valid.
> 2) The name Potential Constant Expression. A PCE has the potential to
> be a CE if the right arguments are stuffed in.
> 3) Usefulness.

This is correct.

> For example, this is not a PCE (although I daresay that many compilers
> won't diagnose it unless you actually try to use it, if then):
>
> int overflow(int i) {
>  return ((i + std::numeric_traits<int>::max()) +
> std::numeric_traits<int>::max()) + std::numeric_traits<int>::max();
> }
>
> because there is no possible value for i that yields a valid CE here,
> due to every possible value overflowing.

I'm not sure what you mean with "won't diagnose it unless you
actually
try to use it", but exactly for this example there is no requirement
at
all - whether used or not in any context - that a compiler has to
diagnose anything here. This is so, because there is no *requirement*,
that any part of the return expression is a constant expression.

If this was actually supposed to be a *constexpr* function,

constexpr int overflow(int i) {
 return ((i + std::numeric_traits<int>::max()) +
 std::numeric_traits<int>::max()) + std::numeric_traits<int>::max();
 // Could be ill-formed, but not required. For machines where
 // overflow would raise a hardware exception, reordering
 // is not allowed, see 1.9/8+9.
}

the following would apply: No diagnostic *required* here - only in
any
expression,  which require to evaluate to constant expressions as in

constexpr int x1 = overflow(0); // Error

but *not* in

const int x2 = overflow(0); // OK, no requirement that x2 can be used
                                     // in constant expressions

constexpr int x3 = x2; // Error, x2 is no constant expression

HTH & Greetings from Bremen,

Daniel Kr   gler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Fri, 2 Jul 2010 16:27:38 CST
Raw View
On 1 Jul., 08:53, restor <akrze...@gmail.com> wrote:

> First, considring the normative text rather than the intent, I believe
> that the word "arbitrary" is closer to saying "someone might pick a
> nasty value for your function" rather than "if you can find one, it is
> ok". (I admit, I am not sure, not being an English speaker.) So, even
> if the intent is different, and the normative text has a bug, but we
> all know what it should say, this is a defect in FCD that needs
> fixing.

This is not really a proof, that this is a defect in the FCD wording.
It would be one, if you can show (a) a clear contradiction within
the wording or (b) demonstrate that implementations differ. There
might be need to improve the wording, but currently I'm not
convinced of this.

> Second, considering an intent rather than the normative text, I am not
> sure if the intent was "choose one that fits". This would allow
> writing functions like:
>
>  constexpr int VerifyPositiveNumber( int i ) {
>    return i > 0 ? i : throw Exception();
>  }
>
> A throw in constexpr function? Yes, because there exists an arbitrary
> value of i (e.g. 1) that renders a constant expression: unevaluated
> operands of conditional operator can do anything (according to 5.19/2)
> - this makes sense (for constant expressions) since they are not
> evaluated anyway.

This rationale is wrong, because *any* occurrence of a *potentially
evaluated* throw-expression prevents the whole return expression from
being a potential constant expression, see 5.19/2 (I did explain
that once incorrectly, so I repeat that here to prevent a
misunderstanding).

As Sebastian described: A *potential constant expression* must
have the potential of being a constant expression if replaced by
an *arbitrary* value. "Arbitrary" just means that we don't know the
actual one and must assume that it may be the wrong one - so to
say. *Only* throw expressions (and other forbidden stuff) that are
*unevaluated* are allowed, but this is not the case here. I think
that 5.19 says this rather clear.

Given only the definition of VerifyPositiveNumber, the argument
i is an opaque value for us and we cannot exclude that it is
i <= 0. This again means that the throw-expression is
an potentially evaluated expression. We can say that without
having any actual value at our hands. This again means that it is
irrelevant for this example whether any arguments might make
the expression well-formed. We can simplify that to the following:

constexpr int bar(bool v) {
 return v ? throw 0 : 0;
}

There are only two possible values of v (50:50 chance), but still the
throw-expression is potentially evaluated, therefore this return
expression does not satisfy the criteria for a potential constant
expression. Let's look now at:

constexpr int foo(bool v) {
 return v ? INT_MAX + 1 : 0;
}

This is *also* ill-formed, because "INT_MAX + 1" is potentially
evaluated.
But

constexpr int foobar(int arg) {
 return arg + 1;
}

is well-formed, because the expression arg + 1 does not itself
lead to an overflow - any overflow here could only be decided
depending on the context:

a) constexpr int x1 = foobar(INT_MAX); // Error, no constant
expression

b) const int x2 = foobar(INT_MAX); // Undefined behaviour, because no
   // requirement exists that foobar(INT_MAX) is a constant
expression

> While the example above would be useful (I imagine
> VerifyPositiveNumber(1) would return 1, and VerifyPositiveNumber(0)
> would fail to compile), I met interpretations of the Standard in this
> group that say it is not allowed.

The *definition* of VerifyPositiveNumber is already ill-formed,
because of the *potentially evaluated* throw-expression. This
does not depend on concrete and possible values of the function
arguments.

HTH & Greetings from Bremen,

Daniel Kr   gler



--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Sun, 4 Jul 2010 14:35:27 CST
Raw View
On 3 Jul, 02:27, Daniel Kr   gler <daniel.krueg...@googlemail.com>
wrote:
>
> This is not really a proof, that this is a defect in the FCD wording.
> It would be one, if you can show (a) a clear contradiction within
> the wording or (b) demonstrate that implementations differ. There
> might be need to improve the wording, but currently I'm not
> convinced of this.

Unclear wording can be considered a defect in spite of absence of
contradictions or any implemented behavior. An international standard
must be precise in all aspects.

> > A throw in constexpr function? Yes, because there exists an arbitrary
> > value of i (e.g. 1) that renders a constant expression: unevaluated
> > operands of conditional operator can do anything (according to 5.19/2)
> > - this makes sense (for constant expressions) since they are not
> > evaluated anyway.
>
> This rationale is wrong, because *any* occurrence of a *potentially
> evaluated* throw-expression prevents the whole return expression from
> being a potential constant expression, see 5.19/2

Can you explain the meaning of the wording "but subexpressions of
logical AND (5.14), logical OR (5.15), and conditional (5.16)
operations that are not evaluated are not considered" in 5.19/2?

And what could you say about the following example?

   #include <typeinfo>

   struct Polymorphic
   {
       virtual ~Polymorphic() {}
   };

   Polymorphic &f(...) { throw 0; }
   void f(void *);

   constexpr int g(int n)
   {
       return typeid(throw 0, f(n * 0)), 0;
   }

   int main() {}

According to 5.19/2 and 5.19/6 bullet 1, the expression

   typeid(throw 0, f(n * 0)), 0

is a potential constant expression (which actually can never give a
constant expression).

Since n is not a constant expression, n * 0 is not a null pointer
constant, so the first f shall be selected, throw 0, f(n * 0) is an
lvalue of polymorphic type, typeid(throw 0, f(n * 0)) is not a
constant expression, and typeid(throw 0, f(n * 0)), 0 is not a
constant expression.

However, when considering the replacement described in 5.19/6 bullet 1
(for the purposes of determining whether the expression is a potential
constant expression), n is considered as prvalue constant expression,
then n * 0 will be treated as null pointer constant, the second f will
be considered as the selected function, throw 0, f(n * 0) will be
considered as an expression of type void, typeid(throw 0, f(n * 0))
will be considered as a constant expression, and typeid(throw 0, f(n *
0)), 0 will be considered as a constant expression.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "peter miller" <fuchsia.groan@virgin.net>
Date: Tue, 6 Jul 2010 02:29:56 CST
Raw View
On Fri, 02 Jul 2010 23:27:38 +0100, Daniel Kr   gler
<daniel.kruegler@googlemail.com> wrote:
[...]
>
> This rationale is wrong, because *any* occurrence of a *potentially
> evaluated* throw-expression prevents the whole return expression from
> being a potential constant expression, see 5.19/2

[...]

Okay, consider:

#define POSITIVE_INT( x ) ( x >= 0 ? x : throw 0 )

Now:

enum {
 X = POSITIVE_INT(1),   // compiles (tested: gcc 4.5)
 Y = POSITIVE_INT(-1)   // error
};

template <int i>
struct metafunc { static const int value = POSITIVE_INT(i); };

template struct metafunc<1>;  // compiles (tested: gcc 4.5)

template struct metafunc<-1>; // error (error)

int main()
{
  POSITIVE_INT( 1 );  // fine
  POSITIVE_INT( -1 ); // exception.
  return 0;
}

Curtsey of 5.19/2, POSITIVE_INT is an expression with all the properties
required, except the ability to be put in a constexpr function.  I can't see
where the standard forbids that.

(gcc 4.5 refuses to have std::domain_error in the throw subexpression, but I
think that violates 5.19/2)

Anyway, let's suppose you are correct--and I'm just a Joe Coder--then I offer
the following, fragment which has the desired effect without recourse to
exceptions:

constexpr int positive_int( int i )
 { return i / ( i >= 0 ); }

Negative i force a compile error when used in a constexpr. The runtime error
is a (structured) exception under Windows, *sigh*, and can be trapped via SIGFPE
on Posix systems. (Could I throw an exception from within the SIGFPE signal
handler?) QED.


Peter


--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: restor <akrzemi1@gmail.com>
Date: Sat, 10 Jul 2010 01:56:07 CST
Raw View
> As Sebastian described: A *potential constant expression* must
> have the potential of being a constant expression if replaced by
> an *arbitrary* value. "Arbitrary" just means that we don't know the
> actual one and must assume that it may be the wrong one - so to
> say. *Only* throw expressions (and other forbidden stuff) that are
> *unevaluated* are allowed, but this is not the case here. I think
> that 5.19 says this rather clear.

So I gathter "arbitrary" means the expression has to be CE *for all*
possible parameter values.
I am still trying to understand the concept of PCE. It looks like I
agree with all your below examples, but not with the explanation.
Now I can see that the only restrictions on a PCE is on its
subexpressions, but not on the full-expression.

> Given only the definition of VerifyPositiveNumber, the argument
> i is an opaque value for us and we cannot exclude that it is
> i <= 0. This again means that the throw-expression is
> an potentially evaluated expression. We can say that without
> having any actual value at our hands. This again means that it is
> irrelevant for this example whether any arguments might make
> the expression well-formed. We can simplify that to the following:
>
> constexpr int bar(bool v) {
>  return v ? throw 0 : 0;
>
> }

ill-formed: subexpression "throw 0" is potentially evaluated.

> There are only two possible values of v (50:50 chance), but still the
> throw-expression is potentially evaluated, therefore this return
> expression does not satisfy the criteria for a potential constant
> expression. Let's look now at:
>
> constexpr int foo(bool v) {
>  return v ? INT_MAX + 1 : 0;
>
> }

ill-formed: subexpression "INT_MAX + 1" is potentially evaluated.

> This is *also* ill-formed, because "INT_MAX + 1" is potentially
> evaluated.
> But
>
> constexpr int foobar(int arg) {
>  return arg + 1;
> }

well-formed: "arg + 1" is potentially evaluated, but is not a
subexpression

> is well-formed, because the expression arg + 1 does not itself
> lead to an overflow - any overflow here could only be decided
> depending on the context:
>
> a) constexpr int x1 = foobar(INT_MAX); // Error, no constant
> expression
>
> b) const int x2 = foobar(INT_MAX); // Undefined behaviour, because no
>    // requirement exists that foobar(INT_MAX) is a constant
> expression

But consider this:

 constexpr int increment(int arg) {
   return arg + 1 + 0;
 }

ill-formed: "arg + 1" is now a sub-expression: and is potentially
evaluated, because it is potentially an overflow.
In the same manner, but some more realistic example:


 constexpr int hourAsSeconds( int days ) {
       return days * 60 * 60;
 }

ill-formed: "days * 60" is a sub-expression, and is potentially
evaluated.
Well, I could be wrong in the interpretation of "subexpression"
because it is not defined in the standard.

BTW, this whole post is the consequence of my pursuit of a way to
report errors in consexpr functions. You left me with the note that it
was possible, but I still cannot figure out how.

Regards,
&rzej

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: CornedBee <wasti.redl@gmx.net>
Date: Sun, 18 Jul 2010 15:27:43 CST
Raw View
On Jul 10, 12:56 am, restor <akrze...@gmail.com> wrote:
> > As Sebastian described: A *potential constant expression* must
> > have the potential of being a constant expression if replaced by
> > an *arbitrary* value. "Arbitrary" just means that we don't know the
> > actual one and must assume that it may be the wrong one - so to
> > say. *Only* throw expressions (and other forbidden stuff) that are
> > *unevaluated* are allowed, but this is not the case here. I think
> > that 5.19 says this rather clear.
>
> So I gathter "arbitrary" means the expression has to be CE *for all*
> possible parameter values.

if that is the correct interpretation of the standard, then constexpr
is stillborn. I stick with my interpretation.

Sebastian


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]