]> granicus.if.org Git - clang/commitdiff
Rewrite of our handling of name lookup in C++ member access expressions, e.g.,
authorDouglas Gregor <dgregor@apple.com>
Wed, 2 Sep 2009 22:59:36 +0000 (22:59 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 2 Sep 2009 22:59:36 +0000 (22:59 +0000)
  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

18 files changed:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Action.h
include/clang/Parse/Parser.h
lib/Parse/MinimalAction.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/Parser.cpp
lib/Sema/Sema.h
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/TreeTransform.h
test/SemaCXX/nested-name-spec.cpp
test/SemaCXX/qual-id-test.cpp
test/SemaTemplate/member-function-template.cpp

index e29e6ab4c773963ba18ddb483fbef767e23891da..a5d318eb255c140417190fad2fca6890ba45d5f1 100644 (file)
@@ -366,6 +366,12 @@ def note_previous_access_declaration : Note<
 // C++ name lookup
 def err_incomplete_nested_name_spec : Error<
   "incomplete type %0 named in nested name specifier">;
+def err_nested_name_member_ref_lookup_ambiguous : Error<
+  "lookup of %0 in member access expression is ambiguous">;
+def note_ambig_member_ref_object_type : Note<
+  "lookup in the object type %0 refers here">;
+def note_ambig_member_ref_scope : Note<
+  "lookup from the current scope refers here">;
 
 // C++ class members
 def err_storageclass_invalid_for_member : Error<
index 0c70441083da710d25f11c14cb2bc2c97883356a..31acc87cb40a8fcb4a756ef351f4295c6da274b3 100644 (file)
@@ -209,10 +209,12 @@ public:
   /// \brief Determine whether the given identifier refers to the name of a
   /// template.
   ///
+  /// \param S the scope in which name lookup occurs
+  ///
   /// \param II the identifier that we are querying to determine whether it
   /// is a template.
   ///
-  /// \param S the scope in which name lookup occurs
+  /// \param IdLoc the source location of the identifier
   ///
   /// \param SS the C++ scope specifier that precedes the template name, if
   /// any.
@@ -224,8 +226,11 @@ public:
   /// of the template that the name refers to.
   ///
   /// \returns the kind of template that this name refers to.
-  virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+  virtual TemplateNameKind isTemplateName(Scope *S,
+                                          const IdentifierInfo &II, 
+                                          SourceLocation IdLoc,
                                           const CXXScopeSpec *SS,
+                                          TypeTy *ObjectType,
                                           bool EnteringContext,
                                           TemplateTy &Template) = 0;
 
@@ -236,17 +241,39 @@ public:
     return 0;
   }
 
-  /// ActOnCXXNestedNameSpecifier - Called during parsing of a
-  /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
-  /// we want to resolve "bar::". 'SS' is empty or the previously parsed
-  /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
-  /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
-  /// Returns a CXXScopeTy* object representing the C++ scope.
+  /// \brief Parsed an identifier followed by '::' in a C++
+  /// nested-name-specifier.
+  ///
+  /// \param S the scope in which the nested-name-specifier was parsed.
+  ///
+  /// \param SS the nested-name-specifier that precedes the identifier. For
+  /// example, if we are parsing "foo::bar::", \p SS will describe the "foo::"
+  /// that has already been parsed.
+  ///
+  /// \param IdLoc the location of the identifier we have just parsed (e.g.,
+  /// the "bar" in "foo::bar::".
+  ///
+  /// \param CCLoc the location of the '::' at the end of the 
+  /// nested-name-specifier.
+  ///
+  /// \param II the identifier that represents the scope that this 
+  /// nested-name-specifier refers to, e.g., the "bar" in "foo::bar::".
+  ///
+  /// \param ObjectType if this nested-name-specifier occurs as part of a 
+  /// C++ member access expression such as "x->Base::f", the type of the base
+  /// object (e.g., *x in the example, if "x" were a pointer).
+  /// 
+  /// \param EnteringContext if true, then we intend to immediately enter the
+  /// context of this nested-name-specifier, e.g., for an out-of-line 
+  /// definition of a class member.
+  ///
+  /// \returns a CXXScopeTy* object representing the C++ scope.
   virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
                                                   const CXXScopeSpec &SS,
                                                   SourceLocation IdLoc,
                                                   SourceLocation CCLoc,
                                                   IdentifierInfo &II,
+                                                  TypeTy *ObjectType,
                                                   bool EnteringContext) {
     return 0;
   }
@@ -267,27 +294,6 @@ public:
     return 0; 
   }
 
-  /// ActOnCXXEnterMemberScope - Called when a C++ class member accessor ('.'
-  /// or '->') is parsed. After this method is called, according to
-  /// [C++ 3.4.5p4], qualified-ids should be looked up in the contexts of both
-  /// the entire postfix-expression and the scope of the class of the object
-  /// expression.
-  /// 'SS' should be an empty CXXScopeSpec to be filled with the class's scope.
-  virtual OwningExprResult ActOnCXXEnterMemberScope(Scope *S,
-                                                    CXXScopeSpec &SS,
-                                                    ExprArg Base,
-                                                    tok::TokenKind OpKind) {
-    return ExprEmpty();
-  }
-
-  /// ActOnCXXExitMemberScope - Called when a postfix-expression that previously
-  /// invoked ActOnCXXEnterMemberScope() is finished. 'SS' is the same
-  /// CXXScopeSpec that was passed to ActOnCXXEnterMemberScope. Used to
-  /// indicate that names should revert to being looked up in the defining
-  /// scope.
-  virtual void ActOnCXXExitMemberScope(Scope *S, const 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
@@ -1280,6 +1286,31 @@ public:
     return ExprEmpty();
   }
 
