diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6152,8 +6152,12 @@ /// TypoExpr - Internal placeholder for expressions where typo correction /// still needs to be performed and/or an error diagnostic emitted. class TypoExpr : public Expr { + // The location for the typo name. + SourceLocation TypoLoc; + public: - TypoExpr(QualType T) : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary) { + TypoExpr(QualType T, SourceLocation TypoLoc) + : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary), TypoLoc(TypoLoc) { assert(T->isDependentType() && "TypoExpr given a non-dependent type"); setDependence(ExprDependence::TypeValueInstantiation | ExprDependence::Error); @@ -6166,8 +6170,8 @@ return const_child_range(const_child_iterator(), const_child_iterator()); } - SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return TypoLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return TypoLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == TypoExprClass; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3695,7 +3695,7 @@ /// Creates a new TypoExpr AST node. TypoExpr *createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, - TypoRecoveryCallback TRC); + TypoRecoveryCallback TRC, SourceLocation TypoLoc); // The set of known/encountered (unique, canonicalized) NamespaceDecls. // diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8307,8 +8307,6 @@ if (FullExpr.isInvalid()) { // Typo-correction fails, we rebuild the broken AST with the typos degraded // to RecoveryExpr. - // FIXME: we lose source locations for RecoveryExpr, as TypoExpr doesn't - // track source locations. struct TyposReplace : TreeTransform { TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {} ExprResult TransformTypoExpr(TypoExpr *E) { diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -5167,9 +5167,9 @@ IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3) return nullptr; - ExprEvalContexts.back().NumTypos++; - return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC)); + return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC), + TypoName.getLoc()); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { @@ -5481,9 +5481,10 @@ TypoExpr *Sema::createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, - TypoRecoveryCallback TRC) { + TypoRecoveryCallback TRC, + SourceLocation TypoLoc) { assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer"); - auto TE = new (Context) TypoExpr(Context.DependentTy); + auto TE = new (Context) TypoExpr(Context.DependentTy, TypoLoc); auto &State = DelayedTypos[TE]; State.Consumer = std::move(TCC); State.DiagHandler = std::move(TDG); diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -13,9 +13,9 @@ void test_invalid_call(int s) { // CHECK: CallExpr {{.*}} '' contains-errors // CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' - // CHECK-NEXT: |-RecoveryExpr {{.*}} <> - // CHECK-NEXT: `-BinaryOperator {{.*}} <, col:28> - // CHECK-NEXT: |-RecoveryExpr {{.*}} <> + // CHECK-NEXT: |-RecoveryExpr {{.*}} + // CHECK-NEXT: `-BinaryOperator {{.*}} + // CHECK-NEXT: |-RecoveryExpr {{.*}} // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 some_func(undef1, undef2+1);