summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Sema/Sema.h30
-rw-r--r--clang/lib/Parse/ParseExpr.cpp7
-rw-r--r--clang/lib/Sema/SemaDecl.cpp9
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp15
-rw-r--r--clang/test/SemaCXX/typo-correction-cxx11.cpp8
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'?}}
+}
+}
OpenPOWER on IntegriCloud