diff options
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 30 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 9 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 15 | ||||
| -rw-r--r-- | clang/test/SemaCXX/typo-correction-cxx11.cpp | 8 |
5 files changed, 57 insertions, 12 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d8341b774f1..8a265f4c59d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2671,18 +2671,44 @@ public: bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr); + /// \brief Process any TypoExprs in the given Expr and its children, + /// generating diagnostics as appropriate and returning a new Expr if there + /// were typos that were all successfully corrected and ExprError if one or + /// more typos could not be corrected. + /// + /// \param E The Expr to check for TypoExprs. + /// + /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its + /// initializer. + /// + /// \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, + CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl = nullptr, llvm::function_ref<ExprResult(Expr *)> Filter = [](Expr *E) -> ExprResult { return E; }); ExprResult - CorrectDelayedTyposInExpr(ExprResult ER, + CorrectDelayedTyposInExpr(Expr *E, + llvm::function_ref<ExprResult(Expr *)> Filter) { + return CorrectDelayedTyposInExpr(E, nullptr, Filter); + } + + ExprResult + CorrectDelayedTyposInExpr(ExprResult ER, VarDecl *InitDecl = nullptr, llvm::function_ref<ExprResult(Expr *)> Filter = [](Expr *E) -> ExprResult { return E; }) { return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), Filter); } + ExprResult + CorrectDelayedTyposInExpr(ExprResult ER, + llvm::function_ref<ExprResult(Expr *)> Filter) { + return CorrectDelayedTyposInExpr(ER, nullptr, Filter); + } + void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, bool ErrorRecovery = true); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 527351012d9..95a28a8d5a1 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -931,7 +931,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, auto Validator = llvm::make_unique<CastExpressionIdValidator>( Tok, isTypeCast != NotTypeCast, isTypeCast != IsTypeCast); Validator->IsAddressOfOperand = isAddressOfOperand; - Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren); + if (Tok.is(tok::periodstar) || Tok.is(tok::arrowstar)) { + Validator->WantExpressionKeywords = false; + Validator->WantRemainingKeywords = false; + } else { + Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren); + } Name.setIdentifier(&II, ILoc); Res = Actions.ActOnIdExpression( getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 00922f73a8e..7f4b3952807 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8710,7 +8710,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // If there is no declaration, there was an error parsing it. Just ignore // the initializer. if (!RealDecl || RealDecl->isInvalidDecl()) { - CorrectDelayedTyposInExpr(Init); + CorrectDelayedTyposInExpr(Init, dyn_cast_or_null<VarDecl>(RealDecl)); return; } @@ -8744,11 +8744,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Attempt typo correction early so that the type of the init expression can // be deduced based on the chosen correction:if the original init contains a // TypoExpr. - ExprResult Res = CorrectDelayedTyposInExpr(Init); + ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl); if (!Res.isUsable()) { RealDecl->setInvalidDecl(); return; } + if (Res.get() != Init) { Init = Res.get(); if (CXXDirectInit) @@ -8967,8 +8968,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Try to correct any TypoExprs in the initialization arguments. for (size_t Idx = 0; Idx < Args.size(); ++Idx) { - ExprResult Res = - CorrectDelayedTyposInExpr(Args[Idx], [this, Entity, Kind](Expr *E) { + ExprResult Res = CorrectDelayedTyposInExpr( + Args[Idx], VDecl, [this, Entity, Kind](Expr *E) { InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E)); return Init.Failed() ? ExprError() : E; }); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index bb67939ad89..b853eaefbe4 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6138,6 +6138,8 @@ public: class TransformTypos : public TreeTransform<TransformTypos> { typedef TreeTransform<TransformTypos> BaseTransform; + VarDecl *InitDecl; // A decl to avoid as a correction because it is in the + // process of being initialized. llvm::function_ref<ExprResult(Expr *)> ExprFilter; llvm::SmallSetVector<TypoExpr *, 2> TypoExprs, AmbiguousTypoExprs; llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache; @@ -6216,8 +6218,8 @@ class TransformTypos : public TreeTransform<TransformTypos> { } public: - TransformTypos(Sema &SemaRef, llvm::function_ref<ExprResult(Expr *)> Filter) - : BaseTransform(SemaRef), ExprFilter(Filter) {} + TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref<ExprResult(Expr *)> Filter) + : BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {} ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, MultiExprArg Args, @@ -6296,6 +6298,8 @@ public: // For the first TypoExpr and an uncached TypoExpr, find the next likely // typo correction and return it. while (TypoCorrection TC = State.Consumer->getNextCorrection()) { + if (InitDecl && TC.getCorrectionDecl() == InitDecl) + continue; ExprResult NE = State.RecoveryHandler ? State.RecoveryHandler(SemaRef, E, TC) : attemptRecovery(SemaRef, *State.Consumer, TC); @@ -6320,8 +6324,9 @@ public: }; } -ExprResult Sema::CorrectDelayedTyposInExpr( - Expr *E, llvm::function_ref<ExprResult(Expr *)> Filter) { +ExprResult +Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, + llvm::function_ref<ExprResult(Expr *)> Filter) { // If the current evaluation context indicates there are uncorrected typos // and the current expression isn't guaranteed to not have typos, try to // resolve any TypoExpr nodes that might be in the expression. @@ -6332,7 +6337,7 @@ ExprResult Sema::CorrectDelayedTyposInExpr( assert(TyposInContext < ~0U && "Recursive call of CorrectDelayedTyposInExpr"); ExprEvalContexts.back().NumTypos = ~0U; auto TyposResolved = DelayedTypos.size(); - auto Result = TransformTypos(*this, Filter).Transform(E); + auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E); ExprEvalContexts.back().NumTypos = TyposInContext; TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { diff --git a/clang/test/SemaCXX/typo-correction-cxx11.cpp b/clang/test/SemaCXX/typo-correction-cxx11.cpp index 573c6aa1171..003d07edb3c 100644 --- a/clang/test/SemaCXX/typo-correction-cxx11.cpp +++ b/clang/test/SemaCXX/typo-correction-cxx11.cpp @@ -15,3 +15,11 @@ struct S { } }; } + +namespace PR23140 { +auto lneed = gned.*[] {}; // expected-error-re {{use of undeclared identifier 'gned'{{$}}}} + +void test(int aaa, int bbb, int thisvar) { // expected-note {{'thisvar' declared here}} + int thatval = aaa * (bbb + thatvar); // expected-error {{use of undeclared identifier 'thatvar'; did you mean 'thisvar'?}} +} +} |