+  /// \brief Invoked when the parser is starting to parse a C++ member access 
+  /// expression such as x.f or x->f.
+  ///
+  /// \param S the scope in which the member access expression occurs.
+  ///
+  /// \param Base the expression in which a member is being accessed, e.g., the
+  /// "x" in "x.f".
+  ///
+  /// \param OpLoc the location of the member access operator ("." or "->")
+  ///
+  /// \param OpKind the kind of member access operator ("." or "->")
+  ///
+  /// \param ObjectType originally NULL. The action should fill in this type
+  /// with the type into which name lookup should look to find the member in 
+  /// the member access expression.
+  ///
+  /// \returns the (possibly modified) \p Base expression
+  virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
+                                                        ExprArg Base,
+                                                        SourceLocation OpLoc,
+                                                        tok::TokenKind OpKind,
+                                                        TypeTy *&ObjectType) {
+    return ExprEmpty();
+  }
+  
   /// ActOnDestructorReferenceExpr - Parsed a destructor reference, for example:
   ///
   /// t->~T();
@@ -1597,10 +1628,26 @@ public:
   /// example, given "MetaFun::template apply", the scope specifier \p
   /// SS will be "MetaFun::", \p TemplateKWLoc contains the location
   /// of the "template" keyword, and "apply" is the \p Name.
+  ///
+  /// \param TemplateKWLoc the location of the "template" keyword (if any).
+  ///
+  /// \param Name the name of the template (an identifier)
+  ///
+  /// \param NameLoc the location of the identifier
+  ///
+  /// \param SS the nested-name-specifier that precedes the "template" keyword
+  /// or the template name. FIXME: If the dependent template name occurs in
+  /// a member access expression, e.g., "x.template f<T>", this 
+  /// nested-name-specifier will be empty.
+  ///
+  /// \param ObjectType if this dependent template name occurs in the 
+  /// context of a member access expression, the type of the object being
+  /// accessed.
   virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
                                                 const IdentifierInfo &Name,
                                                 SourceLocation NameLoc,
-                                                const CXXScopeSpec &SS) {
+                                                const CXXScopeSpec &SS,
+                                                TypeTy *ObjectType) {
     return TemplateTy();
   }
 
@@ -2128,26 +2175,11 @@ public:
   virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
                                   const CXXScopeSpec *SS);
 
-  /// \brief Determine whether the given identifier refers to the name of a
-  /// template.
-  ///
-  /// \param II the identifier that we are querying to determine whether it
-  /// is a template.
-  ///
-  /// \param S the scope in which name lookup occurs
-  ///
-  /// \param SS the C++ scope specifier that precedes the template name, if
-  /// any.
-  ///
-  /// \param EnteringContext whether we are potentially entering the context
-  /// referred to by the scope specifier \p SS
-  ///
-  /// \param Template if the name does refer to a template, the declaration
-  /// of the template that the name refers to.
-  ///
-  /// \returns the kind of template that this name refers to.
-  virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+  virtual TemplateNameKind isTemplateName(Scope *S,
+                                          const IdentifierInfo &II, 
+                                          SourceLocation IdLoc,
                                           const CXXScopeSpec *SS,
+                                          TypeTy *ObjectType,                              
                                           bool EnteringContext,
                                           TemplateTy &Template);
 
index e366c2f256997e9e43990d7fa4cfb744ecc039d8..641b09947b39c26eebe9b7b81672cafb652deab6 100644 (file)
@@ -770,13 +770,9 @@ private:
   // C++ Expressions
   OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
 
-  /// 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.
-  ///
   bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, 
-                                      bool EnteringContext = false);
+                                      TypeTy *ObjectType,
+                                      bool EnteringContext);
   
   //===--------------------------------------------------------------------===//
   // C++ 5.2p1: C++ Casts
index ee23c0038ac088ea8a141d4add3c94c8cbf0e9c9..d89cc8c3ea2940c57752f667b150fe3cbf754719 100644 (file)
@@ -160,8 +160,11 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
 }
 
 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;
index 25bed0937b678fd42a1b07709722185c7616cbe2..25ff53ca9f3c73f6cb2edaa703a4f8b0e7afa13b 100644 (file)
@@ -743,7 +743,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
             ->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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
     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 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
       (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 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
     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).
index 31926ce0f5cc02f6e7234a74f8c405eb70de1ba8..f50147c599a9d5444dd006b84b9e37759ebc5cf7 100644 (file)
@@ -117,7 +117,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
   
   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 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
 
   CXXScopeSpec SS;
   // Parse (optional) nested-name-specifier.
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
   AttributeList *AttrList = 0;
   IdentifierInfo *NamespcName = 0;
@@ -273,7 +273,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
     IsTypeName = false;
 
   // Parse nested-name-specifier.
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
   AttributeList *AttrList = 0;
 
@@ -538,7 +538,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
   
   // 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 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
 
   // 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 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
 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
index 36b6dd4a930e49bacfcf55a1eb05b5027f538ca7..8fca14ff98989a6a4d928525d2b7b49470e05b89 100644 (file)
@@ -923,14 +923,14 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
       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 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
         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 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
                                                            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 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
         }
         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 '++'
index e9cca9fe1d2f941291751cd4e089e2104a1ec2bb..4cd952e393f11d203836c1b7bbcf8047ea5af21d 100644 (file)
 #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 @@ using namespace clang;
 ///         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 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
   }
 
   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 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
       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 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
       
       SS.setScopeRep(
         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II,
-                                            EnteringContext));
+                                            ObjectType, EnteringContext));
       SS.setEndLoc(CCLoc);
       continue;
     }
@@ -182,7 +209,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
     //   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 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
   //   '::' unqualified-id
   //
   CXXScopeSpec SS;
-  ParseOptionalCXXScopeSpecifier(SS);
+  ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
   // unqualified-id:
   //   identifier
index 4d37ac7202a9350f95b453bcf2ef013f9dabb6ac..36d5db599d421841fc82c035c153f9c6ab6d5de4 100644 (file)
@@ -884,7 +884,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
     //            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 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
 
   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 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
     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 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
          "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
index e2205d6df54c3aa7e76d2a1973de431953dc3894..6f462e593b50f5ffaca670345b2a8fdc63c1d66e 100644 (file)
@@ -1983,6 +1983,12 @@ public:
                                                TypeTy *Ty,
                                                SourceLocation RParen);
   
