Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Magissima
Apr 15, 2013

I'd like to introduce you to some of the most special of our rocks and minerals.
Soiled Meat

steckles posted:

Request denied. Reason: The old code is “burnt in”. I’ve heard that one used a few times to justify the continued existence of some of the deeper, stranger places in our codebase.

I've had this happen with date-handling code a couple times. "Luckily" everything will be "okay" as long as we never ever have code or a database running west of central time

Adbot
ADBOT LOVES YOU

That Dang Lizard
Jul 13, 2016

what; an idiomt

Magissima posted:

I've had this happen with date-handling code a couple times. "Luckily" everything will be "okay" as long as we never ever have code or a database running west of central time

It could be worse, like that bug with the F-22 where all the electronics crashed when they crossed the international date line.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

RPATDO_LAMD posted:

You're allowed to have a constexpr function that returns a compile-time constant if passed compile-time-constant arguments but just gets called normally if passed variable / runtime values.
They up and added the consteval keyword to the language to do what constexpr sounds like it's *supposed* to do.

This was a fancy algorithm which gcc executed at compile time but MSVC had a tougher time with it and bailed.

Xarn
Jun 26, 2015
FWIW you can force compile-time evaluation by using the result in a place that requires compile-time evaluation, like a static_assert. Buy yeah, without that the compiler has full liberty to just defer the evaluation, and it is (was) a feature -- the original constexpr specification was extremely limited to avoid implementation problems.

iospace
Jan 19, 2038


That Dang Lizard posted:

It could be worse, like that bug with the F-22 where all the electronics crashed when they crossed the international date line.

This is somehow not surprising to me :ughh:

JawnV6
Jul 4, 2004

So hot ...

Suspicious Dish posted:

Today I discovered that there's no guarantee for constexpr to be actually computed at compile time and MSVC will just give up and compute it at runtime if it's too hard. No way to turn that into an error afaict though.

whitelist ctors

feedmegin
Jul 30, 2008

Xarn posted:

FWIW you can force compile-time evaluation by using the result in a place that requires compile-time evaluation, like a static_assert. Buy yeah, without that the compiler has full liberty to just defer the evaluation, and it is (was) a feature -- the original constexpr specification was extremely limited to avoid implementation problems.

That sort of raises the question of what it was supposed to achieve...

Xerophyte
Mar 17, 2008

This space intentionally left blank

feedmegin posted:

That sort of raises the question of what it was supposed to achieve...

Isn't it essentially a termination checking issue? Compilers may reasonably want to avoid trying to fully evaluate arbitrary expressions that they cannot guarantee terminate at compile time, which means that either constexpr needs to be a non-Turing complete subset of the language where termination can always be validated or implementations must be able to defer evaluation when they're unsure if an expression terminates.

The MSVC implementation is apparently to speculatively evaluate the expression to some configured recursion depth and instruction count (set with /constexpr ), and defer the evaluating a constexpr to runtime if the compile time evaluation fails to terminate within those constraints. This seems pretty reasonable to me; I am not sure if clang or gcc do something fundamentally different. Doing algorithmic termination checking of C++ instead of speculative execution seems like it would be hard, even ignoring that it's in some cases fundamentally impossible.

Volte
Oct 4, 2004

woosh woosh

feedmegin posted:

That sort of raises the question of what it was supposed to achieve...
The only way this issue could come up is if you're using a constexpr function in a runtime context, which is basically the same thing as using a non-constexpr function in a runtime context. Constexpr is what allows a function to run in a compile-time context - it doesn't require it to.

xtal
Jan 9, 2011

by Fluffdaddy

Xerophyte posted:

Isn't it essentially a termination checking issue? Compilers may reasonably want to avoid trying to fully evaluate arbitrary expressions that they cannot guarantee terminate at compile time,

I don't see why this is. If I put a constant equation in that is `while (1);`, then I expect the compiler to hang forever.

Dylan16807
May 12, 2010

xtal posted:

I don't see why this is. If I put a constant equation in that is `while (1);`, then I expect the compiler to hang forever.
Most people don't want their compilers to crash or hang.
Unless I'm missing a joke.

