diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 045bacf21360..005d882c341b 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -101,7 +101,7 @@ public: DeclContext *MemberContext, bool EnteringContext) : Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0), - SemaRef(SemaRef), S(S), + SavedTCIndex(0), SemaRef(SemaRef), S(S), SS(SS ? llvm::make_unique(*SS) : nullptr), CorrectionValidator(std::move(CCC)), MemberContext(MemberContext), Result(SemaRef, TypoName, LookupKind), @@ -187,6 +187,17 @@ public: CurrentTCIndex >= ValidatedCorrections.size(); } + /// \brief Save the current position in the correction stream (overwriting any + /// previously saved position). + void saveCurrentPosition() { + SavedTCIndex = CurrentTCIndex; + } + + /// \brief Restore the saved position in the correction stream. + void restoreSavedPosition() { + CurrentTCIndex = SavedTCIndex; + } + ASTContext &getContext() const { return SemaRef.Context; } const LookupResult &getLookupResult() const { return Result; } @@ -267,6 +278,7 @@ private: SmallVector ValidatedCorrections; size_t CurrentTCIndex; + size_t SavedTCIndex; Sema &SemaRef; Scope *S; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2b507141e975..e75daa412fb5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9459,6 +9459,18 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R, } } +static NamedDecl *getDeclFromExpr(Expr *E) { + if (!E) + return nullptr; + if (auto *DRE = dyn_cast(E)) + return DRE->getDecl(); + if (auto *ME = dyn_cast(E)) + return ME->getMemberDecl(); + if (auto *IRE = dyn_cast(E)) + return IRE->getDecl(); + return nullptr; +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. @@ -9496,7 +9508,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. LHS = CorrectDelayedTyposInExpr(LHSExpr); - RHS = CorrectDelayedTyposInExpr(RHSExpr); + RHS = CorrectDelayedTyposInExpr(RHSExpr, [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; + }); if (!LHS.isUsable() || !RHS.isUsable()) return ExprError(); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index bf4ab267a411..9477c7f2f9ef 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6165,15 +6165,18 @@ public: while (!AmbiguousTypoExprs.empty()) { auto TE = AmbiguousTypoExprs.back(); auto Cached = TransformCache[TE]; - AmbiguousTypoExprs.pop_back(); + auto &State = SemaRef.getTypoExprState(TE); + State.Consumer->saveCurrentPosition(); TransformCache.erase(TE); if (!TryTransform(E).isInvalid()) { - SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream(); + State.Consumer->resetCorrectionStream(); TransformCache.erase(TE); Res = ExprError(); break; - } else - TransformCache[TE] = Cached; + } + AmbiguousTypoExprs.remove(TE); + State.Consumer->restoreSavedPosition(); + TransformCache[TE] = Cached; } // Ensure that all of the TypoExprs within the current Expr have been found. diff --git a/clang/test/SemaCXX/typo-correction-delayed.cpp b/clang/test/SemaCXX/typo-correction-delayed.cpp index f09dd330dbb1..516b600f422f 100644 --- a/clang/test/SemaCXX/typo-correction-delayed.cpp +++ b/clang/test/SemaCXX/typo-correction-delayed.cpp @@ -175,3 +175,13 @@ namespace PR22250 { // expected-error@+1 {{expected ';' after top level declarator}} int getenv_s(size_t *y, char(&z)) {} } + +namespace PR22297 { +double pow(double x, double y); +struct TimeTicks { + static void Now(); // expected-note {{'Now' declared here}} +}; +void f() { + TimeTicks::now(); // expected-error {{no member named 'now' in 'PR22297::TimeTicks'; did you mean 'Now'?}} +} +}