From: Kaelyn Takata Date: Fri, 21 Nov 2014 18:48:04 +0000 (+0000) Subject: Enable ActOnIdExpression to use delayed typo correction for non-C++ code X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1586782767938df3a20f7abc4d8335c48b100bc4;p=platform%2Fupstream%2Fllvm.git Enable ActOnIdExpression to use delayed typo correction for non-C++ code when calling DiagnoseEmptyLookup. llvm-svn: 222551 --- diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 518197e..fbf3337 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -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()) { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 3d57ba9..43929c0 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -910,6 +910,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, auto Validator = llvm::make_unique( 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 &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, diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index 8536420..7fe9862 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -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; diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 0d0f110..f9cfcfe 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -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) << diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 7851c40..764619a 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -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 { diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index 6f89953..7bf4da6 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -774,7 +774,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl &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); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index dc02f4e..fd7c761 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 0b9608a..14f7092 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -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(); diff --git a/clang/test/Sema/typo-correction.c b/clang/test/Sema/typo-correction.c new file mode 100644 index 0000000..e98e5c0 --- /dev/null +++ b/clang/test/Sema/typo-correction.c @@ -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'{{$}}}}