Xerophyte posted:

constexpr needs to be a non-Turing complete subset of the language where termination can always be validated or implementations must be able to defer evaluation when they're unsure if an expression terminates
Except when you'd rather have it fail to compile so you can adjust the code.

RPATDO_LAMD
Mar 22, 2013

🐘🪠🍆

Dylan16807 posted:

Most people don't want their compilers to crash or hang.
Unless I'm missing a joke.

Except when you'd rather have it fail to compile so you can adjust the code.

In order of preference, when I write broken code (such as an infinite loop in a compile-time evaluated expression):

  1. The compiler should fail and produce a helpful error.
  2. The compiler should produce a warning
  3. The compiler should crash and burn horribly

Absolutely no where on the list is

  • The compiler should "helpfully" alter my code to do something else (such as evaluating at runtime instead)

xtal
Jan 9, 2011

by Fluffdaddy

Dylan16807 posted:

Most people don't want their compilers to crash or hang.
Unless I'm missing a joke.

When you write compile-time code that crashes or hangs, you certainly do want the compiler to crash or hang.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Ideally the compiler would give you an error instead of crashing or taking unusually long to run.

xtal
Jan 9, 2011

by Fluffdaddy

Jabor posted:

Ideally the compiler would give you an error instead of crashing or taking unusually long to run.

It's not an unusually long time if it's doing exactly what you wrote imho. The code you write is what should run. That's what we think about runtime, so why think differently for compile time?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Because I write code to actually accomplish useful tasks, not to have some moron tool developer tut-tut about how I wrote something wrong so they're going to waste my time accomplishing nothing until I manually figure out what happened.

By a similar token, I also like having automated analyses that tell me when runtime code is (or could be) problematically slow. These are good things.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Keep in mind that I'm talking about what is apparently an MSVC bug. gcc and clang successfully compile it at compile time without concern. MSVC decides that it is too complicated and unhelpfully shoves the computation to runtime. Someone else suggested using an enum instead of a constexpr variable, which actually provides the error I want.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

feedmegin posted:

That sort of raises the question of what it was supposed to achieve...

It was supposed to let you write functions which can be used in places which require constant expressions (hence "constexpr") without having to do ridiculous metaprogramming things. It does a perfectly good job of this.

This was probably not the right choice of thing to put into the language, but the intended usecase for it really isn't that weird or confusing.

Spatial
Nov 15, 2007

xtal posted:

you certainly do want the compiler to crash or hang.
It's coming from inside the thread! :v:

ToxicFrog
Apr 26, 2008


Spatial posted:

It's coming from inside the thread! :v:

As noted, while that's worse than producing an error message it's definitely better than silently emitting invalid code. IMO, silently doing the wrong thing is the worst possible failure mode for a compiler.

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!

ToxicFrog posted:

As noted, while that's worse than producing an error message it's definitely better than silently emitting invalid code. IMO, silently doing the wrong thing is the worst possible failure mode for a compiler.

Right, but in Suspicious Dish's case, it didn't emit invalid code, it just didn't do exactly what they thought it would do because the feature spec is slightly confusing.

Volte
Oct 4, 2004

woosh woosh
Just to clarify again because it seems that a lot of people misunderstand what constexpr does: it does not make code execute at compile time. It makes code able to be executed at compile time. Whether it is executed at compile-time or at runtime depends entirely on where it is called from, and not solely whether the function is marked constexpr. The compiler emitting a runtime function call when you call a function (constexpr or not) in a runtime context is not a compiler bug. At worst, it's a dropped optimization opportunity. The only way to force something to be called at compile time is to call it from a compile-time context, such as in the value of an enum or inside a static assert.

You're perfectly free to use while (1) inside a compile-time-executed constexpr and the compiler will hang forever*.

(*until it gets killed for exceeding the maximum number of steps).

code:
#include <cstdio>
#include <cstdint>
#include <cinttypes>

constexpr int64_t compute(int64_t x) {
    int64_t result = 0;
    while (result < (10000 * x)) {
        result += 1;
    }
    return result;
}

