[cfe-commits] r80953 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/TreeTransform.h test/SemaCXX/qual-id-test.cpp test/SemaTemplate/member-access-expr.cpp www/cxx_status.html

Douglas Gregor dgregor at apple.com
Thu Sep 3 14:38:09 PDT 2009


Author: dgregor
Date: Thu Sep  3 16:38:09 2009
New Revision: 80953

URL: http://llvm.org/viewvc/llvm-project?rev=80953&view=rev
Log:
Improve template instantiation for member access expressions that
involve qualified names, e.g., x->Base::f. We now maintain enough
information in the AST to compare the results of the name lookup of
"Base" in the scope of the postfix-expression (determined at template
definition time) and in the type of the object expression.

Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/SemaCXX/qual-id-test.cpp
    cfe/trunk/test/SemaTemplate/member-access-expr.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Sep  3 16:38:09 2009
@@ -1306,6 +1306,15 @@
   /// \brief The source range covering the nested name specifier.
   SourceRange QualifierRange;
   
+  /// \brief In a qualified member access expression such as t->Base::f, this
+  /// member stores the resolves of name lookup in the context of the member 
+  /// access expression, to be used at instantiation time.
+  ///
+  /// FIXME: This member, along with the Qualifier and QualifierRange, could
+  /// be stuck into a structure that is optionally allocated at the end of
+  /// the CXXUnresolvedMemberExpr, to save space in the common case.
+  NamedDecl *FirstQualifierFoundInScope;
+  
   /// \brief The member to which this member expression refers, which
   /// can be name, overloaded operator, or destructor.
   /// FIXME: could also be a template-id
@@ -1320,11 +1329,13 @@
                           SourceLocation OperatorLoc,
                           NestedNameSpecifier *Qualifier,
                           SourceRange QualifierRange,
+                          NamedDecl *FirstQualifierFoundInScope,
                           DeclarationName Member,
                           SourceLocation MemberLoc)
     : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
       Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
       Qualifier(Qualifier), QualifierRange(QualifierRange),
+      FirstQualifierFoundInScope(FirstQualifierFoundInScope),
       Member(Member), MemberLoc(MemberLoc) { }
 
   /// \brief Retrieve the base object of this member expressions,
@@ -1349,6 +1360,21 @@
   /// that qualifies the member name.
   SourceRange getQualifierRange() const { return QualifierRange; }
   
+  /// \brief Retrieve the first part of the nested-name-specifier that was
+  /// found in the scope of the member access expression when the member access
+  /// was initially parsed.
+  ///
+  /// This function only returns a useful result when member access expression
+  /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration 
+  /// returned by this function describes what was found by unqualified name 
+  /// lookup for the identifier "Base" within the scope of the member access
+  /// expression itself. At template instantiation time, this information is
+  /// combined with the results of name lookup into the type of the object
+  /// expression itself (the class type of x).
+  NamedDecl *getFirstQualifierFoundInScope() const { 
+    return FirstQualifierFoundInScope;
+  }
+  
   /// \brief Retrieve the name of the member that this expression
   /// refers to.
   DeclarationName getMember() const { return Member; }

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Sep  3 16:38:09 2009
@@ -1610,13 +1610,15 @@
                                             SourceLocation MemberLoc,
                                             DeclarationName MemberName,
                                             DeclPtrTy ImplDecl,
-                                            const CXXScopeSpec *SS = 0) {
+                                            const CXXScopeSpec *SS = 0,
+                                          NamedDecl *FirstQualifierInScope = 0) {
     // FIXME: Temporary helper while we migrate existing calls to 
     // BuildMemberReferenceExpr to support explicitly-specified template
     // arguments.
     return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
                                     MemberName, false, SourceLocation(), 0, 0,
-                                    SourceLocation(), ImplDecl, SS);
+                                    SourceLocation(), ImplDecl, SS,
+                                    FirstQualifierInScope);
   }
   
   OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
@@ -1630,7 +1632,8 @@
                                             unsigned NumExplicitTemplateArgs,
                                             SourceLocation RAngleLoc,
                                             DeclPtrTy ImplDecl,
-                                            const CXXScopeSpec *SS = 0);
+                                            const CXXScopeSpec *SS,
+                                          NamedDecl *FirstQualifierInScope = 0);
   
   virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
                                                     SourceLocation OpLoc,
@@ -2047,12 +2050,18 @@
   virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
                                                    SourceLocation CCLoc);
 
