Enable ActOnIdExpression to use delayed typo correction for non-C++ code

when calling DiagnoseEmptyLookup.

llvm-svn: 222551
This commit is contained in:
Kaelyn Takata 2014-11-21 18:48:04 +00:00
parent 4c3ffc4fef
commit 1586782767
9 changed files with 68 additions and 22 deletions

View File

@ -5724,7 +5724,8 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
} else {
EnterExpressionEvaluationContext Unevaluated(Actions,
Sema::ConstantEvaluated);
NumElements = ParseAssignmentExpression();
NumElements =
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
}
} else {
if (StaticLoc.isValid()) {

View File

@ -910,6 +910,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
auto Validator = llvm::make_unique<CastExpressionIdValidator>(
isTypeCast != NotTypeCast, isTypeCast != IsTypeCast);
Validator->IsAddressOfOperand = isAddressOfOperand;
Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren);
Name.setIdentifier(&II, ILoc);
Res = Actions.ActOnIdExpression(
getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
@ -2513,10 +2514,19 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
}
if (Tok.isNot(tok::comma))
return SawError;
break;
// Move to the next argument, remember where the comma was.
CommaLocs.push_back(ConsumeToken());
}
if (SawError) {
// Ensure typos get diagnosed when errors were encountered while parsing the
// expression list.
for (auto &E : Exprs) {
ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
if (Expr.isUsable()) E = Expr.get();
}
}
return SawError;
}
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,

View File

@ -423,9 +423,11 @@ ExprResult Parser::ParseBraceInitializer() {
if (Tok.is(tok::ellipsis))
SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
SubElt = Actions.CorrectDelayedTyposInExpr(SubElt.get());
// If we couldn't parse the subelement, bail out.
if (!SubElt.isInvalid()) {
if (SubElt.isUsable()) {
InitExprs.push_back(SubElt.get());
} else {
InitExprsOk = false;

View File

@ -2350,7 +2350,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
}
// Otherwise, an arbitrary expression can be the receiver of a send.
ExprResult Res(ParseExpression());
ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square, StopAtSemi);
return Res;
@ -2509,6 +2509,8 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation commaLoc = ConsumeToken(); // Eat the ','.
/// Parse the expression after ','
ExprResult Res(ParseAssignmentExpression());
if (Tok.is(tok::colon))
Res = Actions.CorrectDelayedTyposInExpr(Res);
if (Res.isInvalid()) {
if (Tok.is(tok::colon)) {
Diag(commaLoc, diag::note_extra_comma_message_arg) <<

View File

@ -715,7 +715,8 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
Tok.isNot(tok::annot_pragma_openmp_end))) {
ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
// Parse variable
ExprResult VarExpr = ParseAssignmentExpression();
ExprResult VarExpr =
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (VarExpr.isUsable()) {
Vars.push_back(VarExpr.get());
} else {

View File

@ -774,7 +774,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
// Read the parenthesized expression.
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ExprResult Res(ParseExpression());
ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
T.consumeClose();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);

View File

@ -2122,9 +2122,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
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 (DiagnoseEmptyLookup(S, SS, R,
CCC ? std::move(CCC) : std::move(DefaultValidator),
nullptr, None, &TE)) {
if (TE && KeywordReplacement) {
auto &State = getTypoExprState(TE);
auto BestTC = State.Consumer->getNextCorrection();
@ -4541,6 +4541,8 @@ static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) {
ExprResult result = S.CheckPlaceholderExpr(args[i]);
if (result.isInvalid()) hasInvalid = true;
else args[i] = result.get();
} else if (hasInvalid) {
(void)S.CorrectDelayedTyposInExpr(args[i]);
}
}
return hasInvalid;
@ -5763,6 +5765,15 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprObjectKind &OK,
SourceLocation QuestionLoc) {
if (!getLangOpts().CPlusPlus) {
// C cannot handle TypoExpr nodes on either side of a binop because it
// doesn't handle dependent types properly, so make sure any TypoExprs have
// been dealt with before checking the operands.
ExprResult CondResult = CorrectDelayedTyposInExpr(Cond);
if (!CondResult.isUsable()) return QualType();
Cond = CondResult;
}
ExprResult LHSResult = CheckPlaceholderExpr(LHS.get());
if (!LHSResult.isUsable()) return QualType();
LHS = LHSResult;
@ -8703,17 +8714,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
QualType CompoundType) {
assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
if (!getLangOpts().CPlusPlus) {
// C cannot handle TypoExpr nodes on either side of n assignment because it
// doesn't handle dependent types properly, so make sure any TypoExprs have
// been dealt with before checking the operands.
ExprResult Res = CorrectDelayedTyposInExpr(LHSExpr);
Expr *NewLHS = Res.isInvalid() ? LHSExpr : Res.get();
Res = CorrectDelayedTyposInExpr(RHS);
if (!Res.isInvalid() && (Res.get() != RHS.get() || NewLHS != LHSExpr))
return CheckAssignmentOperands(NewLHS, Res, Loc, CompoundType);
}
// Verify that LHS is a modifiable lvalue, and emit error if not.
if (CheckForModifiableLvalue(LHSExpr, Loc, *this))
return QualType();
@ -9447,6 +9447,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
if (!getLangOpts().CPlusPlus) {
// C cannot handle TypoExpr nodes on either side of a binop because it
// 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);
if (!LHS.isUsable() || !RHS.isUsable())
return ExprError();
}
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@ -13619,6 +13629,15 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
/// Check for operands with placeholder types and complain if found.
/// Returns true if there was an error and no recovery was possible.
ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
if (!getLangOpts().CPlusPlus) {
// C cannot handle TypoExpr nodes on either side of a binop because it
// doesn't handle dependent types properly, so make sure any TypoExprs have
// been dealt with before checking the operands.
ExprResult Result = CorrectDelayedTyposInExpr(E);
if (!Result.isUsable()) return ExprError();
E = Result.get();
}
const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType();
if (!placeholderType) return E;

View File

@ -1676,11 +1676,16 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
if (!collection)
return ExprError();
ExprResult result = CorrectDelayedTyposInExpr(collection);
if (!result.isUsable())
return ExprError();
collection = result.get();
// Bail out early if we've got a type-dependent expression.
if (collection->isTypeDependent()) return collection;
// Perform normal l-value conversion.
ExprResult result = DefaultFunctionArrayLvalueConversion(collection);
result = DefaultFunctionArrayLvalueConversion(collection);
if (result.isInvalid())
return ExprError();
collection = result.get();

View File

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
//
// This file contains typo correction tests which hit different code paths in C
// than in C++ and may exhibit different behavior as a result.
__typeof__(struct F*) var[invalid]; // expected-error-re {{use of undeclared identifier 'invalid'{{$}}}}