Rewrite of our handling of name lookup in C++ member access expressions, e.g.,

  x->Base::f

We no longer try to "enter" the context of the type that "x" points
to. Instead, we drag that object type through the parser and pass it
into the Sema routines that need to know how to perform lookup within
member access expressions.

We now implement most of the crazy name lookup rules in C++
[basic.lookup.classref] for non-templated code, including performing
lookup both in the context of the type referred to by the member
access and in the scope of the member access itself and then detecting
ambiguities when the two lookups collide (p1 and p4; p3 and p7 are
still TODO). This change also corrects our handling of name lookup
within template arguments of template-ids inside the
nested-name-specifier (p6; we used to look into the scope of the
object expression for them) and fixes PR4703.

I have disabled some tests that involve member access expressions
where the object expression has dependent type, because we don't yet
have the ability to describe dependent nested-name-specifiers starting
with an identifier.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80843 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index ee23c00..d89cc8c 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -160,8 +160,11 @@
 }
 
 TemplateNameKind 
-MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
+MinimalAction::isTemplateName(Scope *S,
+                              const IdentifierInfo &II,
+                              SourceLocation IdLoc,
                               const CXXScopeSpec *SS,
+                              TypeTy *ObjectType,                              
                               bool EnteringScope,
                               TemplateTy &TemplateDecl) {
   return TNK_Non_template;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 25bed09..25ff53c 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -743,7 +743,7 @@
             ->Kind == TNK_Type_template) {
         // We have a qualified template-id, e.g., N::A<int>
         CXXScopeSpec SS;
-        ParseOptionalCXXScopeSpecifier(SS, true);
+        ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
         assert(Tok.is(tok::annot_template_id) && 
                "ParseOptionalCXXScopeSpecifier not working");
         AnnotateTemplateIdTokenAsType(&SS);
@@ -1596,7 +1596,7 @@
     Attr = ParseAttributes();
 
   CXXScopeSpec SS;
-  if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
+  if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
     if (Tok.isNot(tok::identifier)) {
       Diag(Tok, diag::err_expected_ident);
       if (Tok.isNot(tok::l_brace)) {
@@ -2034,7 +2034,7 @@
       (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
        Tok.is(tok::annot_cxxscope))) {
     CXXScopeSpec SS;
-    if (ParseOptionalCXXScopeSpecifier(SS, true)) {
+    if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) {
       if(Tok.isNot(tok::star)) {
         // The scope spec really belongs to the direct-declarator.
         D.getCXXScopeSpec() = SS;
@@ -2191,7 +2191,8 @@
     if (D.mayHaveIdentifier()) {
       // ParseDeclaratorInternal might already have parsed the scope.
       bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
-        ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), true);
+        ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, 
+                                       true);
       if (afterCXXScope) {
         // Change the declaration context for name lookup, until this function
         // is exited (and the declarator has been parsed).
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 31926ce..f50147c 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -117,7 +117,7 @@
   
   CXXScopeSpec SS;
   // Parse (optional) nested-name-specifier.
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
   if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
     Diag(Tok, diag::err_expected_namespace_name);
@@ -216,7 +216,7 @@
 
   CXXScopeSpec SS;
   // Parse (optional) nested-name-specifier.
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
   AttributeList *AttrList = 0;
   IdentifierInfo *NamespcName = 0;
@@ -273,7 +273,7 @@
     IsTypeName = false;
 
   // Parse nested-name-specifier.
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
   AttributeList *AttrList = 0;
 
@@ -538,7 +538,8 @@
   
   // Parse the (optional) nested-name-specifier.
   CXXScopeSpec SS;
-  if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, true))
+  if (getLang().CPlusPlus && 
+      ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true))
     if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
       Diag(Tok, diag::err_expected_ident);
 
@@ -813,7 +814,7 @@
 
   // Parse optional '::' and optional nested-name-specifier.
   CXXScopeSpec SS;
-  ParseOptionalCXXScopeSpecifier(SS, true);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
 
   // The location of the base class itself.
   SourceLocation BaseLoc = Tok.getLocation();
@@ -1299,7 +1300,7 @@
 Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
   // parse '::'[opt] nested-name-specifier[opt]
   CXXScopeSpec SS;
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
   TypeTy *TemplateTypeTy = 0;
   if (Tok.is(tok::annot_template_id)) {
     TemplateIdAnnotation *TemplateId
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 36b6dd4..8fca14f 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -923,14 +923,14 @@
       tok::TokenKind OpKind = Tok.getKind();
       SourceLocation OpLoc = ConsumeToken();  // Eat the "." or "->" token.
 
-      CXXScopeSpec MemberSS;
       CXXScopeSpec SS;
+      Action::TypeTy *ObjectType = 0;
       if (getLang().CPlusPlus && !LHS.isInvalid()) {
-        LHS = Actions.ActOnCXXEnterMemberScope(CurScope, MemberSS, move(LHS),
-                                               OpKind);
+        LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS),
+                                                   OpLoc, OpKind, ObjectType);
         if (LHS.isInvalid())
           break;
-        ParseOptionalCXXScopeSpecifier(SS);
+        ParseOptionalCXXScopeSpecifier(SS, ObjectType, false);
       }
 
       if (Tok.is(tok::identifier)) {
@@ -947,8 +947,6 @@
         ConsumeToken();
         
         if (!Tok.is(tok::identifier)) {
-          if (getLang().CPlusPlus)
-            Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
           Diag(Tok, diag::err_expected_ident);
           return ExprError();
         }
@@ -980,8 +978,6 @@
                                                            Tok.getLocation(),
                                                                ConvType, &SS);
         } else {
-          if (getLang().CPlusPlus)
-            Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
           // Don't emit a diagnostic; ParseConversionFunctionId does it for us
           return ExprError();
         }