-  /// 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.
+  NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
+  
+
+  CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
+                                          const CXXScopeSpec &SS,
+                                          SourceLocation IdLoc,
+                                          SourceLocation CCLoc,
+                                          IdentifierInfo &II,
+                                          QualType ObjectType,
+                                          NamedDecl *ScopeLookupResult,
+                                          bool EnteringContext);
+  
   virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
                                                   const CXXScopeSpec &SS,
                                                   SourceLocation IdLoc,

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Thu Sep  3 16:38:09 2009
@@ -288,18 +288,45 @@
   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
-/// 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.
-Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+/// \brief If the given nested-name-specifier begins with a bare identifier
+/// (e.g., Base::), perform name lookup for that identifier as a 
+/// nested-name-specifier within the given scope, and return the result of that
+/// name lookup.
+NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
+  if (!S || !NNS)
+    return 0;
+  
+  while (NNS->getPrefix())
+    NNS = NNS->getPrefix();
+  
+  if (NNS->getKind() != NestedNameSpecifier::Identifier)
+    return 0;
+  
+  LookupResult Found 
+    = LookupName(S, NNS->getAsIdentifier(), LookupNestedNameSpecifierName);
+  assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
+
+  NamedDecl *Result = Found;
+  if (isAcceptableNestedNameSpecifier(Context, Result))
+    return Result;
+  
+  return 0;
+}
+
+/// \brief Build a new nested-name-specifier for "identifier::", as described
+/// by ActOnCXXNestedNameSpecifier.
+///
+/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
+/// that it contains an extra parameter \p ScopeLookupResult, which provides
+/// the result of name lookup within the scope of the nested-name-specifier
+/// that was computed at template definitino time.
+Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
                                                     const CXXScopeSpec &SS,
                                                     SourceLocation IdLoc,
                                                     SourceLocation CCLoc,
                                                     IdentifierInfo &II,