+  virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
+                                                        ExprArg Base,
+                                                        SourceLocation OpLoc,
+                                                        tok::TokenKind OpKind,
+                                                        TypeTy *&ObjectType);
+    
   virtual OwningExprResult
   ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
                                SourceLocation OpLoc,
@@ -2029,6 +2035,7 @@ public:
 
   bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
   
+  DeclContext *computeDeclContext(QualType T);
   DeclContext *computeDeclContext(const CXXScopeSpec &SS, 
                                   bool EnteringContext = false);
   bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
@@ -2051,6 +2058,7 @@ public:
                                                   SourceLocation IdLoc,
                                                   SourceLocation CCLoc,
                                                   IdentifierInfo &II,
+                                                  TypeTy *ObjectType,
                                                   bool EnteringContext);
 
   /// ActOnCXXNestedNameSpecifier - Called during parsing of a
@@ -2067,23 +2075,6 @@ public:
                                                   SourceRange TypeRange,
                                                   SourceLocation CCLoc);
 
-  /// ActOnCXXEnterMemberScope - Called when a C++ class member accessor ('.'
-  /// or '->') is parsed. After this method is called, according to
-  /// [C++ 3.4.5p4], qualified-ids should be looked up in the contexts of both
-  /// the entire postfix-expression and the scope of the class of the object
-  /// expression.
-  /// 'SS' should be an empty CXXScopeSpec to be filled with the class's scope.
-  virtual OwningExprResult ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS,
-                                                    ExprArg Base,
-                                                    tok::TokenKind OpKind);
-
-  /// ActOnCXXExitMemberScope - Called when a postfix-expression that previously
-  /// invoked ActOnCXXEnterMemberScope() is finished. 'SS' is the same
-  /// CXXScopeSpec that was passed to ActOnCXXEnterMemberScope. Used to
-  /// indicate that names should revert to being looked up in the defining
-  /// scope.
-  virtual void ActOnCXXExitMemberScope(Scope *S, const 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
@@ -2311,8 +2302,11 @@ public:
   //===--------------------------------------------------------------------===//
   // C++ Templates [C++ 14]
   //
-  virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+  virtual TemplateNameKind isTemplateName(Scope *S,
+                                          const IdentifierInfo &II, 
+                                          SourceLocation IdLoc,
                                           const CXXScopeSpec *SS,
+                                          TypeTy *ObjectType,
                                           bool EnteringContext,
                                           TemplateTy &Template);
   bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
@@ -2400,7 +2394,8 @@ public:
   virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
                                                 const IdentifierInfo &Name,
                                                 SourceLocation NameLoc,
-                                                const CXXScopeSpec &SS);
+                                                const CXXScopeSpec &SS,
+                                                TypeTy *ObjectType);
 
   bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
                                     ClassTemplateSpecializationDecl *PrevDecl,
index d89a610caecb00ae10a4f867bfa610d038801c05..251ffea925c70a59e2573e610bce77e835aa2041 100644 (file)
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
+/// \brief Compute the DeclContext that is associated with the given type.
+///
+/// \param T the type for which we are attempting to find a DeclContext.
+///
+/// \returns the declaration context represented by the type T, 
+/// or NULL if the declaration context cannot be computed (e.g., because it is
+/// dependent and not the current instantiation).
+DeclContext *Sema::computeDeclContext(QualType T) {
+  if (const TagType *Tag = T->getAs<TagType>())
+    return Tag->getDecl();
+  
+  return 0;
+}
+
 /// \brief Compute the DeclContext that is associated with the given
 /// scope specifier.
 ///
@@ -244,6 +258,36 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
   return NestedNameSpecifier::GlobalSpecifier(Context);
 }
 
+/// \brief Determines whether the given declaration is an valid acceptable
+/// result for name lookup of a nested-name-specifier.
+bool isAcceptableNestedNameSpecifier(ASTContext &Context, NamedDecl *SD) {
+  if (!SD)
+    return false;
+  
+  // Namespace and namespace aliases are fine.
+  if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD))
+    return true;
+  
+  if (!isa<TypeDecl>(SD))
+    return false;
+  
+  // Determine whether we have a class (or, in C++0x, an enum) or
+  // a typedef thereof. If so, build the nested-name-specifier.
+  QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+  if (T->isDependentType())
+    return true;
+  else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+    if (TD->getUnderlyingType()->isRecordType() ||
+        (Context.getLangOptions().CPlusPlus0x && 
+         TD->getUnderlyingType()->isEnumeralType()))
+      return true;
+  } else if (isa<RecordDecl>(SD) || 
+             (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD)))
+    return true;
+
+  return false;
+}
+
 /// ActOnCXXNestedNameSpecifier - Called during parsing of a
 /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
 /// we want to resolve "bar::". 'SS' is empty or the previously parsed
@@ -255,58 +299,134 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
                                                     SourceLocation IdLoc,
                                                     SourceLocation CCLoc,
                                                     IdentifierInfo &II,
