Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h	(revision 74890)
+++ include/clang/Parse/Action.h	(working copy)
@@ -235,6 +235,14 @@
     return 0; 
   }
 
+  virtual bool ActOnCXXEnterMemberScope(Scope *S, ExprArg &exp) {
+    return false;
+  }
+
+  virtual void ActOnCXXExitMemberScope(Scope *S, ExprArg &exp,
+                                       CXXScopeSpec &SS) {
+  }
+
   /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
   /// scope or nested-name-specifier) is parsed, part of a declarator-id.
   /// After this method is called, according to [C++ 3.4.3p3], names should be
@@ -773,7 +781,8 @@
                                                     tok::TokenKind OpKind,
                                                     SourceLocation MemberLoc,
                                                     IdentifierInfo &Member,
-                                                    DeclPtrTy ObjCImpDecl) {
+                                                    DeclPtrTy ObjCImpDecl,
+                                                const CXXScopeSpec *SS = 0) {
     return ExprEmpty();
   }
 
Index: lib/Frontend/PrintParserCallbacks.cpp
===================================================================
--- lib/Frontend/PrintParserCallbacks.cpp	(revision 74890)
+++ lib/Frontend/PrintParserCallbacks.cpp	(working copy)
@@ -531,7 +531,8 @@
                                                       tok::TokenKind OpKind,
                                                       SourceLocation MemberLoc,
                                                       IdentifierInfo &Member,
-                                                      DeclPtrTy ImplDecl) {
+                                                      DeclPtrTy ImplDecl,
+                                                      const CXXScopeSpec *SS=0) {
       Out << __FUNCTION__ << "\n";
       return ExprEmpty();
     }
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h	(revision 74890)
+++ lib/Sema/Sema.h	(working copy)
@@ -1462,7 +1462,8 @@
                                                     tok::TokenKind OpKind,
                                                     SourceLocation MemberLoc,
                                                     IdentifierInfo &Member,
-                                                    DeclPtrTy ImplDecl);
+                                                    DeclPtrTy ImplDecl,
+                                                    const CXXScopeSpec *SS = 0);
   bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
                                FunctionDecl *FDecl,
                                const FunctionProtoType *Proto,
@@ -1821,6 +1822,9 @@
                                                   SourceRange TypeRange,
                                                   SourceLocation CCLoc);
 
+  virtual bool ActOnCXXEnterMemberScope(Scope *S,ExprArg &exp);
+  virtual void ActOnCXXExitMemberScope(Scope *S,ExprArg &exp,CXXScopeSpec &SS);
+
   /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
   /// scope or nested-name-specifier) is parsed, part of a declarator-id.
   /// After this method is called, according to [C++ 3.4.3p3], names should be
Index: lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- lib/Sema/SemaCXXScopeSpec.cpp	(revision 74890)
+++ lib/Sema/SemaCXXScopeSpec.cpp	(working copy)
@@ -14,6 +14,7 @@
 #include "Sema.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/Parse/DeclSpec.h"
 #include "llvm/ADT/STLExtras.h"
@@ -278,6 +279,65 @@
                                      T.getTypePtr());
 }
 
+bool Sema::ActOnCXXEnterMemberScope(Scope *S, ExprArg &Base) {
+  Expr *BaseExpr = static_cast<Expr*>(Base.get());
+  if(BaseExpr == 0)
+    return false;
+
+  QualType BaseType = BaseExpr->getType();
+  if (BaseExpr->getType()->isPointerType())
+    BaseType = BaseType->getAsPointerType()->getPointeeType();
+
+  if (BaseType->isDependentType()) {
+    // FIXME: handle dependent types
+    return false;
+  } else if (!BaseType->isRecordType()) {
+    Diag(BaseExpr->getExprLoc(), 
+         diag::err_typecheck_member_reference_struct_union)
+      << BaseType << BaseExpr->getSourceRange();
+    return false;
+  }
+
+  CXXScopeSpec SS;
+  SS.setRange(BaseExpr->getSourceRange());
+  SS.setScopeRep(
+    NestedNameSpecifier::Create(Context, 0, false, BaseType.getTypePtr())
+    );
+
+  ActOnCXXEnterDeclaratorScope(S,SS);
+  return true;
+}
+
+void Sema::ActOnCXXExitMemberScope(Scope *S, ExprArg &Base, CXXScopeSpec &SS) {
+  ExitDeclaratorContext(S);
+
+  Expr *BaseExpr = static_cast<Expr*>(Base.get());
+  assert(BaseExpr && "Unable to look up base expression");
+
+  QualType BaseType = BaseExpr->getType();
+  if (BaseExpr->getType()->isPointerType())
+    BaseType = BaseType->getAsPointerType()->getPointeeType();
+
+  RecordDecl *Rec = BaseType->getAsRecordType()->getDecl();
+
+  if (SS.isSet()) {
+    NestedNameSpecifier *Prefix
+      = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+    assert(Prefix && Prefix->getKind() == NestedNameSpecifier::TypeSpec
+      && "Nested name specifier does not name a type");
+
+    Type *T = Prefix->getAsType();
+    DeclarationName Name = T->getAsRecordType()->getDecl()->getDeclName();
+    LookupResult Result = LookupQualifiedName(Rec, Name, LookupMemberName,
+                                              false);
+    if (!Result.getAsDecl()) {
+      Diag(SS.getBeginLoc(), diag::err_not_direct_base_or_virtual)
+        << Name.getAsIdentifierInfo() << BaseType;
+    }
+  }
+}
+
+
 /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
 /// scope or nested-name-specifier) is parsed, part of a declarator-id.
 /// After this method is called, according to [C++ 3.4.3p3], names should be
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 74890)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -2067,7 +2067,11 @@
 Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
                                tok::TokenKind OpKind, SourceLocation MemberLoc,
                                IdentifierInfo &Member,
-                               DeclPtrTy ObjCImpDecl) {
+                               DeclPtrTy ObjCImpDecl,const CXXScopeSpec *SS) {
+  // FIXME: handle the CXXScopeSpec for proper lookup of qualified-ids
+  if (SS && SS->isInvalid())
+    return ExprError();
+
   Expr *BaseExpr = Base.takeAs<Expr>();
   assert(BaseExpr && "no record expression");
 
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp	(revision 74890)
+++ lib/Parse/ParseExpr.cpp	(working copy)
@@ -915,6 +915,14 @@
       tok::TokenKind OpKind = Tok.getKind();
       SourceLocation OpLoc = ConsumeToken();  // Eat the "." or "->" token.
 
+      CXXScopeSpec SS;
+      if (getLang().CPlusPlus) {
+        if( !Actions.ActOnCXXEnterMemberScope(CurScope,LHS) )
+          return ExprError();
+        ParseOptionalCXXScopeSpecifier(SS);
+        Actions.ActOnCXXExitMemberScope(CurScope,LHS,SS);
+      }
+
       if (Tok.isNot(tok::identifier)) {
         Diag(Tok, diag::err_expected_ident);
         return ExprError();
@@ -924,7 +932,7 @@
         LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
                                                OpKind, Tok.getLocation(),
                                                *Tok.getIdentifierInfo(),
-                                               ObjCImpDecl);
+                                               ObjCImpDecl, &SS);
       }
       ConsumeToken();
       break;