-                                                    TypeTy *ObjectTypePtr,
+                                                    QualType ObjectType,
+                                                  NamedDecl *ScopeLookupResult,
                                                     bool EnteringContext) {
   NestedNameSpecifier *Prefix 
     = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
@@ -307,11 +334,10 @@
   // Determine where to perform name lookup
   DeclContext *LookupCtx = 0;
   bool isDependent = false;
-  if (ObjectTypePtr) {
+  if (!ObjectType.isNull()) {
     // 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()) {
@@ -320,7 +346,7 @@
     LookupCtx = computeDeclContext(SS, EnteringContext);
     isDependent = isDependentScopeSpecifier(SS);
   }
-
+  
   LookupResult Found;
   bool ObjectTypeSearchedInScope = false;
   if (LookupCtx) {
@@ -332,11 +358,11 @@
     // The declaration context must be complete.
     if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
       return 0;
-
+    
     Found = LookupQualifiedName(LookupCtx, &II, LookupNestedNameSpecifierName,
                                 false);
     
-    if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound && S) {
+    if (!ObjectType.isNull() && Found.getKind() == LookupResult::NotFound) {
       // C++ [basic.lookup.classref]p4:
       //   If the id-expression in a class member access is a qualified-id of
       //   the form 
@@ -354,12 +380,14 @@
       // 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? Both EDG and GCC do it; GCC 
-      // requires the lookup to be successful, EDG doesn't.
-      Found = LookupName(S, &II, LookupNestedNameSpecifierName);
+      // unqualified name lookup in the given scope (if available) or 
+      // reconstruct the result from when name lookup was performed at template
+      // definition time.
+      if (S)
+        Found = LookupName(S, &II, LookupNestedNameSpecifierName);
+      else
+        Found = LookupResult::CreateLookupResult(Context, ScopeLookupResult);
+        
       ObjectTypeSearchedInScope = true;
     }
   } else if (isDependent) {
@@ -379,16 +407,21 @@
   // FIXME: Deal with ambiguities cleanly.
   NamedDecl *SD = Found;
   if (isAcceptableNestedNameSpecifier(Context, SD)) {
-    if (ObjectTypePtr && !ObjectTypeSearchedInScope && S) {
+    if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
       // 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);
+      // see if we can find the same name there. As above, if there is no
+      // scope, reconstruct the result from the template instantiation itself.
+      LookupResult FoundOuter;
+      if (S)
+        FoundOuter = LookupName(S, &II, LookupNestedNameSpecifierName);
+      else
+        FoundOuter = LookupResult::CreateLookupResult(Context, 
+                                                      ScopeLookupResult);
       
       // FIXME: Handle ambiguities in FoundOuter!
       NamedDecl *OuterDecl = FoundOuter;
@@ -396,35 +429,35 @@
           OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
           (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) ||
            !Context.hasSameType(
-                          Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
+                            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);
+             Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
+               << &II;
+             Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
+               << ObjectType;
+             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.
-      }
+             // 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);
-
+    
     // 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());
     
     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.
@@ -441,15 +474,33 @@
     return 0;
   } else
     DiagID = diag::err_undeclared_var_use;
-
+  
   if (SS.isSet())
     Diag(IdLoc, DiagID) << &II << SS.getRange();
   else
     Diag(IdLoc, DiagID) << &II;
-
+  
   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.
+Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+                                                    const CXXScopeSpec &SS,
+                                                    SourceLocation IdLoc,
+                                                    SourceLocation CCLoc,
+                                                    IdentifierInfo &II,
+                                                    TypeTy *ObjectTypePtr,
+                                                    bool EnteringContext) {
+  return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, 
+                                     QualType::getFromOpaquePtr(ObjectTypePtr),
+                                     /*ScopeLookupResult=*/0, EnteringContext);
+}
+
 Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
                                                     const CXXScopeSpec &SS,
                                                     TypeTy *Ty,

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep  3 16:38:09 2009
@@ -1989,7 +1989,8 @@
                                const TemplateArgument *ExplicitTemplateArgs,
                                unsigned NumExplicitTemplateArgs,
                                SourceLocation RAngleLoc,
-                               DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
+                               DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS,
+                               NamedDecl *FirstQualifierInScope) {
   if (SS && SS->isInvalid())
     return ExprError();
 
@@ -2022,14 +2023,23 @@
   // Get the type being accessed in BaseType.  If this is an arrow, the BaseExpr
   // must have pointer type, and the accessed type is the pointee.
   if (OpKind == tok::arrow) {
-    if (BaseType->isDependentType())
+    if (BaseType->isDependentType()) {
+      NestedNameSpecifier *Qualifier = 0;
+      if (SS) {
+        Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+        if (!FirstQualifierInScope)
+          FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+      }
+      
       return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
                                                          BaseExpr, true, 
                                                          OpLoc,
-                            (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+                                                         Qualifier,
                                             SS? SS->getRange() : SourceRange(),
+                                                         FirstQualifierInScope,
                                                          MemberName,
                                                          MemberLoc));
+    }
     else if (const PointerType *PT = BaseType->getAs<PointerType>())
       BaseType = PT->getPointeeType();
     else if (BaseType->isObjCObjectPointerType())
@@ -2051,14 +2061,23 @@
       const PointerType *PT = BaseType->getAs<PointerType>();
 
       if (!PT || (getLangOptions().ObjC1 && 
-                  !PT->getPointeeType()->isRecordType()))
+                  !PT->getPointeeType()->isRecordType())) {
+        NestedNameSpecifier *Qualifier = 0;
+        if (SS) {
+          Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+          if (!FirstQualifierInScope)
+            FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+        }
+        
         return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
                                                            BaseExpr, false, 
                                                            OpLoc, 
-                            (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+                                                           Qualifier,
                                             SS? SS->getRange() : SourceRange(),
+                                                         FirstQualifierInScope,
                                                            MemberName,
                                                            MemberLoc));
+      }
     }
   }
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Sep  3 16:38:09 2009
@@ -1789,9 +1789,20 @@
   // 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())
+  if (!BaseType->isRecordType()) {
+    // C++ [basic.lookup.classref]p2:
+    //   [...] If the type of the object expression is of pointer to scalar
+    //   type, the unqualified-id is looked up in the context of the complete
+    //   postfix-expression.
+    ObjectType = 0;
     return move(Base);
+  }
     
+  // C++ [basic.lookup.classref]p2:
+  //   If the id-expression in a class member access (5.2.5) is an 
+  //   unqualified-id, and the type of the object expres- sion is of a class
+  //   type C (or of pointer to a class type C), the unqualified-id is looked
+  //   up in the scope of class C. [...]
   ObjectType = BaseType.getAsOpaquePtr();
   return move(Base);  
 }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Sep  3 16:38:09 2009
