Issue 6169 - [CTFE] pure functions cannot compute constants using functions not marked as pure #652

Merged
merged 1 commit into from May 4, 2013

Projects

None yet

3 participants

@yebblies
D Programming Language member

When running semantic on an expression used anywhere that forces compile time evaluation, use a scope flag to prevent purity and safety checks on function calls.
This allows more functions to be inferred @safe/pure.

http://d.puremagic.com/issues/show_bug.cgi?id=6169

@donc

There's a huge similarity between this bug, and the gagging that occurs in speculative template instantiation (bug 4269, for example, which I'm currently working on). In both cases, semantic is run in a different mode, and a certain subset of errors need to be suppressed/ignored. I think they can both be treated in the same way.

@yebblies
D Programming Language member

Yeah, this is a new type of gagging (eek) but as it can't leak outside expressions there hopefully won't be too many problems with it. The only ways I could think of for solving 4269 is to make semantic completely reversible for declarations or to suspend gagging when evaulating non-speculative declarations. The first options requires lots of work and has hundreds of corner cases, and the second doesn't work inside speculative declarations... I'll be interested to see your solution.

@donc

I'm taking the second approach: ungag if non-speculative, when semantic is called from a speculative context.

@yebblies
D Programming Language member

Ok, but I don't know how this will work for declarations that must be evaluated speculatively - basically anything can be inside a template declaration, and unless semantic can be re-run how can the errors be detected later?
eg

template Templ(T)
{
    static assert(is(T == int));
    int fun() {}
}
static assert(!__traits(compiles, Templ!(long).fun()));
enum x = Templ!(long).fun(); // semantic has already failed

The issue here isn't that semantic is being run gagged when it shouldn't be, it's that to generate the correct errors semantic has to be run again.

@donc

Yeah, I dealt with that in a previous pull request. TemplateInstance has a member for speculative errors. If an error occurs, that counter gets updated. But it currently only applies to errors inside function bodies. It needs to be extended to work on other declarations.

@yebblies
D Programming Language member

Won't that result in a generic 'errors instantiating' message rather than the specifics? I guess it would change this bug from accepts-invalid to a massive diagnostic problem.

@donc

No. If there are semantic speculative errors, and a non-speculative instantiation is requested, the existing instantiation is discarded.
Code from TemplateInstance::semantic()

   // If both this and the previous instantiation were speculative,
    // use the number of errors that happened last time.
    if (inst->speculative && global.gag)
    {
        global.errors += inst->errors;
        global.gaggedErrors += inst->errors;
    }

    // If the first instantiation was speculative, but this is not:
    if (inst->speculative && !global.gag)
    {
        // If the first instantiation had failed, re-run semantic,
        // so that error messages are shown.
        if (inst->errors)
            goto L1;
        // It had succeeded, mark it is a non-speculative instantiation,
        // and reuse it.
        inst->speculative = 0;
    }
@yebblies
D Programming Language member

Updated to match Don's recent ctfeInterpret changes.

There is one change: Runtime values in case statements are no longer allowed.

@donc

There is one change: Runtime values in case statements are no longer allowed.

Please undo that. Although I would love for that to happen, it's a language change so it needs to be in its own pull request.

@yebblies
D Programming Language member

Ok, I'll leave the original behavior for case variables.

@yebblies
D Programming Language member

Done.

@andralex
D Programming Language member

OK to assign @donc to this? Please advise. I'm uneasy about two things: (a) inferring pure for regular functions makes for a big difference when compiling things separately vs. not. Not sure how bad that is. (b) disallowing runtime values for switch breaks code. This is a big one. Thoughts?

@donc donc was assigned Sep 25, 2012
@donc

The "disallowing runtime values" was removed from the pull request as part of the "restore case variables" commit.
The "inferring pure" part doesn't make a difference for separate compilation, it's simply the fact that whenever any compile-time constant is used, it is never impure, even if it was created by CTFE. If you know an expression is a compile-time literal, you don't need to analyze it further.

@yebblies
D Programming Language member

@andralex
a) This allows more functions to be inferred as pure by excluding ctfe expressions from checks, as nothing run at compile time can break run-time purity and safety. It does not change the circumstances is which a function has purity inference run on it.
b) While I hate case variables with a passion, they are no longer removed by this pull request. I've updated the description to reflect that.

@yebblies
D Programming Language member

Updated.

@yebblies
D Programming Language member

Updated again.

@yebblies yebblies Fix Issue 6169 - [CTFE] pure functions cannot compute constants using…
… functions not marked as pure

When running semantic on an expression used anywhere that forces compile time evaluation, use a scope flag to prevent purity and safety checks on function calls.
This allows better purity/safety inferrence as well.
42d1af1
@donc donc merged commit 15a5783 into dlang:master May 4, 2013

1 check was pending

Details default Pass: 9, Pending: 1
@yebblies yebblies deleted the yebblies:issue6169 branch Nov 22, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment