This is an archive of the discontinued LLVM Phabricator instance.

[clang] Suppress "follow-up" diagnostics on recovery call expressions.
ClosedPublic

Authored by hokein on Oct 22 2020, 3:40 AM.

Details

Summary

Because of typo-correction, the AST can be transformed, and the transformed
AST is marginally useful for diagnostics purpose, the following
diagnostics usually do harm than good (easily cause confusions).

Given the following code:

void abcc();
void test() {
  if (abc());
  // diagnostic 1 (for the typo-correction): the typo is correct to `abcc()`, so the code is treate as `if (abcc())` in AST perspective;
  // diagnostic 2 (for mismatch type): we perform an type-analysis on `if`, discover the type is not match
}

The secondary diagnostic "convertable to bool" is likely bogus to users.

The idea is to use RecoveryExpr (clang's dependent mechanism) to preserve the
recovery behavior but suppress all follow-up diagnostics.

Diff Detail

Event Timeline

hokein created this revision.Oct 22 2020, 3:40 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 22 2020, 3:40 AM
hokein requested review of this revision.Oct 22 2020, 3:40 AM
hokein added inline comments.Oct 22 2020, 3:46 AM
clang/test/Modules/submodules-merge-defs.cpp
21 ↗(On Diff #299916)

this (and the case below) are slight regressions, but I think the following diagnostics are not a big deal.

Cool, this makes sense to me. I hadn't realized this doesn't go through typoexpr, that's a bit unfortunate we can't address this just in one place.

This is a change of behavior with recoveryAST off, but this change basically only affects C++ so that's not a widely-used configuration.

I think the resulting AST is better as the errors there are visible.
Can we have a test specifically of the shape of the AST produced?

clang/lib/Sema/SemaOverload.cpp
12737–12738

while here, drop the stale "returns true" bit? The return type covers the contract well enough IMO

12794

nit: now member call -> member access as we never really go on to build a member call

12808–12809

comment is now out of date.

12808–12809

This results in (IIUC):

CallExpr
>RecoveryExpr (indirection we inserted)
>>DeclRefExpr (callee)
>Arg1

Whereas when overload resolution fails, we create:

RecoveryExpr (call)
> OverloadExpr (callee)
> Arg1

I can see advantages for either, but is there a reason not to be consistent?
(Which I guess means emitting the first one here)

12809

This seems a bit abrupt (because it's not obvious what the previous code is doing I guess).

Maybe

"We now have recovered a callee. However, building a real call may lead to incorrect
secondary diagnostics if our recovery wasn't correct.
We keep the recovery diagnostics and AST but suppress following diagnostics by
using RecoveryExpr"

12814

I think giving the variable a new name here would be clearer

clang/test/Modules/submodules-merge-defs.cpp
21 ↗(On Diff #299916)

I agree, the secondary diagnostics aren't wrong but I don't think they're necessary either.

hokein updated this revision to Diff 300187.Oct 23 2020, 1:00 AM
hokein marked 4 inline comments as done.

address comments and add AST tests.

clang/lib/Sema/SemaOverload.cpp
12808–12809

(Which I guess means emitting the first one here)

yes, exactly.

reasons:

  • BuildCallExpr could emit diagnostics if we pass a non-dependent callee to it, this is something we want to avoid;
  • we'd save some cost -- BuildCallExpr has dedicated code path to handle dependent expr;
sammccall added inline comments.Oct 23 2020, 1:30 AM
clang/lib/Sema/SemaOverload.cpp
12808–12809

Sorry, I meant emitting the second one here. (Or changing the callexpr recovery to use the first form, but that's a larger patch).

I understand we save some code, but not very much (the second form is easy to produce), and we produce quite different ASTs for essentially the same pattern (the only difference is whether we attempted recovery or not). This doesn't seem like a good trade...

hokein updated this revision to Diff 300590.Oct 26 2020, 1:06 AM
hokein marked an inline comment as done.

address comment.

clang/lib/Sema/SemaOverload.cpp
12808–12809

Changed to the second form for consistency. And it doesn't break any existing tests (neither improvements nor regressions).

sammccall accepted this revision.Oct 26 2020, 1:42 AM

Thanks! LG with comment nit

clang/lib/Sema/SemaOverload.cpp
12818

is it a deliberate decision to drop the return type of the recovery function here too? If so, mention it in the comment (currentyl you only talk about not preserving the real call node)

clang/test/AST/ast-dump-recovery.cpp
277

(so this could be void. It will still trigger some follow-on diagnostics though)

clang/test/SemaCXX/typo-correction-delayed.cpp
216

nit: convertible

This revision is now accepted and ready to land.Oct 26 2020, 1:42 AM
hokein updated this revision to Diff 300601.Oct 26 2020, 2:24 AM
hokein marked an inline comment as done.

address comments.

clang/lib/Sema/SemaOverload.cpp
12818

yes, we deliberately use a dependent-type for recovery-expr to suppress diagnostics (rely on clang's dependent mechanism).

clang/test/AST/ast-dump-recovery.cpp
277

As described in the previous comment, the type should always be dependent.

This revision was landed with ongoing or failed builds.Oct 26 2020, 4:45 AM
This revision was automatically updated to reflect the committed changes.

Still LG thank you!