diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3847,32 +3847,28 @@ /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its /// initializer. /// + /// \param RecoverUncorrectedTypos If true, when typo correction fails, it + /// will rebuild the given Expr with all TypoExprs degraded to RecoveryExprs. + /// /// \param Filter A function applied to a newly rebuilt Expr to determine if /// it is an acceptable/usable result from a single combination of typo /// corrections. As long as the filter returns ExprError, different /// combinations of corrections will be tried until all are exhausted. - ExprResult - CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl = nullptr, - llvm::function_ref Filter = - [](Expr *E) -> ExprResult { return E; }); - - ExprResult - CorrectDelayedTyposInExpr(Expr *E, - llvm::function_ref Filter) { - return CorrectDelayedTyposInExpr(E, nullptr, Filter); - } - - ExprResult - CorrectDelayedTyposInExpr(ExprResult ER, VarDecl *InitDecl = nullptr, - llvm::function_ref Filter = - [](Expr *E) -> ExprResult { return E; }) { - return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), Filter); - } - - ExprResult - CorrectDelayedTyposInExpr(ExprResult ER, - llvm::function_ref Filter) { - return CorrectDelayedTyposInExpr(ER, nullptr, Filter); + ExprResult CorrectDelayedTyposInExpr( + Expr *E, VarDecl *InitDecl = nullptr, + bool RecoverUncorrectedTypos = false, + llvm::function_ref Filter = + [](Expr *E) -> ExprResult { return E; }); + + ExprResult CorrectDelayedTyposInExpr( + ExprResult ER, VarDecl *InitDecl = nullptr, + bool RecoverUncorrectedTypos = false, + llvm::function_ref Filter = + [](Expr *E) -> ExprResult { return E; }) { + return ER.isInvalid() + ? ER + : CorrectDelayedTyposInExpr(ER.get(), InitDecl, + RecoverUncorrectedTypos, Filter); } void diagnoseTypo(const TypoCorrection &Correction, diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -984,10 +984,10 @@ EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Decltype); - Result = - Actions.CorrectDelayedTyposInExpr(ParseExpression(), [](Expr *E) { - return E->hasPlaceholderType() ? ExprError() : E; - }); + Result = Actions.CorrectDelayedTyposInExpr( + ParseExpression(), /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/false, + [](Expr *E) { return E->hasPlaceholderType() ? ExprError() : E; }); if (Result.isInvalid()) { DS.SetTypeSpecError(); if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12017,7 +12017,8 @@ // Try to correct any TypoExprs in the initialization arguments. for (size_t Idx = 0; Idx < Args.size(); ++Idx) { ExprResult Res = CorrectDelayedTyposInExpr( - Args[Idx], VDecl, [this, Entity, Kind](Expr *E) { + Args[Idx], VDecl, /*RecoverUncorrectedTypos=*/false, + [this, Entity, Kind](Expr *E) { InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E)); return Init.Failed() ? ExprError() : E; }); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13650,13 +13650,15 @@ // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. LHS = S.CorrectDelayedTyposInExpr(LHS); - RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) { - if (Opc != BO_Assign) - return ExprResult(E); - // Avoid correcting the RHS to the same Expr as the LHS. - Decl *D = getDeclFromExpr(E); - return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; - }); + RHS = S.CorrectDelayedTyposInExpr( + RHS, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false, + [Opc, LHS](Expr *E) { + if (Opc != BO_Assign) + return ExprResult(E); + // Avoid correcting the RHS to the same Expr as the LHS. + Decl *D = getDeclFromExpr(E); + return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; + }); } return std::make_pair(LHS, RHS); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8253,6 +8253,7 @@ ExprResult Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, + bool RecoverUncorrectedTypos, llvm::function_ref Filter) { // If the current evaluation context indicates there are uncorrected typos // and the current expression isn't guaranteed to not have typos, try to @@ -8265,6 +8266,16 @@ TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { ExprEvalContexts.back().NumTypos -= TyposResolved; + if (Result.isInvalid() && RecoverUncorrectedTypos) { + struct TyposReplace : TreeTransform { + TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {} + ExprResult TransformTypoExpr(clang::TypoExpr *E) { + return this->SemaRef.CreateRecoveryExpr(E->getBeginLoc(), + E->getEndLoc(), {}); + } + } TT(*this); + return TT.TransformExpr(E); + } return Result; } assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); @@ -8303,20 +8314,10 @@ DiagnoseUnusedExprResult(FullExpr.get()); } - FullExpr = CorrectDelayedTyposInExpr(FullExpr.get()); - if (FullExpr.isInvalid()) { - // Typo-correction fails, we rebuild the broken AST with the typos degraded - // to RecoveryExpr. - struct TyposReplace : TreeTransform { - TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {} - ExprResult TransformTypoExpr(TypoExpr *E) { - return this->SemaRef.CreateRecoveryExpr(E->getBeginLoc(), - E->getEndLoc(), {}); - } - } TT(*this); - - return TT.TransformExpr(FE); - } + FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); + if (FullExpr.isInvalid()) + return ExprError(); CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -477,7 +477,9 @@ return ER; }; - ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish); + ExprResult Converted = CorrectDelayedTyposInExpr( + Val, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false, + CheckAndFinish); if (Converted.get() == Val.get()) Converted = CheckAndFinish(Val.get()); return Converted;