+                                                    TypeTy *ObjectTypePtr,
                                                     bool EnteringContext) {
   NestedNameSpecifier *Prefix 
     = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  
+  // Determine where to perform name lookup
+  DeclContext *LookupCtx = 0;
+  bool isDependent = false;
+  if (ObjectTypePtr) {
+    // This nested-name-specifier occurs in a member access expression, e.g.,
+    // x->B::f, and we are looking into the type of the object.
+    assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
+    QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+    LookupCtx = computeDeclContext(ObjectType);
+    isDependent = ObjectType->isDependentType();
+  } else if (SS.isSet()) {
+    // This nested-name-specifier occurs after another nested-name-specifier,
+    // so long into the context associated with the prior nested-name-specifier.
+    LookupCtx = computeDeclContext(SS, EnteringContext);
+    isDependent = isDependentScopeSpecifier(SS);
+  }
 
-  NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName,
-                                   false, false, SourceLocation(),
-                                   EnteringContext);
+  LookupResult Found;
+  bool ObjectTypeSearchedInScope = false;
+  if (LookupCtx) {
+    // Perform "qualified" name lookup into the declaration context we 
+    // computed, which is either the type of the base of a member access
+    // expression or the declaration context associated with a prior 
+    // nested-name-specifier.
+    
+    // The declaration context must be complete.
+    if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+      return 0;
 
-  if (SD) {
+    Found = LookupQualifiedName(LookupCtx, &II, LookupNestedNameSpecifierName,
+                                false);
+    
+    if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound && S) {
+      // C++ [basic.lookup.classref]p4:
+      //   If the id-expression in a class member access is a qualified-id of
+      //   the form 
+      //
+      //        class-name-or-namespace-name::...
+      //
+      //   the class-name-or-namespace-name following the . or -> operator is 
+      //   looked up both in the context of the entire postfix-expression and in 
+      //   the scope of the class of the object expression. If the name is found
+      //   only in the scope of the class of the object expression, the name 
+      //   shall refer to a class-name. If the name is found only in the 
+      //   context of the entire postfix-expression, the name shall refer to a
+      //   class-name or namespace-name. [...]
+      //
+      // Qualified name lookup into a class will not find a namespace-name,
+      // so we do not need to diagnoste that case specifically. However, 
+      // this qualified name lookup may find nothing. In that case, perform
+      // unqualified name lookup in the given scope.
+      
+      // FIXME: When we're instantiating a template, do we actually have to
+      // look in the scope of the template? Seems fishy...
+      Found = LookupName(S, &II, LookupNestedNameSpecifierName);
+      ObjectTypeSearchedInScope = true;
+    }
+  } else if (isDependent) {
+    // We were not able to compute the declaration context for a dependent
+    // base object type or prior nested-name-specifier, so this 
+    // nested-name-specifier refers to an unknown specialization. Just build
+    // a dependent nested-name-specifier.
+    return NestedNameSpecifier::Create(Context, Prefix, &II);
+  } else {
+    // Perform unqualified name lookup in the current scope.
+    Found = LookupName(S, &II, LookupNestedNameSpecifierName);
+  }
+  
+  // FIXME: Deal with ambiguities cleanly.
+  NamedDecl *SD = Found;
+  if (isAcceptableNestedNameSpecifier(Context, SD)) {
+    if (ObjectTypePtr && !ObjectTypeSearchedInScope && S) {
+      // C++ [basic.lookup.classref]p4:
+      //   [...] If the name is found in both contexts, the 
+      //   class-name-or-namespace-name shall refer to the same entity.
+      //
+      // We already found the name in the scope of the object. Now, look
+      // into the current scope (the scope of the postfix-expression) to
+      // see if we can find the same name there. 
+      LookupResult FoundOuter 
+        = LookupName(S, &II, LookupNestedNameSpecifierName);
+      
+      // FIXME: Handle ambiguities in FoundOuter!
+      NamedDecl *OuterDecl = FoundOuter;
+      if (isAcceptableNestedNameSpecifier(Context, OuterDecl) &&
+          OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
+          (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
+           !Context.hasSameType(
+                          Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
+                               Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
+        Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+          << &II;
+        Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
+          << QualType::getFromOpaquePtr(ObjectTypePtr);
+        Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
+             
+        // Fall through so that we'll pick the name we found in the object type,
+        // since that's probably what the user wanted anyway.
+      }
+    }
+    
     if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
       return NestedNameSpecifier::Create(Context, Prefix, Namespace);
 
-    if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
-      // Determine whether we have a class (or, in C++0x, an enum) or
-      // a typedef thereof. If so, build the nested-name-specifier.
-      QualType T = Context.getTypeDeclType(Type);
-      bool AcceptableType = false;
-      if (T->isDependentType())
-        AcceptableType = true;
-      else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
-        if (TD->getUnderlyingType()->isRecordType() ||
-            (getLangOptions().CPlusPlus0x && 
-             TD->getUnderlyingType()->isEnumeralType()))
-          AcceptableType = true;
-      } else if (isa<RecordDecl>(Type) || 
-                 (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
-        AcceptableType = true;
-
-      if (AcceptableType)
-        return NestedNameSpecifier::Create(Context, Prefix, false, 
-                                           T.getTypePtr());
-    }
-    
     // FIXME: It would be nice to maintain the namespace alias name, then
     // see through that alias when resolving the nested-name-specifier down to
     // a declaration context.
     if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
       return NestedNameSpecifier::Create(Context, Prefix,
-                                         Alias->getNamespace());
 
-    // Fall through to produce an error: we found something that isn't
-    // a class or a namespace.
-  } else if (SS.isSet() && isDependentScopeSpecifier(SS))
-    return NestedNameSpecifier::Create(Context, Prefix, &II);
+                                         Alias->getNamespace());
+    
+    QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
+    return NestedNameSpecifier::Create(Context, Prefix, false,
+                                       T.getTypePtr());
+  }
 
   // If we didn't find anything during our lookup, try again with
   // ordinary name lookup, which can help us produce better error
   // messages.
   if (!SD)
-    SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName,
-                          false, false, SourceLocation(),
-                          EnteringContext);
+    SD = LookupName(S, &II, LookupOrdinaryName);
+  
   unsigned DiagID;
   if (SD)
     DiagID = diag::err_expected_class_or_namespace;
@@ -338,58 +458,6 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
                                      T.getTypePtr());
 }
 
