BTW, here is just this patch from the set, with all of the changes
discussed and rebased against ToT.
On Wed, Nov 5, 2014 at 1:14 PM, Kaelyn Takata <[email protected]> wrote:
> Accidentally hit "Reply" instead of "Reply All".
>
>
> On Tue, Nov 4, 2014 at 4:54 PM, David Blaikie <[email protected]> wrote:
>
>> Could you post/send (on/off list, etc) an aggregate patch so I can play
>> around with the behavior of this patch?
>>
>> Some superficial patch review
>>
>> lambda passed to CorrectDelayedTyposInExpr has 'else-after-return' - you
>> could move the short block up to the top:
>>
>> if (!...CPlusPlus11)
>> return this->VerifyIntegerConstantExpression(E);
>> /* unindented the longer part of the code */
>>
>
> Fixed. Thanks for catching that!
>
>>
>> I'm slightly surprised at the indentation there too - I think
>> clang-format has a special case for lambdas as the last function argument,
>> where it won't indent them extra (so the "});" will be at the same level as
>> the expression - maybe it only does that if you're not initializing a
>> variable? Dunno.
>>
>
> I think it was a quirk in the version of clang-format used to originally
> format this several months ago; clang-format now formats it a bit
> differently.
>
>>
>> Do you need the 'this->' qualification in that lambda? I assume not. (& I
>> usually favor just capture everything by reference [&] - but up to you on
>> that, we're all still certainly feeling out how best to write C++11)
>>
>
> I didn't think the implicit "this" could be used for accessing member
> functions... I just learned something new. :) (Though "this" still needs to
> be in the capture list--I didn't capture everything by reference because
> the only variable that needed to be captured was "this".)
>
>>
>> EmptyLookupTypoDiags::operator() - some {} on single-statement blocks (if
>> (Ctx)/else)
>> Might be worth inverting the if/following block - the if block is
>> longer/nested than the tail block, so switching them around should reduce
>> indentation, etc.
>>
>
> Done and done.
>
>>
>> std::string CorrectedStr(TC.getAsString(SemaRef.getLangOpts()));
>>
>> Prefer copy/move init rather than direct init:
>>
>> std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts());
>>
>
> Changed.
>
>>
>> Hmm - it might be nice to write EmptyLookupTypoDiags just as a single
>> free function (taking all those members as parameters instead) then call
>> that in a lambda - that way you don't have to write all the member
>> state/ctor/etc logic?
>>
>
> I had to capture variables by value instead of by reference to avoid
> lifetime issues (and having 74 tests fail) and create a local variable so
> the LookupResult didn't have to be captured since it cannot be copied, but
> I did get it working as a static function and a lambda and the switch
> resulted in a net change of 17 fewer lines (37 added, 54 deleted).
>
>>
>> lambda in ParseCaseStatement: I'd probably write "return ExprResult(...)"
>> rather than explicitly specifying the return type. (do you even need to do
>> either? If CorrectDelayedTyposInExpr is a template, then its return result
>> should just implicitly convert to ExprResult in the caller, if it takes a
>> std::function, that should still work too... - I can explain this more in
>> person, perhaps.
>>
>
> You're right, neither seem to be needed--though I thought I had added the
> return type because of clang complaining without it.
>
>>
>> Rather than goto in ParseCXXIdExpression, could that be a loop?
>>
>
> The cleanest way I can see to write it as a loop would be to wrap it in a
> "while (true) {...}" loop, and have an "if (Result.isInvalid() ||
> Result.get()) break;" right before the (now unconditional) call to
> UnconsumeToken. The only other way I can see to do the loop would require
> checking "!Result.isInvalid() && !Result.get()" twice in a row, once to
> know whether to call UnconsumeToken, and once in the do...while loop to
> know whether to continue looping.
>
>>
>>
>> Hmm - why is the correction applied to the LHS/RHS of the binary
>> expression, rather than waiting until the full expression is parsed?
>>
>
> If you are referring to within ParseRHSOfBinaryExpression, it's because
> any error in the RHS will cause the LHS to be replaced with an ExprError
> without any typos in the LHS being diagnosed, so waiting until the full
> expression is parsed causes typos to go undiagnosed if there are unrelated
> parse errors in the full expression. This had been a bit of a pain to
> figure out and track down why typo correction on certain full expressions
> wasn't happening for part of the expression...
>
>>
>>
>>
>>
>>
>>
>> On Wed, Oct 29, 2014 at 12:49 PM, Kaelyn Takata <[email protected]> wrote:
>>
>>
>>> Among other things, this eliminates at least one redundant error case
>>> and allows recovery in several cases where it wasn't possible before
>>> (e.g. correcting a mistyped static_cast<>).
>>> ---
>>> include/clang/Parse/Parser.h | 9 +++
>>> include/clang/Sema/Sema.h | 4 +-
>>> lib/Parse/ParseCXXInlineMethods.cpp | 1 +
>>> lib/Parse/ParseDecl.cpp | 4 +-
>>> lib/Parse/ParseDeclCXX.cpp | 2 +-
>>> lib/Parse/ParseExpr.cpp | 30 +++++++---
>>> lib/Parse/ParseExprCXX.cpp | 13 ++++-
>>> lib/Parse/ParseObjc.cpp | 5 +-
>>> lib/Parse/ParseOpenMP.cpp | 3 +-
>>> lib/Parse/ParseStmt.cpp | 8 ++-
>>> lib/Sema/SemaExpr.cpp | 110
>>> ++++++++++++++++++++++++++++++++---
>>> lib/Sema/SemaStmt.cpp | 19 ++++++
>>> test/FixIt/fixit-unrecoverable.cpp | 4 +-
>>> test/SemaCXX/typo-correction.cpp | 7 ++-
>>> test/SemaTemplate/crash-10438657.cpp | 2 +-
>>> 15 files changed, 189 insertions(+), 32 deletions(-)
>>>
>>>
>>> _______________________________________________
>>>
>>>> cfe-commits mailing list
>>>
>>>> [email protected]
>>>
>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>>
>>>
>>
>
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 9a29edb..d3306ef 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -334,6 +334,15 @@ private:
/// For typos, give a fixit to '='
bool isTokenEqualOrEqualTypo();
+ /// \brief Return the current token to the token stream and make the given
+ /// token the current token.
+ void UnconsumeToken(Token &Consumed) {
+ Token Next = Tok;
+ PP.EnterToken(Consumed);
+ ConsumeToken();
+ PP.EnterToken(Next);
+ }
+
/// ConsumeAnyToken - Dispatch to the right Consume* method based on the
/// current token type. This should only be used in cases where the type of
/// the token really isn't known, e.g. in error recovery.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 19cdfb0..d16fa5f 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3463,7 +3463,7 @@ public:
Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand,
std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr,
- bool IsInlineAsmIdentifier = false);
+ bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr);
void DecomposeUnqualifiedId(const UnqualifiedId &Id,
TemplateArgumentListInfo &Buffer,
@@ -3474,7 +3474,7 @@ public:
DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
std::unique_ptr<CorrectionCandidateCallback> CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
- ArrayRef<Expr *> Args = None);
+ ArrayRef<Expr *> Args = None, TypoExpr **Out = nullptr);
ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
IdentifierInfo *II,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 2a2f3b1..8469fb9 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -336,6 +336,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
DefArgResult = ParseBraceInitializer();
} else
DefArgResult = ParseAssignmentExpression();
+ DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult);
if (DefArgResult.isInvalid())
Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param,
EqualLoc);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2e30c52..d055bd3 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -302,7 +302,8 @@ unsigned Parser::ParseAttributeArgsCommon(
Unevaluated.reset(
new EnterExpressionEvaluationContext(Actions, Sema::Unevaluated));
- ExprResult ArgExpr(ParseAssignmentExpression());
+ ExprResult ArgExpr(
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
@@ -5566,6 +5567,7 @@ void Parser::ParseParameterDeclarationClause(
DefArgResult = ParseBraceInitializer();
} else
DefArgResult = ParseAssignmentExpression();
+ DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult);
if (DefArgResult.isInvalid()) {
Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 91c1372..79ae878 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -796,7 +796,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// The operand of the decltype specifier is an unevaluated operand.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
nullptr,/*IsDecltype=*/true);
- Result = ParseExpression();
+ Result = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Result.isInvalid()) {
DS.SetTypeSpecError();
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index b4ba0bc..3d57ba9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -277,6 +277,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// 'logical-OR-expression' as we might expect.
TernaryMiddle = ParseExpression();
if (TernaryMiddle.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
TernaryMiddle = nullptr;
}
@@ -345,9 +346,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
else
RHS = ParseCastExpression(false);
- if (RHS.isInvalid())
+ if (RHS.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
-
+ }
+
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
prec::Level ThisPrec = NextTokPrec;
@@ -376,8 +379,10 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
static_cast<prec::Level>(ThisPrec + !isRightAssoc));
RHSIsInitList = false;
- if (RHS.isInvalid())
+ if (RHS.isInvalid()) {
+ Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
+ }
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLangOpts().CPlusPlus11);
@@ -413,7 +418,9 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
LHS.get(), TernaryMiddle.get(),
RHS.get());
- }
+ } else
+ // Ensure potential typos in the RHS aren't left undiagnosed.
+ Actions.CorrectDelayedTyposInExpr(RHS);
}
}
@@ -441,7 +448,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
public:
CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes)
: AllowNonTypes(AllowNonTypes) {
- WantTypeSpecifiers = AllowTypes;
+ WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes;
}
bool ValidateCandidate(const TypoCorrection &candidate) override {
@@ -899,13 +906,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
UnqualifiedId Name;
CXXScopeSpec ScopeSpec;
SourceLocation TemplateKWLoc;
+ Token Replacement;
auto Validator = llvm::make_unique<CastExpressionIdValidator>(
isTypeCast != NotTypeCast, isTypeCast != IsTypeCast);
Validator->IsAddressOfOperand = isAddressOfOperand;
Name.setIdentifier(&II, ILoc);
- Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
- Name, Tok.is(tok::l_paren),
- isAddressOfOperand, std::move(Validator));
+ Res = Actions.ActOnIdExpression(
+ getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
+ isAddressOfOperand, std::move(Validator),
+ /*IsInlineAsmIdentifier=*/false, &Replacement);
+ if (!Res.isInvalid() && !Res.get()) {
+ UnconsumeToken(Replacement);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
+ }
break;
}
case tok::char_constant: // constant: character-constant
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index fbe5de1..d507e66 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -619,6 +619,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
+retry:
if (ParseUnqualifiedId(SS,
/*EnteringContext=*/false,
/*AllowDestructorName=*/false,
@@ -633,8 +634,16 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
isAddressOfOperand = false;
- return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name,
- Tok.is(tok::l_paren), isAddressOfOperand);
+ Token Replacement;
+ ExprResult Result = Actions.ActOnIdExpression(
+ getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
+ isAddressOfOperand, nullptr, /*IsInlineAsmIdentifier=*/false,
+ &Replacement);
+ if (!Result.isInvalid() && !Result.get()) {
+ UnconsumeToken(Replacement);
+ goto retry;
+ }
+ return Result;
}
/// ParseLambdaExpression - Parse a C++11 lambda expression.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index ad1cbff..0d0f110 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -2170,7 +2170,10 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
// objc-receiver:
// expression
- ExprResult Receiver = ParseExpression();
+ // Make sure any typos in the receiver are corrected or diagnosed, so that
+ // proper recovery can happen. FIXME: Perhaps filter the corrected expr to
+ // only the things that are valid ObjC receivers?
+ ExprResult Receiver = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Receiver.isInvalid())
return true;
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 3a119a6..7851c40 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -741,7 +741,8 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
if (MustHaveTail) {
ColonLoc = Tok.getLocation();
ConsumeToken();
- ExprResult Tail = ParseAssignmentExpression();
+ ExprResult Tail =
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (Tail.isUsable())
TailExpr = Tail.get();
else
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 3bf66c3..1bfce60 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -642,6 +642,11 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
ExprResult LHS;
if (!MissingCase) {
LHS = ParseConstantExpression();
+ if (!getLangOpts().CPlusPlus11) {
+ LHS = Actions.CorrectDelayedTyposInExpr(LHS, [this](class Expr *E) {
+ return Actions.VerifyIntegerConstantExpression(E);
+ });
+ }
if (LHS.isInvalid()) {
// If constant-expression is parsed unsuccessfully, recover by skipping
// current case statement (moving to the colon that ends it).
@@ -1562,7 +1567,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
} else {
ProhibitAttributes(attrs);
- Value = ParseExpression();
+ Value = Actions.CorrectDelayedTyposInExpr(ParseExpression());
ForEach = isTokIdentifier_in();
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9d67d97..e9acd67 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1673,6 +1673,40 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
}
}
+static void emitEmptyLookupTypoDiagnostic(
+ const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS,
+ DeclarationName Typo, SourceLocation TypoLoc, ArrayRef<Expr *> Args,
+ unsigned DiagnosticID, unsigned DiagnosticSuggestID) {
+ DeclContext *Ctx =
+ SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false);
+ if (!TC) {
+ // Emit a special diagnostic for failed member lookups.
+ // FIXME: computing the declaration context might fail here (?)
+ if (Ctx)
+ SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx
+ << SS.getRange();
+ else
+ SemaRef.Diag(TypoLoc, DiagnosticID) << Typo;
+ return;
+ }
+
+ std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts());
+ bool DroppedSpecifier =
+ TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr;
+ unsigned NoteID =
+ (TC.getCorrectionDecl() && isa<ImplicitParamDecl>(TC.getCorrectionDecl()))
+ ? diag::note_implicit_param_decl
+ : diag::note_previous_decl;
+ if (!Ctx)
+ SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo,
+ SemaRef.PDiag(NoteID));
+ else
+ SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest)
+ << Typo << Ctx << DroppedSpecifier
+ << SS.getRange(),
+ SemaRef.PDiag(NoteID));
+}
+
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
@@ -1680,7 +1714,7 @@ bool
Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
std::unique_ptr<CorrectionCandidateCallback> CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args, TypoExpr **Out) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -1797,8 +1831,22 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
- if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
- S, &SS, std::move(CCC), CTK_ErrorRecovery))) {
+ if (S && Out) {
+ SourceLocation TypoLoc = R.getNameLoc();
+ assert(!ExplicitTemplateArgs &&
+ "Diagnosing an empty lookup with explicit template args!");
+ *Out = CorrectTypoDelayed(
+ R.getLookupNameInfo(), R.getLookupKind(), S, &SS, std::move(CCC),
+ [=](const TypoCorrection &TC) {
+ emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args,
+ diagnostic, diagnostic_suggest);
+ },
+ nullptr, CTK_ErrorRecovery);
+ if (*Out)
+ return true;
+ } else if (S && (Corrected =
+ CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S,
+ &SS, std::move(CCC), CTK_ErrorRecovery))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
@@ -1950,7 +1998,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
SourceLocation TemplateKWLoc, UnqualifiedId &Id,
bool HasTrailingLParen, bool IsAddressOfOperand,
std::unique_ptr<CorrectionCandidateCallback> CCC,
- bool IsInlineAsmIdentifier) {
+ bool IsInlineAsmIdentifier, Token *KeywordReplacement) {
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
if (SS.isInvalid())
@@ -2062,13 +2110,43 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
- auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>();
+ TypoExpr *TE = nullptr;
+ auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>(
+ II, SS.isValid() ? SS.getScopeRep() : nullptr);
DefaultValidator->IsAddressOfOperand = IsAddressOfOperand;
assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) &&
"Typo correction callback misconfigured");
- if (DiagnoseEmptyLookup(S, SS, R,
- CCC ? std::move(CCC) : std::move(DefaultValidator)))
- return ExprError();
+ if (CCC) {
+ // Make sure the callback knows what the typo being diagnosed is.
+ CCC->setTypoName(II);
+ if (SS.isValid())
+ CCC->setTypoNNS(SS.getScopeRep());
+ }
+ if (DiagnoseEmptyLookup(
+ S, SS, R, CCC ? std::move(CCC) : std::move(DefaultValidator),
+ nullptr, None, getLangOpts().CPlusPlus ? &TE : nullptr)) {
+ if (TE && KeywordReplacement) {
+ auto &State = getTypoExprState(TE);
+ auto BestTC = State.Consumer->getNextCorrection();
+ if (BestTC.isKeyword()) {
+ auto *II = BestTC.getCorrectionAsIdentifierInfo();
+ if (State.DiagHandler)
+ State.DiagHandler(BestTC);
+ KeywordReplacement->startToken();
+ KeywordReplacement->setKind(II->getTokenID());
+ KeywordReplacement->setIdentifierInfo(II);
+ KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin());
+ // Clean up the state associated with the TypoExpr, since it has
+ // now been diagnosed (without a call to CorrectDelayedTyposInExpr).
+ clearDelayedTypo(TE);
+ // Signal that a correction to a keyword was performed by returning a
+ // valid-but-null ExprResult.
+ return (Expr*)nullptr;
+ }
+ State.Consumer->resetCorrectionStream();
+ }
+ return TE ? TE : ExprError();
+ }
assert(!R.empty() &&
"DiagnoseEmptyLookup returned false but added no results");
@@ -12430,6 +12508,8 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
}
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
+ Res = CorrectDelayedTyposInExpr(Res);
+
if (!Res.isUsable())
return Res;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 3c4085a..f4dc9c5 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -371,6 +371,23 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
return StmtError();
}
+ ExprResult LHS =
+ CorrectDelayedTyposInExpr(LHSVal, [this](class Expr *E) -> ExprResult {
+ if (!getLangOpts().CPlusPlus11)
+ return VerifyIntegerConstantExpression(E);
+ if (Expr *CondExpr =
+ getCurFunction()->SwitchStack.back()->getCond()) {
+ QualType CondType = CondExpr->getType();
+ llvm::APSInt TempVal;
+ return CheckConvertedConstantExpression(E, CondType, TempVal,
+ CCEK_CaseValue);
+ }
+ return ExprError();
+ });
+ if (LHS.isInvalid())
+ return StmtError();
+ LHSVal = LHS.get();
+
if (!getLangOpts().CPlusPlus11) {
// C99 6.8.4.2p3: The expression shall be an integer constant.
// However, GCC allows any evaluatable integer expression.
diff --git a/test/FixIt/fixit-unrecoverable.cpp b/test/FixIt/fixit-unrecoverable.cpp
index 1e1f1b8..f555792 100644
--- a/test/FixIt/fixit-unrecoverable.cpp
+++ b/test/FixIt/fixit-unrecoverable.cpp
@@ -6,7 +6,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
float f(int y) {
- return static_cst<float>(y); // expected-error{{use of undeclared identifier 'static_cst'; did you mean 'static_cast'?}} \
- // expected-error{{for function-style cast or type construction}}
+ return static_cst<float>(y); // expected-error{{use of undeclared identifier 'static_cst'; did you mean 'static_cast'?}}
}
-
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index a4f5174..4f19283 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -209,11 +209,12 @@ namespace PR13051 {
};
void foo(); // expected-note{{'foo' declared here}}
- void g(void(*)());
- void g(bool(S<int>::*)() const);
+ void g(void(*)()); // expected-note{{candidate function not viable}}
+ void g(bool(S<int>::*)() const); // expected-note{{candidate function not viable}}
void test() {
- g(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}}
+ g(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}} \
+ // expected-error{{no matching function for call to 'g'}}
g(&S<int>::opeartor bool); // expected-error{{did you mean 'operator'?}}
g(&S<int>::foo); // expected-error{{no member named 'foo' in 'PR13051::S<int>'; did you mean simply 'foo'?}}
}
diff --git a/test/SemaTemplate/crash-10438657.cpp b/test/SemaTemplate/crash-10438657.cpp
index 2ee64bd..3eaa8c1 100644
--- a/test/SemaTemplate/crash-10438657.cpp
+++ b/test/SemaTemplate/crash-10438657.cpp
@@ -1,6 +1,6 @@
// RUN: not %clang_cc1 -fsyntax-only %s 2> %t
// RUN: FileCheck %s < %t
-// CHECK: 10 errors
+// CHECK: 9 errors
template<typename _CharT>
class collate : public locale::facet {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits