3 days ago
On Thursday, 25 May 2023 at 10:35:45 UTC, Quirin Schroll wrote:
> On Wednesday, 24 May 2023 at 23:04:53 UTC, Cecil Ward wrote:
>> [...]
>
> I had this almost happen in my C++ code. It never ran because I got a compile error. The compiler is MSVC.
>
> [...]

I like your ‘quick sketch’. Now how do we recruit a volunteer? Since unfortunately, I am not up to the task having zero experience and various other problems.
3 days ago
On Thursday, 25 May 2023 at 13:46:32 UTC, Cecil Ward wrote:
> On Thursday, 25 May 2023 at 10:35:45 UTC, Quirin Schroll wrote:
>> On Wednesday, 24 May 2023 at 23:04:53 UTC, Cecil Ward wrote:
>>> [...]
>>
>> I had this almost happen in my C++ code. It never ran because I got a compile error. The compiler is MSVC.
>>
>> [...]
>
> My apologies, when I wrote ‘straightforward’ I should meant to say, ‘without body, with no content’. You mentioned without side-effects, which is more general and very useful.

We would have to add something in your quick sketch to mention exceptions. So if the basic block is not null, a type of check that I would settle for as a first step, in addition to your conditions all calls would have to be nothrow if there is an exception handler.

I don’t know what the D call is to terminate the current process, or even begin the shutdown sequence for the system if we are building an embedded system with (other) no o/s. But I should think that a routine having an attribute of ‘terminate the process’, when the reason isn’t  because we mean ‘panic’, core_dump, ud_n, etc because of a bug, but because we simply want to terminate the process because we’re all done, with success or failure, means that it is not pure.

In GCC there is a noreturn attribute iirc - is that correct? but I think that there ought to be subtypes of that - to say whether it’s debug code or not, whether it’s a straight ‘end if process’ rather than a panic / bug / core_dump etc. (Does GCC or LDC generate a ud2 when you wish to panic? Presumably without cleanup?)

Merely having an exception handler present above or around your non-trivial infinite loop might be a sign that you have something equivalent to a break inside the loop. But I don’t think we should consider this, as there may actually be no exception throwing at all, and that could be a bug - that the way out has been omitted.

Anyway, it would be easier to do the "L1: jmp L1" thing first as then there are no worries, and we would get some benefit much sooner.
3 days ago
On 5/24/23 16:04, Cecil Ward wrote:

> Is it possible for our compilers to detect direct infinite recursion ?

I agree the compiler can detect some cases. However, a diagnostic may not be what the programmer wants in all cases.

I am writing on this topic because I've recently been pleasantly surprised how dmd lets me inject assert(false) expressions during development:

void foo() {
  someCode();

  assert(false, "some information");

  moreCode();
}

I am a printf-style programmer, where I use such asserts as well.

I *think* the compiler used to complain about that in earlier versions (or maybe I remember compilers of earlier languages like C++?); the compiler would say "unreachable code".

I am thankful that dmd allows me do it during development and debugging.

So, your case may fall into this category where although it doesn't make sense, a programmer may have caused it intentionally.

Ali

3 days ago
On Wednesday, 24 May 2023 at 23:04:53 UTC, Cecil Ward wrote:
> Due to some stupidity of mine involving misuse of templates I ended up with a routine that simply called itself infinitely. Directly, that is, and in this case the routine was optimised down into a simple infinite loop with no loop body content.
>
> Is it possible for our compilers to detect direct infinite recursion ? I’m ignoring the indirect call case, and I’m also ignoring anything involving function pointers, so given those restrictions, we will be able to see that the generated code of a routine is calling its own address, because that address is a literal and we know what the current function is that we’re currently in.
>
> And while we’re at it, is it possible to detect all kinds of straightforward infinite loops (not coming from recursion)? That is where the generated code, perhaps as a result of optimisation, is a straight loop with no body. Can we implement that?
>
> It ought to be possible because the backend can spot a pattern like "L1:  jmp  L1".
>
> I promise I’m not trying to solve the Halting Problem :)
>
> Cecil Ward.

