diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2100,8 +2100,14 @@ OpKind, SS, TemplateKWLoc, Name, CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr); - if (!LHS.isInvalid() && Tok.is(tok::less)) - checkPotentialAngleBracket(LHS); + if (!LHS.isInvalid()) { + if (Tok.is(tok::less)) + checkPotentialAngleBracket(LHS); + } else if (OrigLHS && Name.isValid()) { + // Preserve the member expr if the LHS is an invalid members. + LHS = Actions.CreateRecoveryExpr(OrigLHS->getBeginLoc(), + Name.getEndLoc(), {OrigLHS}); + } break; } case tok::plusplus: // postfix-expression: postfix-expression '++' 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 @@ -83,3 +83,18 @@ // CHECK-NEXT: `-DeclRefExpr {{.*}} 'a' // DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors int ternary = a ? nullptr : a; + +// CHECK: FunctionDecl +// CHECK-NEXT:|-ParmVarDecl {{.*}} x +// CHECK-NEXT:`-CompoundStmt +// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'foo' +// CHECK-NEXT: `-CallExpr {{.*}} contains-errors +// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'foo' +// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' +struct Foo {} foo; +void test(int x) { + foo.abc; + foo->func(x); +} \ No newline at end of file diff --git a/clang/test/SemaCXX/constructor-initializer.cpp b/clang/test/SemaCXX/constructor-initializer.cpp --- a/clang/test/SemaCXX/constructor-initializer.cpp +++ b/clang/test/SemaCXX/constructor-initializer.cpp @@ -250,7 +250,7 @@ B(const String& s, int e=0) // expected-error {{unknown type name}} : A(e), m_String(s) , m_ErrorStr(__null) {} // expected-error {{no matching constructor}} expected-error {{does not name}} B(const B& e) - : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error {{does not name}} \ + : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error 2{{does not name}} \ // expected-error {{no member named 'm_String' in 'test3::B'}} } };