From b11b40a67ef9847447d3066fad06698dd9c317d2 Mon Sep 17 00:00:00 2001 From: Kaelyn Takata Date: Thu, 20 Nov 2014 22:06:40 +0000 Subject: [PATCH] Wire up delayed typo correction to DiagnoseEmptyLookup and set up Sema::ActOnIdExpression to use the new functionality. Among other things, this allows recovery in several cases where it wasn't possible before (e.g. correcting a mistyped static_cast<>). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@222464 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 11 ++++ 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 | 51 +++++++++------ lib/Parse/ParseObjc.cpp | 5 +- lib/Parse/ParseOpenMP.cpp | 3 +- lib/Parse/ParseStmt.cpp | 7 +- lib/Sema/SemaExpr.cpp | 96 +++++++++++++++++++++++++--- 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, 197 insertions(+), 49 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9a29edb722..38073c37c7 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. @@ -1396,6 +1405,8 @@ private: //===--------------------------------------------------------------------===// // C++ Expressions + ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, + Token &Replacement); ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); bool areTokensAdjacent(const Token &A, const Token &B); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a70b6c3afa..8b13b9d32a 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 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 CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, - ArrayRef Args = None); + ArrayRef 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 2a2f3b1046..8469fb9691 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 9266644c59..f84b4dae8d 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 91c1372c63..79ae878520 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 b4ba0bc8d8..3d57ba9cbe 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(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( 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 fbe5de1416..613246ef71 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -567,6 +567,28 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } +ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, + Token &Replacement) { + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/ParsedType(), TemplateKWLoc, Name)) + return ExprError(); + + // This is only the direct operand of an & operator if it is not + // followed by a postfix-expression suffix. + if (isAddressOfOperand && isPostfixExpressionSuffixStart()) + isAddressOfOperand = false; + + return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name, + Tok.is(tok::l_paren), isAddressOfOperand, + nullptr, /*IsInlineAsmIdentifier=*/false, + &Replacement); +} + /// ParseCXXIdExpression - Handle id-expression. /// /// id-expression: @@ -617,24 +639,17 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); - SourceLocation TemplateKWLoc; - UnqualifiedId Name; - if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/false, - /*AllowConstructorName=*/false, - /*ObjectType=*/ ParsedType(), - TemplateKWLoc, - Name)) - return ExprError(); - - // This is only the direct operand of an & operator if it is not - // followed by a postfix-expression suffix. - if (isAddressOfOperand && isPostfixExpressionSuffixStart()) - isAddressOfOperand = false; - - return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name, - Tok.is(tok::l_paren), isAddressOfOperand); + Token Replacement; + ExprResult Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); + if (Result.isUnset()) { + // If the ExprResult is valid but null, then typo correction suggested a + // keyword replacement that needs to be reparsed. + UnconsumeToken(Replacement); + Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); + } + assert(!Result.isUnset() && "Typo correction suggested a keyword replacement " + "for a previous keyword suggestion"); + return Result; } /// ParseLambdaExpression - Parse a C++11 lambda expression. diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index ad1cbff482..0d0f110989 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 3a119a601e..7851c401ce 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 3bf66c3f2e..1bfce60a3b 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 22657ba369..dc02f4ecc2 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 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(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 CCC, TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef Args) { + ArrayRef 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 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(); + TypoExpr *TE = nullptr; + auto DefaultValidator = llvm::make_unique( + 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"); @@ -12450,6 +12528,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 0d2d6032dd..0b9608a98e 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) { + 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. @@ -388,7 +405,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, } } - auto LHS = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false, + LHS = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false, getLangOpts().CPlusPlus11); if (LHS.isInvalid()) return StmtError(); diff --git a/test/FixIt/fixit-unrecoverable.cpp b/test/FixIt/fixit-unrecoverable.cpp index 1e1f1b8db2..f555792ed3 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(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(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 a4f517436a..4f1928365f 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::*)() const); + void g(void(*)()); // expected-note{{candidate function not viable}} + void g(bool(S::*)() const); // expected-note{{candidate function not viable}} void test() { - g(&S::tempalte f); // expected-error{{did you mean 'template'?}} + g(&S::tempalte f); // expected-error{{did you mean 'template'?}} \ + // expected-error{{no matching function for call to 'g'}} g(&S::opeartor bool); // expected-error{{did you mean 'operator'?}} g(&S::foo); // expected-error{{no member named 'foo' in 'PR13051::S'; did you mean simply 'foo'?}} } diff --git a/test/SemaTemplate/crash-10438657.cpp b/test/SemaTemplate/crash-10438657.cpp index 2ee64bdfcd..3eaa8c1ea7 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 class collate : public locale::facet { -- 2.40.0