Is it a nightmare to get template generation to detect a call-to-self, one line function (‘direct’ recursion bar the mangling)? My stupidity was trying to ‘forward’ a call to a particular template specialisation on to the routine for the general case, and getting it all wrong. I wouldn’t want to make more work compared to the L1: jmp L1 case, but if anyone did feel like doing a check at template instantiation-related code emission time then a very nice specific and meaningful message could be output. Indeed there are some very worthwhile diagnostic longwinded template-related error messages already when someone has an error relating to multiple possible template expansion possibilities. (What is that called, that I’m thinking of?)
3 days ago
On Thursday, 25 May 2023 at 15:56:43 UTC, Cecil Ward wrote:
> [...]

Typo: s/template generation/template expansion/
3 days ago

On Thursday, 25 May 2023 at 15:51:15 UTC, Ali Çehreli wrote:

>

On 5/24/23 16:04, Cecil Ward wrote:

>

Is it possible for our compilers to detect direct infinite
recursion?

I agree the compiler can detect some cases. However, a diagnostic may not be what the programmer wants in all cases.

I am writing on this topic because I've recently been pleasantly surprised how dmd lets me inject assert(false) expressions during development:

void foo() {
  someCode();

  assert(false, "some information");

  moreCode();
}

I am a printf-style programmer, where I use such asserts as well.

I think the compiler used to complain about that in earlier versions (or maybe I remember compilers of earlier languages like C++?); the compiler would say "unreachable code".

I am thankful that dmd allows me do it during development and debugging.

So, your case may fall into this category where although it doesn't make sense, a programmer may have caused it intentionally.

I just tried what DMD does with

for (ubyte i = 0; i < 256u; ++i) { ... }

It doesn’t care that i < 256 is trivially true (by type). GCC and Clang give me:

warning: comparison is always true due to limited range of data type (GCC)
warning: result of comparison of constant 256 with expression of type 'unsigned char' is always true (Clang)

(For the record, in C++, this is platform dependent; there’s no guarantee by the language that unsigned char is only 8-bit.)

An assert(false) leading to dead code is indeed similar, but also different from an infinite loop/recursion. This is opinionated: assert(false) is placed with intention; it’s a good question if (or under which circumstances) dead code should be an error; dead code is dubious and in a release build or otherwise optimized build, in non-template code, I’d probably like the compiler telling me about it. An infinite loop/recursion without observable effects is almost certainly not intentional and something is wrong: The condition is wrong or the body doesn’t affect the condition as intended. Even in a debug build, it would be valuable to have the info. There could be 3 degrees of diagnostic:

  1. In a debug build, an infinite loop/recursion, if detected, produces a warning. One big reason for this is that in debug mode, pure functions can actually have observable effects.
  2. In a regular (non-debug, non-release, non-optimized) build, an infinite loop/recursion by syntax (something like while(1){} or int f(int x) => f(x) and a little less basic examples) are errors (because they’re obviously wrong and should be detected by any compiler) and infinite loop/recursion by (deep) semantic analysis gets a warning.
  3. In optimized/release, any detected infinite loop/recursion is an error.

Of course, by infinite loop/recursion, I mean those without observable effects, but “infinite loop/recursion” is wordy enough. A read–eval–print loop is perfectly fine. I might add that pure is not enough. Throwing an exception can break a loop, so nothrow is required as well for all the operations in question.

3 days ago

On Thursday, 25 May 2023 at 15:51:15 UTC, Ali Çehreli wrote:

>

I think the compiler used to complain about that in earlier versions (or maybe I remember compilers of earlier languages like C++?); the compiler would say "unreachable code".

It still does, though it requires the -w flag to enable warnings.

1 2
Next ›   Last »