-Action::OwningExprResult
-Sema::ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS, ExprArg Base,
-                               tok::TokenKind OpKind) {
-  // Since this might be a postfix expression, get rid of ParenListExprs.
-  Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
-
-  Expr *BaseExpr = (Expr*)Base.get();
-  assert(BaseExpr && "no record expansion");
-
-  QualType BaseType = BaseExpr->getType();
-  // FIXME: handle dependent types
-  if (BaseType->isDependentType())
-    return move(Base);
-
-  // C++ [over.match.oper]p8:
-  //   [...] When operator->returns, the operator-> is applied  to the value 
-  //   returned, with the original second operand.
-  if (OpKind == tok::arrow) {
-    while (BaseType->isRecordType()) {
-      Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc());
-      BaseExpr = (Expr*)Base.get();
-      if (BaseExpr == NULL)
-          return ExprError();
-      BaseType = BaseExpr->getType();
-    }
-  }
-
-  if (BaseType->isPointerType())
-    BaseType = BaseType->getPointeeType();
-
-  // We could end up with various non-record types here, such as extended 
-  // vector types or Objective-C interfaces. Just return early and let
-  // ActOnMemberReferenceExpr do the work.
-  if (!BaseType->isRecordType())
-    return move(Base);
-
-  SS.setRange(BaseExpr->getSourceRange());
-  SS.setScopeRep(
-    NestedNameSpecifier::Create(Context, 0, false, BaseType.getTypePtr())
-    );
-
-  if (S)
-    ActOnCXXEnterDeclaratorScope(S,SS);
-  return move(Base);
-}
-
-void Sema::ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS) {
-  if (S && SS.isSet())
-    ActOnCXXExitDeclaratorScope(S,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 0dc4b8d180042fcd5aa492dac7cc004f0cd137d8..87330ab0b63c375f91468da0ef1e7471ce251b49 100644 (file)
@@ -1754,6 +1754,48 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr,
   return E;
 }
 
+Sema::OwningExprResult 
+Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
+                                   tok::TokenKind OpKind, TypeTy *&ObjectType) {
+  // Since this might be a postfix expression, get rid of ParenListExprs.
+  Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+  
+  Expr *BaseExpr = (Expr*)Base.get();
+  assert(BaseExpr && "no record expansion");
+  
+  QualType BaseType = BaseExpr->getType();
+  if (BaseType->isDependentType()) {
+    // FIXME: member of the current instantiation
+    ObjectType = BaseType.getAsOpaquePtr();
+    return move(Base);
+  }
+  
+  // C++ [over.match.oper]p8:
+  //   [...] When operator->returns, the operator-> is applied  to the value 
+  //   returned, with the original second operand.
+  if (OpKind == tok::arrow) {
+    while (BaseType->isRecordType()) {
+      Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc());
+      BaseExpr = (Expr*)Base.get();
+      if (BaseExpr == NULL)
+        return ExprError();
+      BaseType = BaseExpr->getType();
+    }
+  }
+  
+  if (BaseType->isPointerType())
+    BaseType = BaseType->getPointeeType();
+  
+  // We could end up with various non-record types here, such as extended 
+  // vector types or Objective-C interfaces. Just return early and let
+  // ActOnMemberReferenceExpr do the work.
+  if (!BaseType->isRecordType())
+    return move(Base);
+    
+  ObjectType = BaseType.getAsOpaquePtr();
+  return move(Base);  
+}
+
 Sema::OwningExprResult
 Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
                                    SourceLocation OpLoc,
index 4a699de6c8d9597a65b5d0fd3a7b5443beb54bdc..38abd1641d539d71dcf244695ef242ab21e1233f 100644 (file)
@@ -1004,8 +1004,9 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
                           LookupNameKind NameKind, bool RedeclarationOnly) {
   assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
   
-  if (!Name) return LookupResult::CreateLookupResult(Context, 0);
-
+  if (!Name) 
+    return LookupResult::CreateLookupResult(Context, 0);
+  
   // If we're performing qualified name lookup (e.g., lookup into a
   // struct), find fields as part of ordinary name lookup.
   unsigned IDNS
@@ -1013,16 +1014,25 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
                                                 getLangOptions().CPlusPlus);
   if (NameKind == LookupOrdinaryName)
     IDNS |= Decl::IDNS_Member;
-
+  
+  // Make sure that the declaration context is complete.
+  assert((!isa<TagDecl>(LookupCtx) ||
+          LookupCtx->isDependentContext() ||
+          cast<TagDecl>(LookupCtx)->isDefinition() ||
+          Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
+            ->isBeingDefined()) &&
+         "Declaration context must already be complete!");
+    
   // Perform qualified name lookup into the LookupCtx.
   DeclContext::lookup_iterator I, E;
   for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
     if (isAcceptableLookupResult(*I, NameKind, IDNS))
       return LookupResult::CreateLookupResult(Context, I, E);
 
-  // If this isn't a C++ class or we aren't allowed to look into base
-  // classes, we're done.
-  if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
+  // If this isn't a C++ class, we aren't allowed to look into base
+  // classes, we're done, or the lookup context is dependent, we're done.
+  if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx) || 
+      LookupCtx->isDependentContext())
     return LookupResult::CreateLookupResult(Context, 0);
 
   // Perform lookup into our base classes.
@@ -1152,24 +1162,9 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
     if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
       // We have resolved the scope specifier to a particular declaration 
       // contex, and will perform name lookup in that context.
-      
-      if (DC->isDependentContext()) {
-        // If this is a dependent context, then we are looking for a member of
-        // the current instantiation. This is a narrow search that looks into
-        // just the described declaration context (C++0x [temp.dep.type]).
-        unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, 
-                                                                  true);
-        DeclContext::lookup_iterator I, E;
-        for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I)
-          if (isAcceptableLookupResult(*I, NameKind, IDNS))
-            return LookupResult::CreateLookupResult(Context, I, E);
-      }
-      
-      // Qualified name lookup into the named declaration context.
-      // The declaration context must be complete.
-      if (RequireCompleteDeclContext(*SS))
+      if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS))
         return LookupResult::CreateLookupResult(Context, 0);
-            
+                                    
       return LookupQualifiedName(DC, Name, NameKind, RedeclarationOnly);
     }
 
index f0165c91e10683169c9d4ada1a2e6c0038118fe7..119e17f814d017623f753837474361e548e1e805 100644 (file)
 
 using namespace clang;
 