enum MyEnum: int64_t {
    foo = compute(5),
    bar = compute(10)
};

int main() {
    printf("%" PRId64 "%" PRId64 "%" PRId64 "\n", foo, bar, compute(90000000));
}
(Godbolt | -O1 -std=c++17)

Notice that the compiler emits a call to compute() for the third printf argument, but the first two are pre-computed.

Play around with the following things:
  • Change the value of the bar enum to be compute(90000000) and observe that the compiler fails because it can't do that compile-time computation in the allotted number of compile-time steps (this is basically the "desired infinite hang" case, except not ridiculously hostile to the user or impossible to debug).
  • Change -O1 to -O2 and observe that it actually does not emit a call compute() at all and in fact pre-computes the very same value that failed above. So even though you can't force it to be computed at compile-time, it is allowed to do so as an optimization, even if doing so would exceed the limit for doing it in a compile-time context. This is probably the behaviour that's being described as "the compiler gave up and computed it at runtime instead".
In short, if you really need something to be computed at compile-time and not just as an optimization, evaluate it in a context that cannot be computed at runtime. Otherwise, the compiler is free to emit function calls as it sees fit.

edit: whoops should have used PRId64 instead of PRIu64 but I'm too lazy to update the godbolt link

Volte fucked around with this message at 15:05 on Mar 25, 2019

Xarn
Jun 26, 2015
It is important to remember that the compiler has to interpret the C++ code for constexpr contexts, which is a lot slower than compiling it into something sane and then running that, which is why it is allowed to defer to runtime if the compilation would take too long and the result is only needed at runtime.

Volte
Oct 4, 2004

woosh woosh

Xarn posted:

It is important to remember that the compiler has to interpret the C++ code for constexpr contexts, which is a lot slower than compiling it into something sane and then running that, which is why it is allowed to defer to runtime if the compilation would take too long and the result is only needed at runtime.
This is also true -- the reason it can pre-compute the value as an optimization in my example is because it can detect the loop construct and replace it with a multiplication, which is trivially computable at compile time. It can't do that if it's evaluating it in a compile-time context, though I don't actually know if the standard disallows doing that sort of optimization before attempting compile-time evaluation, or if it's just not something that's implemented. I guess it's best to make sure that compile-time behaviour (i.e. whether it compiles or not) doesn't depend on internal compiler optimization abilities so that different compilers don't reject the same code because of implementation details.

Volte fucked around with this message at 15:45 on Mar 25, 2019

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
At -O2, the compiler's optimizer is probably just discovering the closed-form solution for that loop either before or after inlining it.

Volte
Oct 4, 2004

woosh woosh

rjmccall posted:

At -O2, the compiler's optimizer is probably just discovering the closed-form solution for that loop either before or after inlining it.
Indeed - the point being that just because something can be done at compile-time doesn't mean that adding constexpr is going to force it to happen, or that not adding constexpr is going to force it not to happen.

Jazerus
May 24, 2011


Plorkyeran posted:

It was supposed to let you write functions which can be used in places which require constant expressions (hence "constexpr") without having to do ridiculous metaprogramming things. It does a perfectly good job of this.

This was probably not the right choice of thing to put into the language, but the intended usecase for it really isn't that weird or confusing.

C++: This was probably not the right choice of thing to put into the language

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

Volte posted:

Indeed - the point being that just because something can be done at compile-time doesn't mean that adding constexpr is going to force it to happen, or that not adding constexpr is going to force it not to happen.

I find this kind of thing annoying. Compilers these days use a lot of heuristics, and while they're quite good, heuristics by their nature can't account for every possible situation. That's why it's nice when you can override the heuristic and force the compiler to do something when you really need it to. The problem I find is that while c++ often appears to give you this kind of control (such as with inline or constexpr), the reality is you're just providing hints and hoping the compiler guesses correctly.

JawnV6
Jul 4, 2004

So hot ...

RPATDO_LAMD posted:

In order of preference, when I write broken code (such as an infinite loop in a compile-time evaluated expression):

  1. The compiler should fail and produce a helpful error.
  2. The compiler should produce a warning
  3. The compiler should crash and burn horribly