@@ -359,8 +359,10 @@
 }
 
 Decl *TemplateInstantiator::TransformDecl(Decl *D) {
-  if (TemplateTemplateParmDecl *TTP 
-        = dyn_cast_or_null<TemplateTemplateParmDecl>(D)) {
+  if (!D)
+    return 0;
+  
+  if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
     if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
       assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() &&
              "Wrong kind of template template argument");
@@ -381,7 +383,7 @@
       "Reducing depth of template template parameters is not yet implemented");
   }
   
-  return SemaRef.FindInstantiatedDecl(cast_or_null<NamedDecl>(D));
+  return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D));
 }
 
 Decl *TemplateInstantiator::TransformDefinition(Decl *D) {

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Sep  3 16:38:09 2009
@@ -15,6 +15,7 @@
 
 #include "Sema.h"
 #include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -243,7 +244,8 @@
   /// alternate behavior.
   NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
                                                     SourceRange Range,
-                                              QualType ObjectType = QualType());
+                                              QualType ObjectType = QualType(),
+                                          NamedDecl *FirstQualifierInScope = 0);
   
   /// \brief Transform the given template name.
   /// 
@@ -499,7 +501,8 @@
   NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
                                                   SourceRange Range,
                                                   IdentifierInfo &II,
-                                                  QualType ObjectType);
+                                                  QualType ObjectType,
+                                              NamedDecl *FirstQualifierInScope);
 
   /// \brief Build a new nested-name-specifier given the prefix and the
   /// namespace named in the next step in the nested-name-specifier.
@@ -1454,7 +1457,8 @@
                                               NestedNameSpecifier *Qualifier,
                                                   SourceRange QualifierRange,
                                                   DeclarationName Name,
-                                                  SourceLocation MemberLoc) {
+                                                  SourceLocation MemberLoc,
+                                             NamedDecl *FirstQualifierInScope) {
     OwningExprResult Base = move(BaseE);
     tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
 
@@ -1467,7 +1471,8 @@
                                             MemberLoc,
                                             Name,
                                     /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
-                                            &SS);
+                                            &SS,
+                                            FirstQualifierInScope);
     return move(Base);
   }
 
@@ -1591,7 +1596,8 @@
 NestedNameSpecifier *
 TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
                                                      SourceRange Range,
-                                                     QualType ObjectType) {
+                                                     QualType ObjectType,
+                                             NamedDecl *FirstQualifierInScope) {
   if (!NNS)
     return 0;
   
@@ -1599,13 +1605,15 @@
   NestedNameSpecifier *Prefix = NNS->getPrefix();
   if (Prefix) {
     Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range, 
-                                                       ObjectType);
+                                                       ObjectType,
+                                                       FirstQualifierInScope);
     if (!Prefix)
       return 0;
     
-    // Clear out the object type; it only applies to the first element in
-    // the nested-name-specifier.
+    // Clear out the object type and the first qualifier in scope; they only 
+    // apply to the first element in the nested-name-specifier.
     ObjectType = QualType();
+    FirstQualifierInScope = 0;
   }
   
   switch (NNS->getKind()) {
@@ -1618,7 +1626,8 @@
       
     return getDerived().RebuildNestedNameSpecifier(Prefix, Range, 
                                                    *NNS->getAsIdentifier(),
-                                                   ObjectType);
+                                                   ObjectType,
+                                                   FirstQualifierInScope);
       
   case NestedNameSpecifier::Namespace: {
     NamespaceDecl *NS 
@@ -4055,22 +4064,28 @@
   if (Base.isInvalid())
     return SemaRef.ExprError();
   
+  NamedDecl *FirstQualifierInScope
+    = cast_or_null<NamedDecl>(
+              getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
+  
   NestedNameSpecifier *Qualifier = 0;
   if (E->getQualifier()) {
     Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
                                                       E->getQualifierRange(),
-                                      QualType::getFromOpaquePtr(ObjectType));
+                                      QualType::getFromOpaquePtr(ObjectType),
+                                                        FirstQualifierInScope);
     if (!Qualifier)
       return SemaRef.ExprError();
   }
   
   // FIXME: Transform the declaration name
   DeclarationName Name = E->getMember();
-  
+    
   if (!getDerived().AlwaysRebuild() &&
       Base.get() == E->getBase() &&
       Qualifier == E->getQualifier() &&
-      Name == E->getMember())
+      Name == E->getMember() &&
+      FirstQualifierInScope == E->getFirstQualifierFoundInScope())
     return SemaRef.Owned(E->Retain()); 
   
   return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
@@ -4079,7 +4094,8 @@
                                                      Qualifier,
                                                      E->getQualifierRange(),
                                                      Name,
