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

This reverts commit efa9aaad70 and adds a
crash test.

The commit caused a crash in CodeGen with -fms-compatibility, see
https://bugs.llvm.org/show_bug.cgi?id=48690.
This commit is contained in:
Haojian Wu 2021-01-22 12:15:05 +01:00
parent def99ad68b
commit d972d4c749
4 changed files with 22 additions and 34 deletions

View File

@ -12923,7 +12923,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
}
// Build an implicit member access expression if appropriate. Just drop the
// Build an implicit member call if appropriate. Just drop the
// casts and such from the call, we don't really care.
ExprResult NewFn = ExprError();
if ((*R.begin())->isCXXClassMember())
@ -12938,19 +12938,12 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
if (NewFn.isInvalid())
return ExprError();
auto CallE =
SemaRef.BuildCallExpr(/*Scope*/ nullptr, NewFn.get(), LParenLoc,
MultiExprArg(Args.data(), Args.size()), RParenLoc);
if (CallE.isInvalid())
return ExprError();
// 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 behavior but suppress all following diagnostics by
// using RecoveryExpr. We deliberately drop the return type of the recovery
// function, and rely on clang's dependent mechanism to suppress following
// diagnostics.
return SemaRef.CreateRecoveryExpr(CallE.get()->getBeginLoc(),
CallE.get()->getEndLoc(), {CallE.get()});
// This shouldn't cause an infinite loop because we're giving it
// an expression with viable lookup results, which should never
// end up here.
return SemaRef.BuildCallExpr(/*Scope*/ nullptr, NewFn.get(), LParenLoc,
MultiExprArg(Args.data(), Args.size()),
RParenLoc);
}
/// Constructs and populates an OverloadedCandidateSet from

View File

@ -296,14 +296,3 @@ void InvalidCondition() {
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2
invalid() ? 1 : 2;
}
void abcc();
void TypoCorrection() {
// RecoveryExpr is always dependent-type in this case in order to suppress
// following diagnostics.
// CHECK: RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: `-CallExpr {{.*}} 'void'
// CHECK-NEXT: `-ImplicitCastExpr
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'abcc'
abc();
}

View File

@ -0,0 +1,15 @@
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-obj -fms-compatibility %s -o -
// CHECK that we don't crash.
struct Base {
void b(int, int);
};
template <typename Base> struct Derived : Base {
void d() { b(1, 2); }
};
void use() {
Derived<Base> d;
d.d();
}

View File

@ -209,15 +209,6 @@ int z = 1 ? N : ; // expected-error {{expected expression}}
// expected-error-re@-1 {{use of undeclared identifier 'N'{{$}}}}
}
namespace noSecondaryDiags {
void abcc(); // expected-note {{'abcc' declared here}}
void test() {
// Verify the secondary diagnostic ".. convertible to 'bool'" is suppressed.
if (abc()) {} // expected-error {{use of undeclared identifier 'abc'; did you mean 'abcc'?}}
}
}
// PR 23285. This test must be at the end of the file to avoid additional,
// unwanted diagnostics.
// expected-error-re@+2 {{use of undeclared identifier 'uintmax_t'{{$}}}}