@@ -1007,14 +1003,9 @@
         }
         ConsumeToken();
       } else {
-        if (getLang().CPlusPlus)
-          Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
         Diag(Tok, diag::err_expected_ident);
         return ExprError();
       }
-
-      if (getLang().CPlusPlus)
-        Actions.ActOnCXXExitMemberScope(CurScope, MemberSS);
       break;
     }
     case tok::plusplus:    // postfix-expression: postfix-expression '++'
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index e9cca9f..4cd952e 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -16,10 +16,11 @@
 #include "clang/Parse/DeclSpec.h"
 using namespace clang;
 
-/// ParseOptionalCXXScopeSpecifier - Parse global scope or
-/// nested-name-specifier if present.  Returns true if a nested-name-specifier
-/// was parsed from the token stream.  Note that this routine will not parse
-/// ::new or ::delete, it will just leave them in the token stream.
+/// \brief Parse global scope or nested-name-specifier if present. 
+///
+/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
+/// may be preceded by '::'). Note that this routine will not parse ::new or 
+/// ::delete; it will just leave them in the token stream.
 ///
 ///       '::'[opt] nested-name-specifier
 ///       '::'
@@ -28,9 +29,22 @@
 ///         type-name '::'
 ///         namespace-name '::'
 ///         nested-name-specifier identifier '::'
-///         nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+///         nested-name-specifier 'template'[opt] simple-template-id '::'
 ///
+///
+/// \param SS the scope specifier that will be set to the parsed 
+/// nested-name-specifier (or empty)
+///
+/// \param ObjectType if this nested-name-specifier is being parsed following 
+/// the "." or "->" of a member access expression, this parameter provides the
+/// type of the object whose members are being accessed.
+///
+/// \param EnteringContext whether we will be entering into the context of
+/// the nested-name-specifier after parsing it.
+///
+/// \returns true if a scope specifier was parsed.
 bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