-                                                     E->getMemberLoc());
+                                                     E->getMemberLoc(),
+                                                     FirstQualifierInScope);
 }
 
 template<typename Derived>
@@ -4435,15 +4451,17 @@
 TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
                                                    SourceRange Range,
                                                    IdentifierInfo &II,
-                                                   QualType ObjectType) {
+                                                   QualType ObjectType,
+                                             NamedDecl *FirstQualifierInScope) {
   CXXScopeSpec SS;
   // FIXME: The source location information is all wrong.
   SS.setRange(Range);
   SS.setScopeRep(Prefix);
   return static_cast<NestedNameSpecifier *>(
-                    SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(), 
+                    SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(), 
                                                         Range.getEnd(), II,
-                                                  ObjectType.getAsOpaquePtr(),
+                                                        ObjectType,
+                                                        FirstQualifierInScope,
                                                         false));
 }
 

Modified: cfe/trunk/test/SemaCXX/qual-id-test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/qual-id-test.cpp?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/qual-id-test.cpp (original)
+++ cfe/trunk/test/SemaCXX/qual-id-test.cpp Thu Sep  3 16:38:09 2009
@@ -107,18 +107,26 @@
         a.A::B::base::x();
         a->A::member::foo();
 
-        a.bad::x(); // xpected-error{{direct or virtual}}
-        a.sub::x();
-        a.base::x();
-        a.B::base::x(); // xpected-error{{use of undeclared identifier 'B'}}
-        a->member::foo();
+        a.bad::x(); // expected-error{{direct or virtual}}
     }
-  
+
   void test_fun5() {
-    // FIXME: Enable the following once we get the nested-name-specifier lookup
-    // right during template instantiation.
-    // fun5<A::sub>(); // xpected-note 2{{instantiation}}
+    fun5<A::sub>(); // expected-note{{instantiation}}
+  }
+  
+  template<typename T>
+  void fun6() {
+    T a;
+    a.sub::x();
+    a.base::x();
+    a->member::foo();
+    a.B::base::x(); // expected-error{{use of undeclared identifier 'B'}}
+   }
+  
+  void test_fun6() {
+    fun6<A::sub>(); // expected-note{{instantiation}}
   }
+  
 }
 
 // PR4703

Modified: cfe/trunk/test/SemaTemplate/member-access-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/member-access-expr.cpp?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/member-access-expr.cpp (original)
+++ cfe/trunk/test/SemaTemplate/member-access-expr.cpp Thu Sep  3 16:38:09 2009
@@ -1,5 +1,4 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-// XFAIL
 template<typename T>
 void call_f0(T x) {
   x.Base::f0();
@@ -30,7 +29,8 @@
 template<typename TheBase, typename T>
 void call_f0_through_typedef2(T x) {
   typedef TheBase CrazyBase; // expected-note{{current scope}}
-  x.CrazyBase::f0(); // expected-error{{ambiguous}}
+  x.CrazyBase::f0(); // expected-error{{ambiguous}} \
+                     // expected-error 2{{no member named}}
 }
 
 struct OtherBase { };
@@ -41,8 +41,8 @@
 
 void test_f0_through_typedef2(X0 x0, X1 x1) {
   call_f0_through_typedef2<Base>(x0);
-  call_f0_through_typedef2<OtherBase>(x1);
-  call_f0_through_typedef2<Base>(x1); // expected-note{{here}}
+  call_f0_through_typedef2<OtherBase>(x1); // expected-note{{instantiation}}
+  call_f0_through_typedef2<Base>(x1); // expected-note{{instantiation}}
 }
 
 

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=80953&r1=80952&r2=80953&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Thu Sep  3 16:38:09 2009
@@ -380,7 +380,14 @@
   <td></td>  
 </tr>
 <tr><td>    3.4.4 [basic.lookup.elab]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>    3.4.5 [basic.lookup.classref]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>    3.4.5 [basic.lookup.classref]</td>
+  <td class="na">N/A</td>
+  <td class="na">N/A</td>
+  <td class="advanced"></td>
+  <td class="na">N/A</td>
+  <td>Missing ambiguity/consistency checks for paragraphs 3 (~type-name) and 7 (conversion-type-id)</td>
+</tr>
 <tr><td>    3.4.6 [basic.lookup.udir]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  3.5 [basic.link]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  3.6 [basic.start]</td><td></td><td></td><td></td><td></td><td></td></tr>





More information about the cfe-commits mailing list