Absolutely no where on the list is

  • The compiler should "helpfully" alter my code to do something else (such as evaluating at runtime instead)
oh gosh are u gonna be mad

Dylan16807
May 12, 2010

xtal posted:

It's not an unusually long time if it's doing exactly what you wrote imho. The code you write is what should run. That's what we think about runtime, so why think differently for compile time?
If it's runtime code you might be depending on the side effects of hanging. Also compilers can and do optimize away infinite do-nothing loops, so it's not reliable without an external call or volatile.

At compile time that purpose goes away and there's no reason to hang.

Xerophyte
Mar 17, 2008

This space intentionally left blank
Sure, I think everyone would love it if the compiler always gave an error for invalid compile-time expressions and always accepted valid ones. The problem is that a compiler cannot know that an expression will terminate without solving the halting problem. Since it definitely can't solve the halting problem the compiler has to do at least one of:
1. Sometimes hang indefinitely while it waits for your ill-formed expression to maybe hopefully terminate.
2. Sometimes reject well-formed expressions that it cannot successfully determine will terminate.
3. Reduce the generality of constant expressions so they're in some incomplete subset of the language where expressions are guaranteed to always terminate.

C++ went with 2, and a requirement in the standard for core constant expressions is that they will not "exceed the implementation-defined limits" which seems fine to me since the alternatives are worse. There's additionally the question to do when the compile time evaluation fails.

constexpr took the view that it is there to help you write better code, not guarantee evaluation. It's like const: it makes the typechecker more restrictive to stop you from doing things that have side effects. constexpr functions may still be emitted into the binary, may be used on variables, and marking appropriate pre-existing code as constexpr will not change the result of your program.

consteval instead gives a hard guarantee that "every call to the function must produce a compile-time constant". consteval functions may never be called with variables as parameters, and allow compilers to fail on well-formed code if it's over some implementation-specific complexity level.

Both of these are mildly annoying. I'd think there could have been some way of forcing a constexpr call to be evaluated at compile time or fail, rather than adding consteval and its very strict no-variables-ever policy, but since it's C++ I am probably missing some fun other corner case.

Athas
Aug 6, 2007

fuck that joker

Xerophyte posted:

Sure, I think everyone would love it if the compiler always gave an error for invalid compile-time expressions and always accepted valid ones. The problem is that a compiler cannot know that an expression will terminate without solving the halting problem.

Well now! Assuming it is possible to statically check that a C++ expression does not have side effects, then solving the halting problem is not necessary. As far as I know, the pure subset of C is Turing-incomplete for pedantic reasons, because it requires all objects to be uniquely identifiable with a finitely-sized integer (everything must potentially have an address), and so the total number of objects that can exist at once is limited. Unless C++ changed some of these details, I believe the same restriction must apply. The restriction to pure expressions is that I'm not sure if you can use the file system functions to access potentially unbounded storage. Anyway, this would imply that pure C++ expressions embody a linear bounded automaton, not a full Turing machine, and you can verify termination of an LBA simply by tracking all intermediate evaluation states and constantly checking whether you've reached a state you've seen before. Clearly this was the intended implementation strategy.

TheresaJayne
Jul 1, 2011
of course going back to the date thing, the islamic calendar is simple 30,29,30,29,30,29,30,29,30,29,30,29

NtotheTC
Dec 31, 2007


Why don't we just push the earth towards the sun a tiny bit so we get 360 days a year? Then this problem goes away.

Ola
Jul 19, 2004

NtotheTC posted:

Why don't we just push the earth towards the sun a tiny bit so we get 360 days a year? Then this problem goes away.

360 official days, plus 5.2422 days of planned downtime.

Happy Thread
Jul 10, 2005

by Fluffdaddy
Plaster Town Cop

Phobeste
Apr 9, 2006

never, like, count out Touchdown Tom, man
Cursed

Jazerus
May 24, 2011


huh elon's program crashed

weird

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer
r/fellowdevelopers

Adbot
ADBOT LOVES YOU

Soricidus
Oct 21, 2010
freedom-hating statist shill
while (firetruck.isVisible()) speed++;

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply