summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/SemaInternal.h14
-rw-r--r--lib/Sema/SemaExpr.cpp20
-rw-r--r--lib/Sema/SemaExprCXX.cpp11
-rw-r--r--test/SemaCXX/typo-correction-delayed.cpp10
4 files changed, 49 insertions, 6 deletions
diff --git a/include/clang/Sema/SemaInternal.h b/include/clang/Sema/SemaInternal.h
index 045bacf213..005d882c34 100644
--- a/include/clang/Sema/SemaInternal.h
+++ b/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<CXXScopeSpec>(*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<TypoCorrection, 4> ValidatedCorrections;
size_t CurrentTCIndex;
+ size_t SavedTCIndex;
Sema &SemaRef;
Scope *S;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9cb147f878..93b4c30871 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -9457,6 +9457,18 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R,
}
}
+static NamedDecl *getDeclFromExpr(Expr *E) {
+ if (!E)
+ return nullptr;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getDecl();
+ if (auto *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (auto *IRE = dyn_cast<ObjCIvarRefExpr>(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.
@@ -9494,7 +9506,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/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 49a579fb76..ca15550768 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -6162,15 +6162,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/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
index c5c23ba039..a73a5dc809 100644
--- a/test/SemaCXX/typo-correction-delayed.cpp
+++ b/test/SemaCXX/typo-correction-delayed.cpp
@@ -165,3 +165,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'?}}
+}
+}