-/// isTemplateName - Determines whether the identifier II is a
-/// template name in the current scope, and returns the template
-/// declaration if II names a template. An optional CXXScope can be
-/// passed to indicate the C++ scope in which the identifier will be
-/// found. 
-TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
-                                      const CXXScopeSpec *SS,
-                                      bool EnteringContext,
-                                      TemplateTy &TemplateResult) {                                      
-  LookupResult Found = LookupParsedName(S, SS, &II, LookupOrdinaryName, 
-                                        false, false, SourceLocation(),
-                                        EnteringContext);
+/// \brief Determine whether the declaration found is acceptable as the name
+/// of a template and, if so, return that template declaration. Otherwise,
+/// returns NULL.
+static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
+  if (!D)
+    return 0;
   
-  // FIXME: Cope with ambiguous name-lookup results.
-  assert(!Found.isAmbiguous() && 
-         "Cannot handle template name-lookup ambiguities");
+  if (isa<TemplateDecl>(D))
+    return D;
+  
+  if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+    // C++ [temp.local]p1:
+    //   Like normal (non-template) classes, class templates have an
+    //   injected-class-name (Clause 9). The injected-class-name
+    //   can be used with or without a template-argument-list. When
+    //   it is used without a template-argument-list, it is
+    //   equivalent to the injected-class-name followed by the
+    //   template-parameters of the class template enclosed in
+    //   <>. When it is used with a template-argument-list, it
+    //   refers to the specified class template specialization,
+    //   which could be the current specialization or another
+    //   specialization.
+    if (Record->isInjectedClassName()) {
+      Record = cast<CXXRecordDecl>(Record->getCanonicalDecl());
+      if (Record->getDescribedClassTemplate())
+        return Record->getDescribedClassTemplate();
+
+      if (ClassTemplateSpecializationDecl *Spec
+            = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+        return Spec->getSpecializedTemplate();
+    }
+    
+    return 0;
+  }
   
-  NamedDecl *IIDecl = Found;
+  OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D);
+  if (!Ovl)
+    return 0;
   
-  TemplateNameKind TNK = TNK_Non_template;
-  TemplateDecl *Template = 0;
-
-  if (IIDecl) {
-    if ((Template = dyn_cast<TemplateDecl>(IIDecl))) {
-      if (isa<FunctionTemplateDecl>(IIDecl))
-        TNK = TNK_Function_template;
-      else if (isa<ClassTemplateDecl>(IIDecl) || 
-               isa<TemplateTemplateParmDecl>(IIDecl))
-        TNK = TNK_Type_template;
-      else
-        assert(false && "Unknown template declaration kind");
-    } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
-      // C++ [temp.local]p1:
-      //   Like normal (non-template) classes, class templates have an
-      //   injected-class-name (Clause 9). The injected-class-name
-      //   can be used with or without a template-argument-list. When
-      //   it is used without a template-argument-list, it is
-      //   equivalent to the injected-class-name followed by the
-      //   template-parameters of the class template enclosed in
-      //   <>. When it is used with a template-argument-list, it
-      //   refers to the specified class template specialization,
-      //   which could be the current specialization or another
-      //   specialization.
-      if (Record->isInjectedClassName()) {
-        Record = cast<CXXRecordDecl>(Record->getCanonicalDecl());
-        if ((Template = Record->getDescribedClassTemplate()))
-          TNK = TNK_Type_template;
-        else if (ClassTemplateSpecializationDecl *Spec
-                   = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
-          Template = Spec->getSpecializedTemplate();
-          TNK = TNK_Type_template;
-        }
+  for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+                                              FEnd = Ovl->function_end();
+       F != FEnd; ++F) {
+    if (FunctionTemplateDecl *FuncTmpl = dyn_cast<FunctionTemplateDecl>(*F)) {
+      // We've found a function template. Determine whether there are
+      // any other function templates we need to bundle together in an
+      // OverloadedFunctionDecl
+      for (++F; F != FEnd; ++F) {
+        if (isa<FunctionTemplateDecl>(*F))
+          break;
       }
-    } else if (OverloadedFunctionDecl *Ovl 
-                 = dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
-      for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
-                                                  FEnd = Ovl->function_end();
-           F != FEnd; ++F) {
-        if (FunctionTemplateDecl *FuncTmpl 
-              = dyn_cast<FunctionTemplateDecl>(*F)) {
-          // We've found a function template. Determine whether there are
-          // any other function templates we need to bundle together in an
-          // OverloadedFunctionDecl
-          for (++F; F != FEnd; ++F) {
-            if (isa<FunctionTemplateDecl>(*F))
-              break;
-          }
-          
-          if (F != FEnd) {
-            // Build an overloaded function decl containing only the
-            // function templates in Ovl.
-            OverloadedFunctionDecl *OvlTemplate 
-              = OverloadedFunctionDecl::Create(Context,
-                                               Ovl->getDeclContext(),
-                                               Ovl->getDeclName());
-            OvlTemplate->addOverload(FuncTmpl);
+      
+      if (F != FEnd) {
+        // Build an overloaded function decl containing only the
+        // function templates in Ovl.
+        OverloadedFunctionDecl *OvlTemplate 
+          = OverloadedFunctionDecl::Create(Context,
+                                           Ovl->getDeclContext(),
+                                           Ovl->getDeclName());
+        OvlTemplate->addOverload(FuncTmpl);
+        OvlTemplate->addOverload(*F);
+        for (++F; F != FEnd; ++F) {
+          if (isa<FunctionTemplateDecl>(*F))
             OvlTemplate->addOverload(*F);
-            for (++F; F != FEnd; ++F) {
-              if (isa<FunctionTemplateDecl>(*F))
-                OvlTemplate->addOverload(*F);
-            }
-
-            // Form the resulting TemplateName
-            if (SS && SS->isSet() && !SS->isInvalid()) {
-              NestedNameSpecifier *Qualifier 
-                = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
-              TemplateResult 
-                = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, 
-                                                                    false,
-                                                                  OvlTemplate));              
-            } else {
-              TemplateResult = TemplateTy::make(TemplateName(OvlTemplate));
-            }
-            return TNK_Function_template;
-          }
-          
-          TNK = TNK_Function_template;
-          Template = FuncTmpl;
-          break;
         }
+        
+        return OvlTemplate;
       }
+
+      return FuncTmpl;
     }
+  }
+  
+  return 0;
+}
 
