diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -12725,8 +12725,6 @@ } /// Attempts to recover from a call where no functions were found. -/// -/// Returns true if new candidates were found. static ExprResult BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, @@ -12783,7 +12781,7 @@ return ExprError(); } - // Build an implicit member call if appropriate. Just drop the + // Build an implicit member access expression if appropriate. Just drop the // casts and such from the call, we don't really care. ExprResult NewFn = ExprError(); if ((*R.begin())->isCXXClassMember()) @@ -12798,10 +12796,16 @@ if (NewFn.isInvalid()) return ExprError(); - // 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, + // 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. + ExprResult RE = SemaRef.CreateRecoveryExpr( + NewFn.get()->getBeginLoc(), NewFn.get()->getEndLoc(), {NewFn.get()}); + if (RE.isInvalid()) + return ExprError(); + + return SemaRef.BuildCallExpr(/*Scope*/ nullptr, RE.get(), LParenLoc, MultiExprArg(Args.data(), Args.size()), RParenLoc); } diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -271,3 +271,11 @@ // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 invalid() ? 1 : 2; } + +void abcc(); +void TypoCorrection() { + // CHECK: CallExpr {{.*}} '' contains-errors + // CHECK-NEXT: `-RecoveryExpr {{.*}} + // CHECK-NEXT: `-DeclRefExpr {{.*}} 'abcc' + abc(); +} diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp @@ -21,12 +21,10 @@ } namespace C { - class C {}; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B::B' to 'const C::C &' for 1st argument}} + class C {}; #if __cplusplus >= 201103L // C++11 or later - // expected-note@-2 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'B::B' to 'C::C &&' for 1st argument}} #endif - void func(C); // expected-note {{'C::func' declared here}} \ - // expected-note {{passing argument to parameter here}} + void func(C); // expected-note {{'C::func' declared here}} C operator+(C,C); D::D operator+(D::D,D::D); } @@ -38,13 +36,7 @@ namespace Test { void test() { func(A::A()); - // FIXME: namespace-aware typo correction causes an extra, misleading - // message in this case; some form of backtracking, diagnostic message - // delaying, or argument checking before emitting diagnostics is needed to - // avoid accepting and printing out a typo correction that proves to be - // incorrect once argument-dependent lookup resolution has occurred. - func(B::B()); // expected-error {{use of undeclared identifier 'func'; did you mean 'C::func'?}} \ - // expected-error {{no viable conversion from 'B::B' to 'C::C'}} + func(B::B()); // expected-error {{use of undeclared identifier 'func'; did you mean 'C::func'?}} func(C::C()); A::A() + A::A(); B::B() + B::B(); diff --git a/clang/test/Modules/submodules-merge-defs.cpp b/clang/test/Modules/submodules-merge-defs.cpp --- a/clang/test/Modules/submodules-merge-defs.cpp +++ b/clang/test/Modules/submodules-merge-defs.cpp @@ -18,7 +18,7 @@ // expected-error-re@-1 {{missing '#include "{{.*}}-defs.h"'; 'A' must be declared}} // expected-note@defs.h:1 +{{here}} extern class A pre_a2; -int pre_use_a = use_a(pre_a2); // expected-error 2{{'A' must be defined}} expected-error {{'use_a' must be declared}} +int pre_use_a = use_a(pre_a2); // expected-error {{'use_a' must be declared}} // expected-note@defs.h:2 +{{here}} B::Inner2 pre_bi; // expected-error +{{must be declared}} expected-error +{{must be defined}} diff --git a/clang/test/SemaCXX/enable_if.cpp b/clang/test/SemaCXX/enable_if.cpp --- a/clang/test/SemaCXX/enable_if.cpp +++ b/clang/test/SemaCXX/enable_if.cpp @@ -356,9 +356,9 @@ __attribute__((enable_if(num != 1, ""))); } // namespace ns -using ns::Function; // expected-note 3{{declared here}} +using ns::Function; // expected-note 2{{declared here}} void Run() { - Functioon(0); // expected-error{{use of undeclared identifier}} expected-error{{too few arguments}} + Functioon(0); // expected-error{{use of undeclared identifier}} Functioon(0, 1); // expected-error{{use of undeclared identifier}} Functioon(0, 1, 2); // expected-error{{use of undeclared identifier}} } diff --git a/clang/test/SemaCXX/typo-correction-delayed.cpp b/clang/test/SemaCXX/typo-correction-delayed.cpp --- a/clang/test/SemaCXX/typo-correction-delayed.cpp +++ b/clang/test/SemaCXX/typo-correction-delayed.cpp @@ -209,6 +209,15 @@ // expected-error-re@-1 {{use of undeclared identifier 'N'{{$}}}} } +namespace noSecondaryDiags { +void abcc(); // expected-note {{'abcc' declared here}} + +void test() { + // Verify the secondary diagnostic ".. convertiable 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'{{$}}}}