[cfe-commits] r80925 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/Sema/SemaExpr.cpp lib/Sema/TreeTransform.h test/SemaCXX/qual-id-test.cpp

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


Author: dgregor
Date: Thu Sep  3 11:14:30 2009
New Revision: 80925

URL: http://llvm.org/viewvc/llvm-project?rev=80925&view=rev
Log:
Improved handling for dependent, qualified member access expressions, e.g.,

  t->Base::f

where t has a dependent type. We save the nested-name-specifier in the
CXXUnresolvedMemberExpr then, during instantiation, substitute into
the nested-name-specifier with the (transformed) object type of t, so
that we get name lookup into the type of the object expression.

Note that we do not yet retain information about name lookup into the
lexical scope of the member access expression, so several regression
tests are still disabled.


Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/SemaCXX/qual-id-test.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Sep  3 11:14:30 2009
@@ -1300,23 +1300,31 @@
   /// \brief The location of the '->' or '.' operator.
   SourceLocation OperatorLoc;
 
+  /// \brief The nested-name-specifier that precedes the member name, if any.
+  NestedNameSpecifier *Qualifier;
+  
+  /// \brief The source range covering the nested name specifier.
+  SourceRange QualifierRange;
+  
   /// \brief The member to which this member expression refers, which
   /// can be name, overloaded operator, or destructor.
-  /// FIXME: could also be a template-id, and we might have a 
-  /// nested-name-specifier as well.
+  /// FIXME: could also be a template-id
   DeclarationName Member;
 
   /// \brief The location of the member name.
   SourceLocation MemberLoc;
-
+  
 public:
   CXXUnresolvedMemberExpr(ASTContext &C, 
                           Expr *Base, bool IsArrow, 
                           SourceLocation OperatorLoc,
+                          NestedNameSpecifier *Qualifier,
+                          SourceRange QualifierRange,
                           DeclarationName Member,
                           SourceLocation MemberLoc)
     : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
       Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
+      Qualifier(Qualifier), QualifierRange(QualifierRange),
       Member(Member), MemberLoc(MemberLoc) { }
 
   /// \brief Retrieve the base object of this member expressions,
@@ -1333,6 +1341,14 @@
   SourceLocation getOperatorLoc() const { return OperatorLoc; }
   void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
 
+  /// \brief Retrieve the nested-name-specifier that qualifies the member
+  /// name.
+  NestedNameSpecifier *getQualifier() const { return Qualifier; }
+  
+  /// \brief Retrieve the source range covering the nested-name-specifier
+  /// that qualifies the member name.
+  SourceRange getQualifierRange() const { return QualifierRange; }
+  
   /// \brief Retrieve the name of the member that this expression
   /// refers to.
   DeclarationName getMember() const { return Member; }

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=80925&r1=80924&r2=80925&view=diff

==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Thu Sep  3 11:14:30 2009
@@ -1138,6 +1138,8 @@
 void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
   PrintExpr(Node->getBase());
   OS << (Node->isArrow() ? "->" : ".");
+  if (NestedNameSpecifier *Qualifier = Node->getQualifier())
+    Qualifier->print(OS, Policy);
   OS << Node->getMember().getAsString();
 }
 

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=80925&r1=80924&r2=80925&view=diff

==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Thu Sep  3 11:14:30 2009
@@ -550,6 +550,7 @@
 void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) {
   VisitExpr(S);
   ID.AddBoolean(S->isArrow());
+  VisitNestedNameSpecifier(S->getQualifier());
   VisitName(S->getMember());
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep  3 11:14:30 2009
@@ -2025,7 +2025,9 @@
     if (BaseType->isDependentType())
       return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
                                                          BaseExpr, true, 
-                                                         OpLoc, 
+                                                         OpLoc,
+                            (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+                                            SS? SS->getRange() : SourceRange(),
                                                          MemberName,
                                                          MemberLoc));
     else if (const PointerType *PT = BaseType->getAs<PointerType>())
@@ -2053,6 +2055,8 @@
         return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
                                                            BaseExpr, false, 
                                                            OpLoc, 
+                            (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+                                            SS? SS->getRange() : SourceRange(),
                                                            MemberName,
                                                            MemberLoc));
     }
@@ -2082,29 +2086,29 @@
     LookupResult Result
       = LookupQualifiedName(DC, MemberName, LookupMemberName, false);
 
+    if (!Result)
+      return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated)
+               << MemberName << BaseExpr->getSourceRange());
+    if (Result.isAmbiguous()) {
+      DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
+                              BaseExpr->getSourceRange());
+      return ExprError();
+    }
+    
     if (SS && SS->isSet()) {
       QualType BaseTypeCanon 
         = Context.getCanonicalType(BaseType).getUnqualifiedType();
       QualType MemberTypeCanon 
         = Context.getCanonicalType(
-            Context.getTypeDeclType(
-                     dyn_cast<TypeDecl>(Result.getAsDecl()->getDeclContext())));
-
+                  Context.getTypeDeclType(
+                    dyn_cast<TypeDecl>(Result.getAsDecl()->getDeclContext())));
+      
       if (BaseTypeCanon != MemberTypeCanon &&
           !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
         return ExprError(Diag(SS->getBeginLoc(),
                               diag::err_not_direct_base_or_virtual)
                          << MemberTypeCanon << BaseTypeCanon);
     }
-
-    if (!Result)
-      return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated)
-               << MemberName << BaseExpr->getSourceRange());
-    if (Result.isAmbiguous()) {
-      DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
-                              BaseExpr->getSourceRange());
-      return ExprError();
-    }
     
     NamedDecl *MemberDecl = Result;
 

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