-    if (TNK != TNK_Non_template) {
-      if (SS && SS->isSet() && !SS->isInvalid()) {
-        NestedNameSpecifier *Qualifier 
-          = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
-        TemplateResult 
-          = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, 
-                                                              false,
-                                                              Template));
-      } else
-        TemplateResult = TemplateTy::make(TemplateName(Template));
+TemplateNameKind Sema::isTemplateName(Scope *S,
+                                      const IdentifierInfo &II, 
+                                      SourceLocation IdLoc,
+                                      const CXXScopeSpec *SS,
+                                      TypeTy *ObjectTypePtr,
+                                      bool EnteringContext,
+                                      TemplateTy &TemplateResult) {
+  // Determine where to perform name lookup
+  DeclContext *LookupCtx = 0;
+  bool isDependent = false;
+  if (ObjectTypePtr) {
+    // This nested-name-specifier occurs in a member access expression, e.g.,
+    // x->B::f, and we are looking into the type of the object.
+    assert((!SS || !SS->isSet()) && 
+           "ObjectType and scope specifier cannot coexist");
+    QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+    LookupCtx = computeDeclContext(ObjectType);
+    isDependent = ObjectType->isDependentType();
+  } else if (SS && SS->isSet()) {
+    // This nested-name-specifier occurs after another nested-name-specifier,
+    // so long into the context associated with the prior nested-name-specifier.
+
+    LookupCtx = computeDeclContext(*SS, EnteringContext);
+    isDependent = isDependentScopeSpecifier(*SS);
+  }
+  
+  LookupResult Found;
+  bool ObjectTypeSearchedInScope = false;
+  if (LookupCtx) {
+    // Perform "qualified" name lookup into the declaration context we
+    // computed, which is either the type of the base of a member access
+    // expression or the declaration context associated with a prior 
+    // nested-name-specifier.
+
+    // The declaration context must be complete.
+    if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
+      return TNK_Non_template;
+    
+    Found = LookupQualifiedName(LookupCtx, &II, LookupOrdinaryName);
+    
+    if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) {
+      // C++ [basic.lookup.classref]p1:
+      //   In a class member access expression (5.2.5), if the . or -> token is
+      //   immediately followed by an identifier followed by a <, the 
+      //   identifier must be looked up to determine whether the < is the 
+      //   beginning of a template argument list (14.2) or a less-than operator.
+      //   The identifier is first looked up in the class of the object 
+      //   expression. If the identifier is not found, it is then looked up in 
+      //   the context of the entire postfix-expression and shall name a class
+      //   or function template.
+      //
+      // FIXME: When we're instantiating a template, do we actually have to
+      // look in the scope of the template? Seems fishy...
+      Found = LookupName(S, &II, LookupOrdinaryName);
+      ObjectTypeSearchedInScope = true;
     }
+  } else if (isDependent) {
+    // We cannot look into a dependent object type or 
+    return TNK_Non_template;
+  } else {
+    // Perform unqualified name lookup in the current scope.
+    Found = LookupName(S, &II, LookupOrdinaryName);
+  }
+  
+  // FIXME: Cope with ambiguous name-lookup results.
+  assert(!Found.isAmbiguous() && 
+         "Cannot handle template name-lookup ambiguities");
+
+  NamedDecl *Template = isAcceptableTemplateName(Context, Found);
+  if (!Template)
+    return TNK_Non_template;
+
+  if (ObjectTypePtr && !ObjectTypeSearchedInScope) {
+    // C++ [basic.lookup.classref]p1:
+    //   [...] If the lookup in the class of the object expression finds a 
+    //   template, the name is also looked up in the context of the entire
+    //   postfix-expression and [...]
+    //
+    LookupResult FoundOuter = LookupName(S, &II, LookupOrdinaryName);
+    // FIXME: Handle ambiguities in this lookup better
+    NamedDecl *OuterTemplate = isAcceptableTemplateName(Context, FoundOuter);
+    
+    if (!OuterTemplate) {
+      //   - if the name is not found, the name found in the class of the 
+      //     object expression is used, otherwise
+    } else if (!isa<ClassTemplateDecl>(OuterTemplate)) {
+      //   - if the name is found in the context of the entire 
+      //     postfix-expression and does not name a class template, the name 
+      //     found in the class of the object expression is used, otherwise
+    } else {
+      //   - if the name found is a class template, it must refer to the same
+      //     entity as the one found in the class of the object expression, 
+      //     otherwise the program is ill-formed.
+      if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) {
+        Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+          << &II;
+        Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type)
+          << QualType::getFromOpaquePtr(ObjectTypePtr);
+        Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope);
+        
+        // Recover by taking the template that we found in the object 
+        // expression's type.
+      }
+    }      
   }
-  return TNK;
+  
+  if (SS && SS->isSet() && !SS->isInvalid()) {
+    NestedNameSpecifier *Qualifier 
+      = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+    if (OverloadedFunctionDecl *Ovl 
+          = dyn_cast<OverloadedFunctionDecl>(Template))
+      TemplateResult 
+        = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+                                                            Ovl));
+    else
+      TemplateResult 
+        = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+                                                 cast<TemplateDecl>(Template)));    
+  } else if (OverloadedFunctionDecl *Ovl 
+               = dyn_cast<OverloadedFunctionDecl>(Template)) {
+    TemplateResult = TemplateTy::make(TemplateName(Ovl));
+  } else {
+    TemplateResult = TemplateTy::make(
+                                  TemplateName(cast<TemplateDecl>(Template)));
+  }
+  
+  if (isa<ClassTemplateDecl>(Template) || 
+      isa<TemplateTemplateParmDecl>(Template))
+    return TNK_Type_template;
+  
+  assert((isa<FunctionTemplateDecl>(Template) || 
+          isa<OverloadedFunctionDecl>(Template)) &&
+         "Unhandled template kind in Sema::isTemplateName");
+  return TNK_Function_template;
 }
 
 /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -1130,14 +1223,11 @@ Sema::TemplateTy
 Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
                                  const IdentifierInfo &Name,
                                  SourceLocation NameLoc,
