This is an archive of the discontinued LLVM Phabricator instance.

[FileCheck] Fix numeric error propagation
ClosedPublic

Authored by jdenny on Mar 5 2021, 3:48 PM.

Details

Summary

A more general name might be match-time error propagation. That is,
it's conceivable we'll one day have non-numeric errors that require
the handling fixed by this patch.

Without this patch, FileCheck behaves as follows:

$ cat check
CHECK-NOT: [[#0x8000000000000000+0x8000000000000000]]

$ FileCheck -vv -dump-input=never check < input
check:1:54: remark: implicit EOF: expected string found in input
CHECK-NOT: [[#0x8000000000000000+0x8000000000000000]]
                                                     ^
<stdin>:2:1: note: found here

^
check:1:15: error: unable to substitute variable or numeric expression: overflow error
CHECK-NOT: [[#0x8000000000000000+0x8000000000000000]]
              ^
$ echo $?
0

Notice that the exit status is 0 even though there's an error.
Moreover, FileCheck doesn't print the error diagnostic unless both
-dump-input=never and -vv are specified.

The same problem occurs when CHECK-NOT does have a match but a
capture fails due to overflow: exit status is 0, and no diagnostic is
printed unless both -dump-input=never and -vv are specified. The
usefulness of capturing from CHECK-NOT is questionable, but this
case should certainly produce an error.

With this patch, FileCheck always includes the error diagnostic and
has non-zero exit status for the above examples. It's conceivable
that this change will cause some existing tests to fail, but my
assumption is that they should fail. Moreover, with nearly every
project enabled, this patch didn't produce additional check-all
failures for me.

This patch also extends input dumps to include such numeric error
diagnostics for both expected and excluded patterns.

As noted in fixmes in some of the tests added by this patch, this
patch worsens an existing issue with redundant diagnostics. I'll fix
that bug in a subsequent patch.

Diff Detail

Event Timeline

jdenny created this revision.Mar 5 2021, 3:48 PM
jdenny requested review of this revision.Mar 5 2021, 3:48 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 5 2021, 3:48 PM
jdenny added a comment.Mar 6 2021, 4:27 AM

This patch also extends input dumps to include similar error
diagnostics.

I realize now that the wording in this patch isn't general enough: it handles not only pattern errors but also overflow errors due to large values in the input. I should extend the tests accordingly. So far, I believe the logic in this patch is correct.

jdenny planned changes to this revision.Mar 6 2021, 5:28 AM

Actually, I do need to rethink the logic for that overflow case: PrintNoMatch is being called after a match, so its diagnostics don't make sense in that case. Sorry for the noise. I'll work on it.

jdenny updated this revision to Diff 328891.Mar 7 2021, 12:28 PM
jdenny retitled this revision from [FileCheck] Fix CHECK-NOT numeric error diagnostics to [FileCheck] Fix numeric error propagation.
jdenny edited the summary of this revision. (Show Details)

I've generalized this patch to also handle errors that occur after matching. One issue is that PrintNoMatch was handling those, but I moved the handling to PrintMatch so that we actually report the full match that was found. That seems like useful information and helps with -dump-input.

Also, I started renaming functions I modified significantly to follow the current LLVM style: printNoMatch and printMatch. I knows some LLVM projects update style incrementally like this. I forget if we decided to do that in FileCheck, but I'm happy to revert that part if people don't want to.

thopre added a comment.Mar 8 2021, 7:03 AM

I like the idea behind it. I suppose that's what you had in mind when you wrote your comments in https://reviews.llvm.org/D86222. It should make that patch a lot simpler. Thanks and sorry I didn't progress faster on that one.

llvm/include/llvm/FileCheck/FileCheck.h
137–141

May I suggest making it clear that this error is despite the match being successful? It was not obvious to me until I read the rest of the patch.

llvm/lib/FileCheck/FileCheck.cpp
1194–1199

Nit

2091–2120

Why the reordering of MatchError(s)?

2434–2441

Shouldn't we delegate to printMatch to check for Req.VerboseVerbose?

2491–2492

Likewise.

llvm/lib/FileCheck/FileCheckImpl.h
701–713

Move below above MatchResult.

715–716
jdenny added a comment.Mar 9 2021, 6:01 PM

I like the idea behind it. I suppose that's what you had in mind when you wrote your comments in https://reviews.llvm.org/D86222. It should make that patch a lot simpler.

Wow. That patch was clearly lurking in my subconscious, but my conscious mind had forgotten it. I even replicated the PrintNoMatch -> printNoMatch change! I did notice a strange feeling of deja vu while I was working on the patch.

Thanks and sorry I didn't progress faster on that one.

No worries, and thanks for the reminder. If there are ideas in that patch that belong here, please let me know.

I've replied to some comments, and I'll work on the others later.

llvm/include/llvm/FileCheck/FileCheck.h
137–141

Does the following wording help?

"Indicates an error while processing a match after it was found for an expected or excluded pattern."

I'm hesitant to use the word success because (1) there's an error and (2) matching is an error anyway if the pattern is excluded.

llvm/lib/FileCheck/FileCheck.cpp
2091–2120

I was going for symmetry with printMatch, for which any error is included in the MatchResult parameter in that position. To say it another way, that position holds the "result" in both cases. If that doesn't look good to you, I'm fine to revert.

2434–2441

There are two printMatch calls in this function. The first triggers on (an error or) Req.VerboseVerbose, which reports CHECK-DAG discarded matches. The second triggers on !Req.VerboseVerbose to be sure the final CHECK-DAG match is reported when discarded matches aren't shown. We'd have to tell printMatch which case this is, but it seems easier just to keep that logic in the caller.

I'm open to changing it, but what I'm imagining doesn't seem as clean.

llvm/lib/FileCheck/FileCheckImpl.h
701–713

Thanks for catching that.

Actually, this comment is left over from a previous attempt and is now wrong in either place. That is, in the case of an error, MatchResult might not have a match.

The comment preceding match below says it better. What if we just drop the above comment?

thopre added inline comments.Mar 10 2021, 3:53 AM
llvm/include/llvm/FileCheck/FileCheck.h
137–141

Sure, LGTM.

llvm/lib/FileCheck/FileCheck.cpp
2091–2120

Ah no that's fine, I like symmetry. It just felt like a spurious change but I'm happy with the motivation.

2434–2441

Ah sorry, I missed the negation in the second call. Nevermind then

llvm/lib/FileCheck/FileCheckImpl.h
701–713

I'm fine with that. After all the structure is fairly self explanatory (Optional match, an error which we know can be success and it's named MatchResult)

llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
14

Did you intend to have two undefined variables (UNDEF and VAR)? Why not just UNDEFVAR? I don't think the parser looks anything after the minus sign.

llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt
10

Same as for CHECK-NOT testcase: UNDEFVAR

llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
11–19

FYI I'd like to make a patch to use APInt in FileCheck to allow numbers bigger than 64bits. I've found the need while working on __builtin_isnan for long double. No timeline and I don't expect to have time on it soon but that would remove the only post-match error unless a new one is added before that. On the other hand I haven't even started that work so I think this testcase should be kept.

jdenny updated this revision to Diff 329749.Mar 10 2021, 12:57 PM
jdenny marked 13 inline comments as done.

Applied @thopre's suggestions.

jdenny added inline comments.Mar 10 2021, 1:00 PM
llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
14

Good catch. I was trying to hyphenate. I'll go with UNDEFVAR.

(BTW, the parser doesn't complain when UNDEF is defined. It just ignores -VAR. We should fix that.)

llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
11–19

Thanks for mentioning it. Inequality constraints will fit here, right? If so, hopefully they'll come first so it's easy to maintain this handling.

jdenny added inline comments.Mar 10 2021, 1:09 PM
llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
11–19

Actually, based on the way == works, I suppose not.

thopre accepted this revision.Mar 10 2021, 1:09 PM

LGTM but maybe you want feedback from James, though he appears very busy

llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
11–19

Inequality will need code needed for using a variable defined on the same line: the ability of tentatively match a line, set variables etc. and discard if a constraint is not met. I have an old patch that does it but I wanted something more automatic (i.e. require a transaction object to perform a match with a commit method and the destructor would delete everything unless committed. That's the general idea but everytime I try to compartmentalize FileCheck more (e.g. creating a numeric expression parser object) I get into an encapsulation hell with info I need but not easily available. Sorry for renting

Anyway, perhaps it's time for me to get back to the use of var defined on the same line and get closure on that FileCheck numeric expression patchset.

This revision is now accepted and ready to land.Mar 10 2021, 1:09 PM
thopre added inline comments.Mar 10 2021, 1:11 PM
llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
14

Ouch. Could you create a bug and subscribe me?

jdenny marked an inline comment as done.Mar 10 2021, 5:18 PM
jdenny added inline comments.
llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
11–19

I agree that FileCheck internals could benefit from some refactoring.

I now see three potential uses cases for these after-match errors (represented by MatchFoundErrorNote and reported by printMatch in this patch):

  1. FileCheck internal limitations: the pattern matches as specified but FileCheck cannot handle it. The only limitation right now is overflow/underflow, but that could be eliminated in the future, as you have pointed out.
  1. A user-visible two-stage check of a directive's constraints: instead of searching for a match that satisfies all constraints of the directive, it searches for a match that satisfies only some constraints and then fails if the remaining constraints aren't satisfied by that match. This would be confusing in ways we've discussed before. For example, we once discussed doing this for a variable captured and later used in an expression within the same directive. Given the input 1 0 2, the following directive would then fail (0 isn't 1 + 1), but it seems better for it to succeed because, intuitively, the pattern should match (2 is 1 + 1):

    CHECK: [[%u,X:]] {{.*}} [[%u,X+1]]

    It's especially confusing how CHECK-NOT should then behave: with the current error handling in this patch, CHECK-NOT would also fail on a match not satisfying the remaining constraints. Is that really the meaning of CHECK-NOT? So, use case 2 seems wrong, and your comments suggest you're not planning to pursue it for this example. From the user's view, it will then seem like one stage.
  1. What about division by zero for a variable captured and used in the same directive? For example, given the input 0 / 0 = 0, should the following produce an after-match error, or should FileCheck keep looking for another match?

    CHECK: [[#%u,X:]] / [[#%u,Y:]] = [[%u:X/Y]]

    What should CHECK-NOT do? It seems to me FileCheck should fail in both cases because it cannot compute what should actually match. What do you think?
jdenny marked an inline comment as done.Mar 10 2021, 5:44 PM
jdenny added inline comments.
llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
14

LGTM but maybe you want feedback from James, though he appears very busy

Yes, sorry, been busy. I was off sick much of last week, and am participating in the ACCU conference most of this week. I'll try to find time to look at this next week, if you want my input, but there's no need to wait on me otherwise.

jdenny marked an inline comment as done.Mar 11 2021, 4:05 PM

Yes, sorry, been busy. I was off sick much of last week, and am participating in the ACCU conference most of this week. I'll try to find time to look at this next week, if you want my input, but there's no need to wait on me otherwise.

Glad you're better! I'd be happy to have your input. I'll wait a week or so in case you have time. Of course, post-commit reviews are fine too.

I've run out of steam as I started looking at this, partly because I'm getting hung up on the bool return indicating some kind of errors. This is to me a significant design smell, and I'd prefer a different approach, although I haven't got any concrete suggestions.

llvm/lib/FileCheck/FileCheck.cpp
1376

Aside: this is a good example of where auto is hurting readability of the code. I can't tell whether VariableDef is an Optional, or something else with a getValue() method below. If it's the former, you could replace getValue() with -> for example.

2012

I'm really not a fan of bool return types to indicate an error. Does true indicate an error or false, for example? There's also nothing enforcing that the error is checked (see my "Error handling in libraries" lightning talk from LLVM Dev 2018 for more).

2141

StringRef?

2240

A good example of my concern above: printNoMatch returns a bool, but you do nothing with it here. Should you? If not, why not?

jdenny updated this revision to Diff 330758.Mar 15 2021, 12:17 PM
jdenny marked 3 inline comments as done.

Address @jhenderson's review.

printMatch and printNoMatch now return either ErrorSuccess or ErrorReported, which is a new class so that these functions can inform their callers that some error has occurred but has already been reported. In most cases, I've wrapped the printMatch and printNoMatch calls in reportMatchResult, which cleans up the callers.

llvm/lib/FileCheck/FileCheck.cpp
1376

Perhaps we need a patch that adjusts all such occurrences in this file.

jhenderson accepted this revision.Mar 17 2021, 2:16 AM

I've gone through the code and briefly skimmed the tests. I need to focus on clearing other reviews, so won't spend more time on this, and I didn't see any further problems, so LGTM.

llvm/lib/FileCheck/FileCheck.cpp
1376

+1 to that suggestion.

Thanks for the review. I'm rebasing and retesting, and then I'll push.

This revision was automatically updated to reflect the committed changes.