==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Sep  3 11:14:30 2009
@@ -242,7 +242,8 @@
   /// nested-name-specifier. Subclasses may override this function to provide
   /// alternate behavior.
   NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
-                                                    SourceRange Range);
+                                                    SourceRange Range,
+                                              QualType ObjectType = QualType());
   
   /// \brief Transform the given template name.
   /// 
@@ -497,7 +498,8 @@
   /// different behavior.
   NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
                                                   SourceRange Range,
-                                                  IdentifierInfo &II);
+                                                  IdentifierInfo &II,
+                                                  QualType ObjectType);
 
   /// \brief Build a new nested-name-specifier given the prefix and the
   /// namespace named in the next step in the nested-name-specifier.
@@ -1449,23 +1451,23 @@
   OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
                                                   bool IsArrow,
                                                   SourceLocation OperatorLoc,
+                                              NestedNameSpecifier *Qualifier,
+                                                  SourceRange QualifierRange,
                                                   DeclarationName Name,
                                                   SourceLocation MemberLoc) {
     OwningExprResult Base = move(BaseE);
     tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
+
     CXXScopeSpec SS;
-    Sema::TypeTy *ObjectType = 0;
-    
-    Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), OperatorLoc,
-                                                OpKind, ObjectType);
-    if (Base.isInvalid())
-      return SemaRef.ExprError();
-    
+    SS.setRange(QualifierRange);
+    SS.setScopeRep(Qualifier);
+        
     Base = SemaRef.BuildMemberReferenceExpr(/*Scope=*/0,
                                             move(Base), OperatorLoc, OpKind,
                                             MemberLoc,
                                             Name,
-                                    /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
+                                    /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
+                                            &SS);
     return move(Base);
   }
 
@@ -1588,27 +1590,35 @@
 template<typename Derived>
 NestedNameSpecifier *
 TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
-                                                     SourceRange Range) {
+                                                     SourceRange Range,
+                                                     QualType ObjectType) {
   if (!NNS)
     return 0;
   
   // Transform the prefix of this nested name specifier.
   NestedNameSpecifier *Prefix = NNS->getPrefix();
   if (Prefix) {
-    Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range);
+    Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range, 
+                                                       ObjectType);
     if (!Prefix)
       return 0;
+    
+    // Clear out the object type; it only applies to the first element in
+    // the nested-name-specifier.
+    ObjectType = QualType();
   }
   
   switch (NNS->getKind()) {
   case NestedNameSpecifier::Identifier:
-    assert(Prefix && 
-           "Can't have an identifier nested-name-specifier with no prefix");
-    if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix())
+    assert((Prefix || !ObjectType.isNull()) && 
+            "Identifier nested-name-specifier with no prefix or object type");
+    if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() &&
+        ObjectType.isNull())
       return NNS;
       
     return getDerived().RebuildNestedNameSpecifier(Prefix, Range, 
-                                                   *NNS->getAsIdentifier());
+                                                   *NNS->getAsIdentifier(),
+                                                   ObjectType);
       
   case NestedNameSpecifier::Namespace: {
     NamespaceDecl *NS 
@@ -4037,18 +4047,38 @@
   if (Base.isInvalid())
     return SemaRef.ExprError();
   
+  Sema::TypeTy *ObjectType = 0;
+  Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), 
+                                              E->getOperatorLoc(),
+                                      E->isArrow()? tok::arrow : tok::period,
+                                              ObjectType);
+  if (Base.isInvalid())
+    return SemaRef.ExprError();
+  
+  NestedNameSpecifier *Qualifier = 0;
+  if (E->getQualifier()) {
+    Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+                                                      E->getQualifierRange(),
+                                      QualType::getFromOpaquePtr(ObjectType));
+    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())
     return SemaRef.Owned(E->Retain()); 
-      
+  
   return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
                                                      E->isArrow(),
                                                      E->getOperatorLoc(),
-                                                     E->getMember(),
+                                                     Qualifier,
+                                                     E->getQualifierRange(),
+                                                     Name,
                                                      E->getMemberLoc());
 }
 
@@ -4404,7 +4434,8 @@
 NestedNameSpecifier *
 TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
                                                    SourceRange Range,
-                                                   IdentifierInfo &II) {
+                                                   IdentifierInfo &II,
+                                                   QualType ObjectType) {
   CXXScopeSpec SS;
   // FIXME: The source location information is all wrong.
   SS.setRange(Range);
@@ -4412,7 +4443,7 @@
   return static_cast<NestedNameSpecifier *>(
                     SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(), 
                                                         Range.getEnd(), II,
-                                                        /*FIXME:ObjectType=*/0,
+                                                  ObjectType.getAsOpaquePtr(),
                                                         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=80925&r1=80924&r2=80925&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/qual-id-test.cpp (original)
+++ cfe/trunk/test/SemaCXX/qual-id-test.cpp Thu Sep  3 11:14:30 2009
@@ -103,25 +103,22 @@
         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();
         a->A::member::foo();
 
-        // Things that work, but shouldn't
-        a.bad::x();
-
-        // Things that fail, but shouldn't
-        a.sub::x(); // xpected-error{{use of undeclared identifier 'sub'}}
-        a.base::x(); // xpected-error{{use of undeclared identifier 'base'}}
+        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(); // xpected-error{{use of undeclared identifier 'member'}}
-#endif
+        a->member::foo();
     }
+  
+  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}}
+  }
 }
 
 // PR4703





More information about the cfe-commits mailing list