-                                 const CXXScopeSpec &SS) {
-  if (!SS.isSet() || SS.isInvalid())
-    return TemplateTy();
-
-  NestedNameSpecifier *Qualifier 
-    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
-
-  if (computeDeclContext(SS, false)) {
+                                 const CXXScopeSpec &SS,
+                                 TypeTy *ObjectType) {
+  if ((ObjectType && 
+       computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
+      (SS.isSet() && computeDeclContext(SS, false))) {
     // C++0x [temp.names]p5:
     //   If a name prefixed by the keyword template is not the name of
     //   a template, the program is ill-formed. [Note: the keyword
@@ -1155,7 +1245,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
     // "template" keyword is now permitted). We follow the C++0x
     // rules, even in C++03 mode, retroactively applying the DR.
     TemplateTy Template;
-    TemplateNameKind TNK = isTemplateName(Name, 0, &SS, false, Template);
+    TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType, 
+                                          false, Template);
     if (TNK == TNK_Non_template) {
       Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
         << &Name;
@@ -1165,6 +1256,13 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
     return Template;
   }
 
+  // FIXME: We need to be able to create a dependent template name with just
+  // an identifier, to handle the x->template f<T> case.
+  assert(!ObjectType && 
+      "Cannot handle dependent template names without a nested-name-specifier");
+  
+  NestedNameSpecifier *Qualifier 
+    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
   return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
 }
 
index e7400e74734a4c582b77272ac91ba82139a297df..8fe28a46bf539d8c62a29b1a46339f0f4ae67436 100644 (file)
@@ -1454,7 +1454,10 @@ public:
     OwningExprResult Base = move(BaseE);
     tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
     CXXScopeSpec SS;
-    Base = SemaRef.ActOnCXXEnterMemberScope(0, SS, move(Base), OpKind);
+    Sema::TypeTy *ObjectType = 0;
+    
+    Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), OperatorLoc,
+                                                OpKind, ObjectType);
     if (Base.isInvalid())
       return SemaRef.ExprError();
     
@@ -1463,7 +1466,6 @@ public:
                                             MemberLoc,
                                             Name,
                                     /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
-    SemaRef.ActOnCXXExitMemberScope(0, SS);
     return move(Base);
   }
 
@@ -4410,6 +4412,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
   return static_cast<NestedNameSpecifier *>(
                     SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(), 
                                                         Range.getEnd(), II,
+                                                        /*FIXME:ObjectType=*/0,
                                                         false));
 }
 
@@ -4467,7 +4470,11 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
   SS.setRange(SourceRange(getDerived().getBaseLocation()));
   SS.setScopeRep(Qualifier);
   Sema::TemplateTy Template;
-  TemplateNameKind TNK = SemaRef.isTemplateName(II, 0, &SS, false, Template);
+  TemplateNameKind TNK = SemaRef.isTemplateName(0, II,
+                                     /*FIXME:*/getDerived().getBaseLocation(),
+                                                &SS, 
+                                                /*FIXME:ObjectType=*/0, false,
+                                                Template);
   if (TNK == TNK_Non_template) {
     SemaRef.Diag(getDerived().getBaseLocation(), 
                  diag::err_template_kw_refers_to_non_template)
index 97f31033e8ab6b163b2d4b9d658a32bf9cfee297..ffb20d2082361a98dafab3686ce0892a24866573 100644 (file)
@@ -13,7 +13,7 @@ namespace A {
 }
 
 A:: ; // expected-error {{expected unqualified-id}}
-::A::ax::undef ex3; // expected-error {{expected a class or namespace}} expected-error {{unknown type name 'undef'}}
+::A::ax::undef ex3; // expected-error {{no member named}} expected-error {{unknown type name 'undef'}}
 A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{unknown type name 'undef2'}}
 
 int A::C::Ag1() { return 0; }
index ad013990cac2ecef310a48efaec403820ef67898..10f1a47a9d4a2ae0d00bbd532cd4120dfa5b1c60 100644 (file)
@@ -3,7 +3,7 @@ namespace A
 {
     namespace B
     {
-        struct base
+        struct base // expected-note{{object type}}
         {
             void x() {}
             void y() {}
@@ -82,13 +82,31 @@ namespace C
         i.foo(); // expected-error{{member reference base type 'int' is not a structure or union}}
     }
 
+    void fun4a() {
+      A::sub *a;
+      
+      typedef A::member base; // expected-note{{current scope}}
+      a->base::x(); // expected-error{{ambiguous}}      
+    }
+
+    void fun4b() {
+      A::sub *a;
+      
+      typedef A::B::base base;
+      a->base::x();
+    }
+  
     template<typename T>
-    void fun4()
+    void fun5()
     {
         T a;
         a.x();
         a->foo();
 
+#if 0
+        // FIXME: We need the notion of identifiers as dependent 
+        // nested-name-specifiers without a prefix for this code to work.
+      
         // Things that work for the wrong reason
         a.A::sub::x();
         a.A::B::base::x();
@@ -98,9 +116,20 @@ namespace C
         a.bad::x();
 
         // Things that fail, but shouldn't
-        a.sub::x(); // expected-error{{use of undeclared identifier 'sub'}}
-        a.base::x(); // expected-error{{use of undeclared identifier 'base'}}
-        a.B::base::x(); // expected-error{{use of undeclared identifier 'B'}}
-        a->member::foo(); // expected-error{{use of undeclared identifier 'member'}}
+        a.sub::x(); // xpected-error{{use of undeclared identifier 'sub'}}
+        a.base::x(); // xpected-error{{use of undeclared identifier 'base'}}
+        a.B::base::x(); // xpected-error{{use of undeclared identifier 'B'}}
+        a->member::foo(); // xpected-error{{use of undeclared identifier 'member'}}
+#endif
     }
 }
+
+// PR4703
+struct a {
+  int a;
+  static int sa;
+};
+
+a a;
+
+int a::sa = a.a;
index 8eb40c83c344ce9b7aca86b1994ae595b6da85ba..83bf16c69004d6a810b2baaabd3d44fc2e893076 100644 (file)
@@ -48,3 +48,4 @@ void test_X_f0_explicit(X x, int i, long l) {
 
 // PR4608
 class A { template <class x> x a(x z) { return z+y; } int y; };
+