+                                            Action::TypeTy *ObjectType,
                                             bool EnteringContext) {
   assert(getLang().CPlusPlus &&
          "Call sites of this function should be guarded by checking for C++");
@@ -59,16 +73,28 @@
   }
 
   while (true) {
+    if (HasScopeSpecifier) {
+      // C++ [basic.lookup.classref]p5:
+      //   If the qualified-id has the form
+      //       ::class-name-or-namespace-name::...
+      //   the class-name-or-namespace-name is looked up in global scope as a
+      //   class-name or namespace-name.
+      //
+      // To implement this, we clear out the object type as soon as we've
+      // seen a leading '::' or part of a nested-name-specifier.
+      ObjectType = 0;
+    }
+    
     // nested-name-specifier:
     //   nested-name-specifier 'template'[opt] simple-template-id '::'
 
     // Parse the optional 'template' keyword, then make sure we have
     // 'identifier <' after it.
     if (Tok.is(tok::kw_template)) {
-      // If we don't have a scope specifier, this isn't a
+      // If we don't have a scope specifier or an object type, this isn't a
       // nested-name-specifier, since they aren't allowed to start with
       // 'template'.
-      if (!HasScopeSpecifier)
+      if (!HasScopeSpecifier && !ObjectType)
         break;
 
       SourceLocation TemplateKWLoc = ConsumeToken();
@@ -91,7 +117,8 @@
       TemplateTy Template 
         = Actions.ActOnDependentTemplateName(TemplateKWLoc,
                                              *Tok.getIdentifierInfo(),
-                                             Tok.getLocation(), SS);
+                                             Tok.getLocation(), SS,
+                                             ObjectType);
       if (!Template)
         break;
       if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
@@ -173,7 +200,7 @@
       
       SS.setScopeRep(
         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II,
-                                            EnteringContext));
+                                            ObjectType, EnteringContext));
       SS.setEndLoc(CCLoc);
       continue;
     }
@@ -182,7 +209,10 @@
     //   type-name '<'
     if (Next.is(tok::less)) {
       TemplateTy Template;
-      if (TemplateNameKind TNK = Actions.isTemplateName(II, CurScope, &SS,
+      if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II,
+                                                        Tok.getLocation(),
+                                                        &SS,
+                                                        ObjectType,
                                                         EnteringContext,
                                                         Template)) {
         // We have found a template name, so annotate this this token
@@ -267,7 +297,7 @@
   //   '::' unqualified-id
   //
   CXXScopeSpec SS;
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
   // unqualified-id:
   //   identifier
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 4d37ac7..36d5db5 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -884,7 +884,8 @@
     //            simple-template-id
     SourceLocation TypenameLoc = ConsumeToken();
     CXXScopeSpec SS;
-    bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS, false);
+    bool HadNestedNameSpecifier 
+      = ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
     if (!HadNestedNameSpecifier) {
       Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
       return false;
@@ -928,7 +929,7 @@
 
   CXXScopeSpec SS;
   if (getLang().CPlusPlus)
-    ParseOptionalCXXScopeSpecifier(SS, EnteringContext);
+    ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext);
 
   if (Tok.is(tok::identifier)) {
     // Determine whether the identifier is a type name.
@@ -959,8 +960,10 @@
     if (NextToken().is(tok::less)) {
       TemplateTy Template;
       if (TemplateNameKind TNK 
-            = Actions.isTemplateName(*Tok.getIdentifierInfo(),
-                                     CurScope, &SS, EnteringContext, Template))
+            = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(), 
+                                     Tok.getLocation(), &SS, 
+                                     /*ObjectType=*/0, EnteringContext, 
+                                     Template))
         if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
           // If an unrecoverable error occurred, we need to return true here,
           // because the token stream is in a damaged state.  We may not return
@@ -1022,7 +1025,7 @@
          "Cannot be a type or scope token!");
 
   CXXScopeSpec SS;
-  if (!ParseOptionalCXXScopeSpecifier(SS, EnteringContext))
+  if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext))
     return Tok.is(tok::annot_template_id);
 
   // Push the current token back into the token stream (or revert it if it is